From c460766320b8d6892495fd9fb6d22cd5a6470c98 Mon Sep 17 00:00:00 2001 From: Zhi Guan Date: Thu, 22 Feb 2024 11:14:59 +0800 Subject: [PATCH] Update SM2 arithmetic implementations Decouple API and implementations. SM2 arithmetic exposes 3 types: GF(p), GF(n), and Point. --- CMakeLists.txt | 1 + include/gmssl/sm2.h | 4 +- include/gmssl/sm2_z256.h | 26 +- src/sm2_alg.c | 14 +- src/sm2_lib.c | 405 +---------------------------- src/sm2_sign.c | 421 +++++++++++++++++++++++++++++++ src/sm2_z256.c | 532 ++++++++++++++++++++++++++------------- tests/sm2_z256test.c | 472 ++++++++++++++++++++++++++-------- 8 files changed, 1168 insertions(+), 707 deletions(-) create mode 100644 src/sm2_sign.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 0635e7b4..d6eac538 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,6 +20,7 @@ set(src src/sm3_digest.c src/sm2_alg.c src/sm2_key.c + src/sm2_sign.c src/sm2_lib.c src/sm2_ctx.c src/sm9_alg.c diff --git a/include/gmssl/sm2.h b/include/gmssl/sm2.h index cc183be8..fbc84c78 100644 --- a/include/gmssl/sm2.h +++ b/include/gmssl/sm2.h @@ -1,5 +1,5 @@ /* - * Copyright 2014-2023 The GmSSL Project. All Rights Reserved. + * Copyright 2014-2024 The GmSSL Project. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. @@ -317,6 +317,8 @@ typedef struct { uint8_t ciphertext[SM2_MAX_PLAINTEXT_SIZE]; } SM2_CIPHERTEXT; +int sm2_kdf(const uint8_t *in, size_t inlen, size_t outlen, uint8_t *out); + int sm2_do_encrypt(const SM2_KEY *key, const uint8_t *in, size_t inlen, SM2_CIPHERTEXT *out); int sm2_do_decrypt(const SM2_KEY *key, const SM2_CIPHERTEXT *in, uint8_t *out, size_t *outlen); diff --git a/include/gmssl/sm2_z256.h b/include/gmssl/sm2_z256.h index 6ce939df..1d5a0aa3 100644 --- a/include/gmssl/sm2_z256.h +++ b/include/gmssl/sm2_z256.h @@ -20,6 +20,7 @@ extern "C" { #endif +typedef uint64_t SM2_Z256[4]; void sm2_z256_copy(uint64_t r[4], const uint64_t a[4]); void sm2_z256_copy_conditional(uint64_t dst[4], const uint64_t src[4], uint64_t move); @@ -43,12 +44,25 @@ void sm2_z256_modp_mul_by_2(uint64_t r[4], const uint64_t a[4]); void sm2_z256_modp_mul_by_3(uint64_t r[4], const uint64_t a[4]); void sm2_z256_modp_div_by_2(uint64_t r[4], const uint64_t a[4]); -void sm2_z256_to_mont(const uint64_t a[4], uint64_t r[4]); -void sm2_z256_from_mont(uint64_t r[4], const uint64_t a[4]); -void sm2_z256_mont_mul(uint64_t r[4], const uint64_t a[4], const uint64_t b[4]); -void sm2_z256_mont_sqr(uint64_t r[4], const uint64_t a[4]); -void sm2_z256_mont_inv(uint64_t r[4], const uint64_t a[4]); -int sm2_z256_mont_print(FILE *fp, int ind, int fmt, const char *label, const uint64_t a[4]); +void sm2_z256_modp_to_mont(const uint64_t a[4], uint64_t r[4]); +void sm2_z256_modp_from_mont(uint64_t r[4], const uint64_t a[4]); +void sm2_z256_modp_mont_mul(uint64_t r[4], const uint64_t a[4], const uint64_t b[4]); +void sm2_z256_modp_mont_sqr(uint64_t r[4], const uint64_t a[4]); +void sm2_z256_modp_mont_exp(uint64_t r[4], const uint64_t a[4], const uint64_t e[4]); +void sm2_z256_modp_mont_inv(uint64_t r[4], const uint64_t a[4]); +int sm2_z256_modp_mont_print(FILE *fp, int ind, int fmt, const char *label, const uint64_t a[4]); + +void sm2_z256_modn_add(uint64_t r[4], const uint64_t a[4], const uint64_t b[4]); +void sm2_z256_modn_sub(uint64_t r[4], const uint64_t a[4], const uint64_t b[4]); +void sm2_z256_modn_neg(uint64_t r[4], const uint64_t a[4]); + +void sm2_z256_modn_to_mont(const uint64_t a[4], uint64_t r[4]); +void sm2_z256_modn_from_mont(uint64_t r[4], const uint64_t a[4]); +void sm2_z256_modn_mont_mul(uint64_t r[4], const uint64_t a[4], const uint64_t b[4]); +void sm2_z256_modn_mont_sqr(uint64_t r[4], const uint64_t a[4]); +void sm2_z256_modn_mont_exp(uint64_t r[4], const uint64_t a[4], const uint64_t e[4]); +void sm2_z256_modn_mont_inv(uint64_t r[4], const uint64_t a[4]); +int sm2_z256_modn_mont_print(FILE *fp, int ind, int fmt, const char *label, const uint64_t a[4]); typedef struct { diff --git a/src/sm2_alg.c b/src/sm2_alg.c index 7b2c2e76..5aa247a0 100644 --- a/src/sm2_alg.c +++ b/src/sm2_alg.c @@ -1,5 +1,5 @@ -/* - * Copyright 2014-2022 The GmSSL Project. All Rights Reserved. +/* + * Copyright 2014-2024 The GmSSL Project. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. @@ -20,10 +20,6 @@ #include -#define sm2_print_bn(label,a) sm2_bn_print(stderr,0,0,label,a) // 这个不应该放在这里,应该放在测试文件中 - - - const SM2_BN SM2_P = { 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, @@ -65,7 +61,6 @@ const SM2_BN SM2_TWO = {2,0,0,0,0,0,0,0}; const SM2_BN SM2_THREE = {3,0,0,0,0,0,0,0}; - int sm2_bn_check(const SM2_BN a) { int err = 0; @@ -775,8 +770,6 @@ int sm2_fn_rand(SM2_BN r) return 1; } - - void sm2_jacobian_point_init(SM2_JACOBIAN_POINT *R) { memset(R, 0, sizeof(SM2_JACOBIAN_POINT)); @@ -817,7 +810,7 @@ void sm2_jacobian_point_get_xy(const SM2_JACOBIAN_POINT *P, SM2_BN x, SM2_BN y) } } -int sm2_jacobian_pointpoint_print(FILE *fp, int fmt, int ind, const char *label, const SM2_JACOBIAN_POINT *P) +int sm2_jacobian_point_print(FILE *fp, int fmt, int ind, const char *label, const SM2_JACOBIAN_POINT *P) { int len = 0; SM2_BN x; @@ -1321,6 +1314,7 @@ int sm2_point_from_hash(SM2_POINT *R, const uint8_t *data, size_t datalen) sm2_bn_add(u, SM2_P, SM2_ONE); sm2_bn_rshift(u, u, 2); + // How many times? do { sm3_digest(data, datalen, dgst); diff --git a/src/sm2_lib.c b/src/sm2_lib.c index c5e22e16..85129889 100644 --- a/src/sm2_lib.c +++ b/src/sm2_lib.c @@ -1,5 +1,5 @@ /* - * Copyright 2014-2023 The GmSSL Project. All Rights Reserved. + * Copyright 2014-2024 The GmSSL Project. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. @@ -20,144 +20,6 @@ #include -extern const SM2_BN SM2_N; -extern const SM2_BN SM2_ONE; - -int sm2_do_sign(const SM2_KEY *key, const uint8_t dgst[32], SM2_SIGNATURE *sig) -{ - SM2_JACOBIAN_POINT _P, *P = &_P; - SM2_BN d; - SM2_BN d_inv; - SM2_BN e; - SM2_BN k; - SM2_BN x; - SM2_BN t; - SM2_BN r; - SM2_BN s; - - //fprintf(stderr, "sm2_do_sign\n"); - sm2_bn_from_bytes(d, key->private_key); - - // compute (d + 1)^-1 (mod n) - sm2_fn_add(d_inv, d, SM2_ONE); //sm2_bn_print(stderr, 0, 4, "(1+d)", d_inv); - if (sm2_bn_is_zero(d_inv)) { - error_print(); - return -1; - } - sm2_fn_inv(d_inv, d_inv); //sm2_bn_print(stderr, 0, 4, "(1+d)^-1", d_inv); - - // e = H(M) - sm2_bn_from_bytes(e, dgst); //sm2_bn_print(stderr, 0, 4, "e", e); - -retry: - // rand k in [1, n - 1] - do { - if (sm2_fn_rand(k) != 1) { - error_print(); - return -1; - } - } while (sm2_bn_is_zero(k)); //sm2_bn_print(stderr, 0, 4, "k", k); - - // (x, y) = kG - sm2_jacobian_point_mul_generator(P, k); - sm2_jacobian_point_get_xy(P, x, NULL); - //sm2_bn_print(stderr, 0, 4, "x", x); - - // r = e + x (mod n) - if (sm2_bn_cmp(e, SM2_N) >= 0) { - sm2_bn_sub(e, e, SM2_N); - } - if (sm2_bn_cmp(x, SM2_N) >= 0) { - sm2_bn_sub(x, x, SM2_N); - } - sm2_fn_add(r, e, x); //sm2_bn_print(stderr, 0, 4, "r = e + x (mod n)", r); - - // if r == 0 or r + k == n re-generate k - sm2_bn_add(t, r, k); - if (sm2_bn_is_zero(r) || sm2_bn_cmp(t, SM2_N) == 0) { - //sm2_bn_print(stderr, 0, 4, "r + k", t); - goto retry; - } - - // s = ((1 + d)^-1 * (k - r * d)) mod n - sm2_fn_mul(t, r, d); //sm2_bn_print(stderr, 0, 4, "r*d", t); - sm2_fn_sub(k, k, t); //sm2_bn_print(stderr, 0, 4, "k-r*d", k); - sm2_fn_mul(s, d_inv, k); //sm2_bn_print(stderr, 0, 4, "s = ((1 + d)^-1 * (k - r * d)) mod n", s); - - // check s != 0 - if (sm2_bn_is_zero(s)) { - goto retry; - } - - sm2_bn_to_bytes(r, sig->r); //sm2_bn_print_bn(stderr, 0, 4, "r", r); - sm2_bn_to_bytes(s, sig->s); //sm2_bn_print_bn(stderr, 0, 4, "s", s); - - gmssl_secure_clear(d, sizeof(d)); - gmssl_secure_clear(d_inv, sizeof(d_inv )); - gmssl_secure_clear(k, sizeof(k)); - gmssl_secure_clear(t, sizeof(t)); - return 1; -} - -int sm2_do_verify(const SM2_KEY *key, const uint8_t dgst[32], const SM2_SIGNATURE *sig) -{ - SM2_JACOBIAN_POINT _P, *P = &_P; - SM2_JACOBIAN_POINT _R, *R = &_R; - SM2_BN r; - SM2_BN s; - SM2_BN e; - SM2_BN x; - SM2_BN t; - - // parse public key - sm2_jacobian_point_from_bytes(P, (const uint8_t *)&key->public_key); - //sm2_jacobian_point_print(stderr, 0, 4, "P", P); - - // parse signature values - sm2_bn_from_bytes(r, sig->r); //sm2_bn_print(stderr, 0, 4, "r", r); - sm2_bn_from_bytes(s, sig->s); //sm2_bn_print(stderr, 0, 4, "s", s); - - // check r, s in [1, n-1] - if (sm2_bn_is_zero(r) == 1 - || sm2_bn_cmp(r, SM2_N) >= 0 - || sm2_bn_is_zero(s) == 1 - || sm2_bn_cmp(s, SM2_N) >= 0) { - error_print(); - return -1; - } - - // e = H(M) - sm2_bn_from_bytes(e, dgst); //sm2_bn_print(stderr, 0, 4, "e = H(M)", e); - - // t = r + s (mod n), check t != 0 - sm2_fn_add(t, r, s); //sm2_bn_print(stderr, 0, 4, "t = r + s (mod n)", t); - if (sm2_bn_is_zero(t)) { - error_print(); - return -1; - } - - // Q = s * G + t * P - sm2_jacobian_point_mul_sum(R, t, P, s); - sm2_jacobian_point_get_xy(R, x, NULL); - //sm2_bn_print(stderr, 0, 4, "x", x); - - // r' = e + x (mod n) - if (sm2_bn_cmp(e, SM2_N) >= 0) { - sm2_bn_sub(e, e, SM2_N); - } - if (sm2_bn_cmp(x, SM2_N) >= 0) { - sm2_bn_sub(x, x, SM2_N); - } - sm2_fn_add(e, e, x); //sm2_bn_print(stderr, 0, 4, "e + x (mod n)", e); - - // check if r == r' - if (sm2_bn_cmp(e, r) != 0) { - error_print(); - return -1; - } - return 1; -} - int sm2_signature_to_der(const SM2_SIGNATURE *sig, uint8_t **out, size_t *outlen) { size_t len = 0; @@ -360,223 +222,6 @@ int sm2_kdf(const uint8_t *in, size_t inlen, size_t outlen, uint8_t *out) return 1; } -static int all_zero(const uint8_t *buf, size_t len) -{ - size_t i; - for (i = 0; i < len; i++) { - if (buf[i]) { - return 0; - } - } - return 1; -} - -int sm2_do_encrypt(const SM2_KEY *key, const uint8_t *in, size_t inlen, SM2_CIPHERTEXT *out) -{ - SM2_BN k; - SM2_JACOBIAN_POINT _P, *P = &_P; - SM2_JACOBIAN_POINT _C1, *C1 = &_C1; - SM2_JACOBIAN_POINT _kP, *kP = &_kP; - uint8_t x2y2[64]; - SM3_CTX sm3_ctx; - - if (!(SM2_MIN_PLAINTEXT_SIZE <= inlen && inlen <= SM2_MAX_PLAINTEXT_SIZE)) { - error_print(); - return -1; - } - - sm2_jacobian_point_from_bytes(P, (uint8_t *)&key->public_key); - - // S = h * P, check S != O - // for sm2 curve, h == 1 and S == P - // SM2_POINT can not present point at infinity, do do nothing here - -retry: - // rand k in [1, n - 1] - do { - if (sm2_fn_rand(k) != 1) { - error_print(); - return -1; - } - } while (sm2_bn_is_zero(k)); //sm2_bn_print(stderr, 0, 4, "k", k); - - // output C1 = k * G = (x1, y1) - sm2_jacobian_point_mul_generator(C1, k); - sm2_jacobian_point_to_bytes(C1, (uint8_t *)&out->point); - - // k * P = (x2, y2) - sm2_jacobian_point_mul(kP, k, P); - sm2_jacobian_point_to_bytes(kP, x2y2); - - // t = KDF(x2 || y2, inlen) - sm2_kdf(x2y2, 64, inlen, out->ciphertext); - - // if t is all zero, retry - if (all_zero(out->ciphertext, inlen)) { - goto retry; - } - - // output C2 = M xor t - gmssl_memxor(out->ciphertext, out->ciphertext, in, inlen); - out->ciphertext_size = (uint32_t)inlen; - - // output C3 = Hash(x2 || m || y2) - sm3_init(&sm3_ctx); - sm3_update(&sm3_ctx, x2y2, 32); - sm3_update(&sm3_ctx, in, inlen); - sm3_update(&sm3_ctx, x2y2 + 32, 32); - sm3_finish(&sm3_ctx, out->hash); - - gmssl_secure_clear(k, sizeof(k)); - gmssl_secure_clear(kP, sizeof(SM2_JACOBIAN_POINT)); - gmssl_secure_clear(x2y2, sizeof(x2y2)); - return 1; -} - -int sm2_do_encrypt_fixlen(const SM2_KEY *key, const uint8_t *in, size_t inlen, int point_size, SM2_CIPHERTEXT *out) -{ - unsigned int trys = 200; - SM2_BN k; - SM2_JACOBIAN_POINT _P, *P = &_P; - SM2_JACOBIAN_POINT _C1, *C1 = &_C1; - SM2_JACOBIAN_POINT _kP, *kP = &_kP; - uint8_t x2y2[64]; - SM3_CTX sm3_ctx; - - if (!(SM2_MIN_PLAINTEXT_SIZE <= inlen && inlen <= SM2_MAX_PLAINTEXT_SIZE)) { - error_print(); - return -1; - } - - switch (point_size) { - case SM2_ciphertext_compact_point_size: - case SM2_ciphertext_typical_point_size: - case SM2_ciphertext_max_point_size: - break; - default: - error_print(); - return -1; - } - - sm2_jacobian_point_from_bytes(P, (uint8_t *)&key->public_key); - - // S = h * P, check S != O - // for sm2 curve, h == 1 and S == P - // SM2_POINT can not present point at infinity, do do nothing here - -retry: - // rand k in [1, n - 1] - do { - if (sm2_fn_rand(k) != 1) { - error_print(); - return -1; - } - } while (sm2_bn_is_zero(k)); //sm2_bn_print(stderr, 0, 4, "k", k); - - // output C1 = k * G = (x1, y1) - sm2_jacobian_point_mul_generator(C1, k); - sm2_jacobian_point_to_bytes(C1, (uint8_t *)&out->point); - - // check fixlen - if (trys) { - size_t len = 0; - asn1_integer_to_der(out->point.x, 32, NULL, &len); - asn1_integer_to_der(out->point.y, 32, NULL, &len); - if (len != point_size) { - trys--; - goto retry; - } - } else { - gmssl_secure_clear(k, sizeof(k)); - error_print(); - return -1; - } - - // k * P = (x2, y2) - sm2_jacobian_point_mul(kP, k, P); - sm2_jacobian_point_to_bytes(kP, x2y2); - - // t = KDF(x2 || y2, inlen) - sm2_kdf(x2y2, 64, inlen, out->ciphertext); - - // if t is all zero, retry - if (all_zero(out->ciphertext, inlen)) { - goto retry; - } - - // output C2 = M xor t - gmssl_memxor(out->ciphertext, out->ciphertext, in, inlen); - out->ciphertext_size = (uint32_t)inlen; - - // output C3 = Hash(x2 || m || y2) - sm3_init(&sm3_ctx); - sm3_update(&sm3_ctx, x2y2, 32); - sm3_update(&sm3_ctx, in, inlen); - sm3_update(&sm3_ctx, x2y2 + 32, 32); - sm3_finish(&sm3_ctx, out->hash); - - gmssl_secure_clear(k, sizeof(k)); - gmssl_secure_clear(kP, sizeof(SM2_JACOBIAN_POINT)); - gmssl_secure_clear(x2y2, sizeof(x2y2)); - return 1; -} - -int sm2_do_decrypt(const SM2_KEY *key, const SM2_CIPHERTEXT *in, uint8_t *out, size_t *outlen) -{ - int ret = -1; - SM2_BN d; - SM2_JACOBIAN_POINT _C1, *C1 = &_C1; - uint8_t x2y2[64]; - SM3_CTX sm3_ctx; - uint8_t hash[32]; - - // check C1 is on sm2 curve - sm2_jacobian_point_from_bytes(C1, (uint8_t *)&in->point); - if (!sm2_jacobian_point_is_on_curve(C1)) { - error_print(); - return -1; - } - - // check if S = h * C1 is point at infinity - // this will not happen, as SM2_POINT can not present point at infinity - - // d * C1 = (x2, y2) - sm2_bn_from_bytes(d, key->private_key); - sm2_jacobian_point_mul(C1, d, C1); - - // t = KDF(x2 || y2, klen) and check t is not all zeros - sm2_jacobian_point_to_bytes(C1, x2y2); - sm2_kdf(x2y2, 64, in->ciphertext_size, out); - if (all_zero(out, in->ciphertext_size)) { - error_print(); - goto end; - } - - // M = C2 xor t - gmssl_memxor(out, out, in->ciphertext, in->ciphertext_size); - *outlen = in->ciphertext_size; - - // u = Hash(x2 || M || y2) - sm3_init(&sm3_ctx); - sm3_update(&sm3_ctx, x2y2, 32); - sm3_update(&sm3_ctx, out, in->ciphertext_size); - sm3_update(&sm3_ctx, x2y2 + 32, 32); - sm3_finish(&sm3_ctx, hash); - - // check if u == C3 - if (memcmp(in->hash, hash, sizeof(hash)) != 0) { - error_print(); - goto end; - } - ret = 1; - -end: - gmssl_secure_clear(d, sizeof(d)); - gmssl_secure_clear(C1, sizeof(SM2_JACOBIAN_POINT)); - gmssl_secure_clear(x2y2, sizeof(x2y2)); - return ret; -} - int sm2_ciphertext_to_der(const SM2_CIPHERTEXT *C, uint8_t **out, size_t *outlen) { size_t len = 0; @@ -773,51 +418,3 @@ int sm2_ecdh(const SM2_KEY *key, const uint8_t *peer_public, size_t peer_public_ } return 1; } - - -// (x1, y1) = k * G -// r = e + x1 -// s = (k - r * d)/(1 + d) = (k +r - r * d - r)/(1 + d) = (k + r - r(1 +d))/(1 + d) = (k + r)/(1 + d) - r -// = -r + (k + r)*(1 + d)^-1 -// = -r + (k + r) * d' - -int sm2_do_sign_fast(const SM2_Fn d, const uint8_t dgst[32], SM2_SIGNATURE *sig) -{ - SM2_JACOBIAN_POINT R; - SM2_BN e; - SM2_BN k; - SM2_BN x1; - SM2_BN r; - SM2_BN s; - - // e = H(M) - sm2_bn_from_bytes(e, dgst); - if (sm2_bn_cmp(e, SM2_N) >= 0) { - sm2_bn_sub(e, e, SM2_N); - } - - // rand k in [1, n - 1] - do { - if (sm2_fn_rand(k) != 1) { - error_print(); - return -1; - } - } while (sm2_bn_is_zero(k)); - - // (x1, y1) = kG - sm2_jacobian_point_mul_generator(&R, k); - sm2_jacobian_point_get_xy(&R, x1, NULL); - - // r = e + x1 (mod n) - sm2_fn_add(r, e, x1); - - // s = (k + r) * d' - r - sm2_bn_add(s, k, r); - sm2_fn_mul(s, s, d); - sm2_fn_sub(s, s, r); - - sm2_bn_to_bytes(r, sig->r); - sm2_bn_to_bytes(s, sig->s); - return 1; -} - diff --git a/src/sm2_sign.c b/src/sm2_sign.c new file mode 100644 index 00000000..909586d6 --- /dev/null +++ b/src/sm2_sign.c @@ -0,0 +1,421 @@ +/* + * Copyright 2014-2024 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +extern const SM2_BN SM2_N; +extern const SM2_BN SM2_ONE; + +int sm2_do_sign(const SM2_KEY *key, const uint8_t dgst[32], SM2_SIGNATURE *sig) +{ + SM2_JACOBIAN_POINT _P, *P = &_P; + SM2_BN d; + SM2_BN d_inv; + SM2_BN e; + SM2_BN k; + SM2_BN x; + SM2_BN t; + SM2_BN r; + SM2_BN s; + + //fprintf(stderr, "sm2_do_sign\n"); + sm2_bn_from_bytes(d, key->private_key); + + // compute (d + 1)^-1 (mod n) + sm2_fn_add(d_inv, d, SM2_ONE); //sm2_bn_print(stderr, 0, 4, "(1+d)", d_inv); + if (sm2_bn_is_zero(d_inv)) { + error_print(); + return -1; + } + sm2_fn_inv(d_inv, d_inv); //sm2_bn_print(stderr, 0, 4, "(1+d)^-1", d_inv); + + // e = H(M) + sm2_bn_from_bytes(e, dgst); //sm2_bn_print(stderr, 0, 4, "e", e); + +retry: + // rand k in [1, n - 1] + do { + if (sm2_fn_rand(k) != 1) { + error_print(); + return -1; + } + } while (sm2_bn_is_zero(k)); //sm2_bn_print(stderr, 0, 4, "k", k); + + // (x, y) = kG + sm2_jacobian_point_mul_generator(P, k); + sm2_jacobian_point_get_xy(P, x, NULL); + //sm2_bn_print(stderr, 0, 4, "x", x); + + // r = e + x (mod n) + if (sm2_bn_cmp(e, SM2_N) >= 0) { + sm2_bn_sub(e, e, SM2_N); + } + if (sm2_bn_cmp(x, SM2_N) >= 0) { + sm2_bn_sub(x, x, SM2_N); + } + sm2_fn_add(r, e, x); //sm2_bn_print(stderr, 0, 4, "r = e + x (mod n)", r); + + // if r == 0 or r + k == n re-generate k + sm2_bn_add(t, r, k); + if (sm2_bn_is_zero(r) || sm2_bn_cmp(t, SM2_N) == 0) { + //sm2_bn_print(stderr, 0, 4, "r + k", t); + goto retry; + } + + // s = ((1 + d)^-1 * (k - r * d)) mod n + sm2_fn_mul(t, r, d); //sm2_bn_print(stderr, 0, 4, "r*d", t); + sm2_fn_sub(k, k, t); //sm2_bn_print(stderr, 0, 4, "k-r*d", k); + sm2_fn_mul(s, d_inv, k); //sm2_bn_print(stderr, 0, 4, "s = ((1 + d)^-1 * (k - r * d)) mod n", s); + + // check s != 0 + if (sm2_bn_is_zero(s)) { + goto retry; + } + + sm2_bn_to_bytes(r, sig->r); //sm2_bn_print_bn(stderr, 0, 4, "r", r); + sm2_bn_to_bytes(s, sig->s); //sm2_bn_print_bn(stderr, 0, 4, "s", s); + + gmssl_secure_clear(d, sizeof(d)); + gmssl_secure_clear(d_inv, sizeof(d_inv )); + gmssl_secure_clear(k, sizeof(k)); + gmssl_secure_clear(t, sizeof(t)); + return 1; +} + +// (x1, y1) = k * G +// r = e + x1 +// s = (k - r * d)/(1 + d) = (k +r - r * d - r)/(1 + d) = (k + r - r(1 +d))/(1 + d) = (k + r)/(1 + d) - r +// = -r + (k + r)*(1 + d)^-1 +// = -r + (k + r) * d' + +int sm2_do_sign_fast(const SM2_Fn d, const uint8_t dgst[32], SM2_SIGNATURE *sig) +{ + SM2_JACOBIAN_POINT R; + SM2_BN e; + SM2_BN k; + SM2_BN x1; + SM2_BN r; + SM2_BN s; + + // e = H(M) + sm2_bn_from_bytes(e, dgst); + if (sm2_bn_cmp(e, SM2_N) >= 0) { + sm2_bn_sub(e, e, SM2_N); + } + + // rand k in [1, n - 1] + do { + if (sm2_fn_rand(k) != 1) { + error_print(); + return -1; + } + } while (sm2_bn_is_zero(k)); + + // (x1, y1) = kG + sm2_jacobian_point_mul_generator(&R, k); + sm2_jacobian_point_get_xy(&R, x1, NULL); + + // r = e + x1 (mod n) + sm2_fn_add(r, e, x1); + + // s = (k + r) * d' - r + sm2_bn_add(s, k, r); + sm2_fn_mul(s, s, d); + sm2_fn_sub(s, s, r); + + sm2_bn_to_bytes(r, sig->r); + sm2_bn_to_bytes(s, sig->s); + return 1; +} + +int sm2_do_verify(const SM2_KEY *key, const uint8_t dgst[32], const SM2_SIGNATURE *sig) +{ + SM2_JACOBIAN_POINT _P, *P = &_P; + SM2_JACOBIAN_POINT _R, *R = &_R; + SM2_BN r; + SM2_BN s; + SM2_BN e; + SM2_BN x; + SM2_BN t; + + // parse public key + sm2_jacobian_point_from_bytes(P, (const uint8_t *)&key->public_key); + //sm2_jacobian_point_print(stderr, 0, 4, "P", P); + + // parse signature values + sm2_bn_from_bytes(r, sig->r); //sm2_bn_print(stderr, 0, 4, "r", r); + sm2_bn_from_bytes(s, sig->s); //sm2_bn_print(stderr, 0, 4, "s", s); + + // check r, s in [1, n-1] + if (sm2_bn_is_zero(r) == 1 + || sm2_bn_cmp(r, SM2_N) >= 0 + || sm2_bn_is_zero(s) == 1 + || sm2_bn_cmp(s, SM2_N) >= 0) { + error_print(); + return -1; + } + + // e = H(M) + sm2_bn_from_bytes(e, dgst); //sm2_bn_print(stderr, 0, 4, "e = H(M)", e); + + // t = r + s (mod n), check t != 0 + sm2_fn_add(t, r, s); //sm2_bn_print(stderr, 0, 4, "t = r + s (mod n)", t); + if (sm2_bn_is_zero(t)) { + error_print(); + return -1; + } + + // Q = s * G + t * P + sm2_jacobian_point_mul_sum(R, t, P, s); + sm2_jacobian_point_get_xy(R, x, NULL); + //sm2_bn_print(stderr, 0, 4, "x", x); + + // r' = e + x (mod n) + if (sm2_bn_cmp(e, SM2_N) >= 0) { + sm2_bn_sub(e, e, SM2_N); + } + if (sm2_bn_cmp(x, SM2_N) >= 0) { + sm2_bn_sub(x, x, SM2_N); + } + sm2_fn_add(e, e, x); //sm2_bn_print(stderr, 0, 4, "e + x (mod n)", e); + + // check if r == r' + if (sm2_bn_cmp(e, r) != 0) { + error_print(); + return -1; + } + return 1; +} + +static int all_zero(const uint8_t *buf, size_t len) +{ + size_t i; + for (i = 0; i < len; i++) { + if (buf[i]) { + return 0; + } + } + return 1; +} + +int sm2_do_encrypt(const SM2_KEY *key, const uint8_t *in, size_t inlen, SM2_CIPHERTEXT *out) +{ + SM2_BN k; + SM2_JACOBIAN_POINT _P, *P = &_P; + SM2_JACOBIAN_POINT _C1, *C1 = &_C1; + SM2_JACOBIAN_POINT _kP, *kP = &_kP; + uint8_t x2y2[64]; + SM3_CTX sm3_ctx; + + if (!(SM2_MIN_PLAINTEXT_SIZE <= inlen && inlen <= SM2_MAX_PLAINTEXT_SIZE)) { + error_print(); + return -1; + } + + sm2_jacobian_point_from_bytes(P, (uint8_t *)&key->public_key); + + // S = h * P, check S != O + // for sm2 curve, h == 1 and S == P + // SM2_POINT can not present point at infinity, do do nothing here + +retry: + // rand k in [1, n - 1] + do { + if (sm2_fn_rand(k) != 1) { + error_print(); + return -1; + } + } while (sm2_bn_is_zero(k)); //sm2_bn_print(stderr, 0, 4, "k", k); + + // output C1 = k * G = (x1, y1) + sm2_jacobian_point_mul_generator(C1, k); + sm2_jacobian_point_to_bytes(C1, (uint8_t *)&out->point); + + // k * P = (x2, y2) + sm2_jacobian_point_mul(kP, k, P); + sm2_jacobian_point_to_bytes(kP, x2y2); + + // t = KDF(x2 || y2, inlen) + sm2_kdf(x2y2, 64, inlen, out->ciphertext); + + // if t is all zero, retry + if (all_zero(out->ciphertext, inlen)) { + goto retry; + } + + // output C2 = M xor t + gmssl_memxor(out->ciphertext, out->ciphertext, in, inlen); + out->ciphertext_size = (uint32_t)inlen; + + // output C3 = Hash(x2 || m || y2) + sm3_init(&sm3_ctx); + sm3_update(&sm3_ctx, x2y2, 32); + sm3_update(&sm3_ctx, in, inlen); + sm3_update(&sm3_ctx, x2y2 + 32, 32); + sm3_finish(&sm3_ctx, out->hash); + + gmssl_secure_clear(k, sizeof(k)); + gmssl_secure_clear(kP, sizeof(SM2_JACOBIAN_POINT)); + gmssl_secure_clear(x2y2, sizeof(x2y2)); + return 1; +} + +int sm2_do_encrypt_fixlen(const SM2_KEY *key, const uint8_t *in, size_t inlen, int point_size, SM2_CIPHERTEXT *out) +{ + unsigned int trys = 200; + SM2_BN k; + SM2_JACOBIAN_POINT _P, *P = &_P; + SM2_JACOBIAN_POINT _C1, *C1 = &_C1; + SM2_JACOBIAN_POINT _kP, *kP = &_kP; + uint8_t x2y2[64]; + SM3_CTX sm3_ctx; + + if (!(SM2_MIN_PLAINTEXT_SIZE <= inlen && inlen <= SM2_MAX_PLAINTEXT_SIZE)) { + error_print(); + return -1; + } + + switch (point_size) { + case SM2_ciphertext_compact_point_size: + case SM2_ciphertext_typical_point_size: + case SM2_ciphertext_max_point_size: + break; + default: + error_print(); + return -1; + } + + sm2_jacobian_point_from_bytes(P, (uint8_t *)&key->public_key); + + // S = h * P, check S != O + // for sm2 curve, h == 1 and S == P + // SM2_POINT can not present point at infinity, do do nothing here + +retry: + // rand k in [1, n - 1] + do { + if (sm2_fn_rand(k) != 1) { + error_print(); + return -1; + } + } while (sm2_bn_is_zero(k)); //sm2_bn_print(stderr, 0, 4, "k", k); + + // output C1 = k * G = (x1, y1) + sm2_jacobian_point_mul_generator(C1, k); + sm2_jacobian_point_to_bytes(C1, (uint8_t *)&out->point); + + // check fixlen + if (trys) { + size_t len = 0; + asn1_integer_to_der(out->point.x, 32, NULL, &len); + asn1_integer_to_der(out->point.y, 32, NULL, &len); + if (len != point_size) { + trys--; + goto retry; + } + } else { + gmssl_secure_clear(k, sizeof(k)); + error_print(); + return -1; + } + + // k * P = (x2, y2) + sm2_jacobian_point_mul(kP, k, P); + sm2_jacobian_point_to_bytes(kP, x2y2); + + // t = KDF(x2 || y2, inlen) + sm2_kdf(x2y2, 64, inlen, out->ciphertext); + + // if t is all zero, retry + if (all_zero(out->ciphertext, inlen)) { + goto retry; + } + + // output C2 = M xor t + gmssl_memxor(out->ciphertext, out->ciphertext, in, inlen); + out->ciphertext_size = (uint32_t)inlen; + + // output C3 = Hash(x2 || m || y2) + sm3_init(&sm3_ctx); + sm3_update(&sm3_ctx, x2y2, 32); + sm3_update(&sm3_ctx, in, inlen); + sm3_update(&sm3_ctx, x2y2 + 32, 32); + sm3_finish(&sm3_ctx, out->hash); + + gmssl_secure_clear(k, sizeof(k)); + gmssl_secure_clear(kP, sizeof(SM2_JACOBIAN_POINT)); + gmssl_secure_clear(x2y2, sizeof(x2y2)); + return 1; +} + +int sm2_do_decrypt(const SM2_KEY *key, const SM2_CIPHERTEXT *in, uint8_t *out, size_t *outlen) +{ + int ret = -1; + SM2_BN d; + SM2_JACOBIAN_POINT _C1, *C1 = &_C1; + uint8_t x2y2[64]; + SM3_CTX sm3_ctx; + uint8_t hash[32]; + + // check C1 is on sm2 curve + sm2_jacobian_point_from_bytes(C1, (uint8_t *)&in->point); + if (!sm2_jacobian_point_is_on_curve(C1)) { + error_print(); + return -1; + } + + // check if S = h * C1 is point at infinity + // this will not happen, as SM2_POINT can not present point at infinity + + // d * C1 = (x2, y2) + sm2_bn_from_bytes(d, key->private_key); + sm2_jacobian_point_mul(C1, d, C1); + + // t = KDF(x2 || y2, klen) and check t is not all zeros + sm2_jacobian_point_to_bytes(C1, x2y2); + sm2_kdf(x2y2, 64, in->ciphertext_size, out); + if (all_zero(out, in->ciphertext_size)) { + error_print(); + goto end; + } + + // M = C2 xor t + gmssl_memxor(out, out, in->ciphertext, in->ciphertext_size); + *outlen = in->ciphertext_size; + + // u = Hash(x2 || M || y2) + sm3_init(&sm3_ctx); + sm3_update(&sm3_ctx, x2y2, 32); + sm3_update(&sm3_ctx, out, in->ciphertext_size); + sm3_update(&sm3_ctx, x2y2 + 32, 32); + sm3_finish(&sm3_ctx, hash); + + // check if u == C3 + if (memcmp(in->hash, hash, sizeof(hash)) != 0) { + error_print(); + goto end; + } + ret = 1; + +end: + gmssl_secure_clear(d, sizeof(d)); + gmssl_secure_clear(C1, sizeof(SM2_JACOBIAN_POINT)); + gmssl_secure_clear(x2y2, sizeof(x2y2)); + return ret; +} diff --git a/src/sm2_z256.c b/src/sm2_z256.c index d3ae135c..042d9eaf 100644 --- a/src/sm2_z256.c +++ b/src/sm2_z256.c @@ -52,8 +52,35 @@ #include #include +/* +SM2 parameters -// z256 +p = 0xfffffffeffffffffffffffffffffffffffffffff00000000ffffffffffffffff +a = 0xfffffffeffffffffffffffffffffffffffffffff00000000fffffffffffffffc +b = 0x28e9fa9e9d9f5e344d5a9e4bcf6509a7f39789f515ab8f92ddbcbd414d940e93 +x = 0x32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7 +y = 0xbc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0 +n = 0xfffffffeffffffffffffffffffffffff7203df6b21c6052b53bbf40939d54123 +h = 0x1 +*/ + +const uint64_t SM2_Z256_ONE[4] = { 1,0,0,0 }; + +void sm2_z256_from_bytes(uint64_t r[4], const uint8_t in[32]) +{ + r[3] = GETU64(in); + r[2] = GETU64(in + 8); + r[1] = GETU64(in + 16); + r[0] = GETU64(in + 24); +} + +void sm2_z256_to_bytes(const uint64_t a[4], uint8_t out[32]) +{ + PUTU64(out, a[3]); + PUTU64(out + 8, a[2]); + PUTU64(out + 16, a[1]); + PUTU64(out + 24, a[0]); +} void sm2_z256_copy(uint64_t r[4], const uint64_t a[4]) { @@ -74,22 +101,6 @@ void sm2_z256_copy_conditional(uint64_t dst[4], const uint64_t src[4], uint64_t dst[3] = (src[3] & mask1) ^ (dst[3] & mask2); } -void sm2_z256_from_bytes(uint64_t r[4], const uint8_t in[32]) -{ - r[3] = GETU64(in); - r[2] = GETU64(in + 8); - r[1] = GETU64(in + 16); - r[0] = GETU64(in + 24); -} - -void sm2_z256_to_bytes(const uint64_t a[4], uint8_t out[32]) -{ - PUTU64(out, a[3]); - PUTU64(out + 8, a[2]); - PUTU64(out + 16, a[1]); - PUTU64(out + 24, a[0]); -} - static uint64_t is_zero(uint64_t in) { in |= (0 - in); @@ -294,18 +305,18 @@ int sm2_z512_print(FILE *fp, int ind, int fmt, const char *label, const uint64_t return 1; } - -// z256 mod p +// GF(p) // p = 2^256 - 2^224 - 2^96 + 2^64 - 1 +// = 0xfffffffeffffffffffffffffffffffffffffffff00000000ffffffffffffffff const uint64_t SM2_Z256_P[4] = { - 0xffffffffffffffff, 0xffffffff00000000, 0xffffffffffffffff, 0xfffffffeffffffff + 0xffffffffffffffff, 0xffffffff00000000, 0xffffffffffffffff, 0xfffffffeffffffff, }; -// mont(1) = 2^256 mod p = 2^224 + 2^96 - 2^64 + 1 +// 2^256 - p = 2^224 + 2^96 - 2^64 + 1 const uint64_t SM2_Z256_NEG_P[4] = { - 1, ((uint64_t)1 << 32) - 1, 0, ((uint64_t)1 << 32) }; - + 1, ((uint64_t)1 << 32) - 1, 0, ((uint64_t)1 << 32), +}; void sm2_z256_modp_add(uint64_t r[4], const uint64_t a[4], const uint64_t b[4]) { @@ -373,24 +384,24 @@ void sm2_z256_modp_neg(uint64_t r[4], const uint64_t a[4]) (void)sm2_z256_sub(r, SM2_Z256_P, a); } +// p' = -p^(-1) mod 2^256 +// = fffffffc00000001fffffffe00000000ffffffff000000010000000000000001 +// sage: -(IntegerModRing(2^256)(p))^-1 +const uint64_t SM2_Z256_P_PRIME[4] = { + 0x0000000000000001, 0xffffffff00000001, 0xfffffffe00000000, 0xfffffffc00000001, +}; -// montegomery - -const uint64_t *SM2_Z256_MONT_ONE = SM2_Z256_NEG_P; +// mont(1) (mod p) = 2^256 mod p = 2^256 - p +const uint64_t *SM2_Z256_MODP_MONT_ONE = SM2_Z256_NEG_P; // z = xy // c = (z + (z * p' mod 2^256) * p)/2^256 -void sm2_z256_mont_mul(uint64_t r[4], const uint64_t a[4], const uint64_t b[4]) +void sm2_z256_modp_mont_mul(uint64_t r[4], const uint64_t a[4], const uint64_t b[4]) { uint64_t z[8]; uint64_t t[8]; uint64_t c; - // p' = -p^(-1) mod 2^256 = fffffffc00000001fffffffe00000000ffffffff000000010000000000000001 - const uint64_t p_[4] = { - 0x0000000000000001, 0xffffffff00000001, 0xfffffffe00000000, 0xfffffffc00000001 - }; - //sm2_z256_print(stderr, 0, 0, "a", a); //sm2_z256_print(stderr, 0, 0, "b", b); @@ -399,7 +410,7 @@ void sm2_z256_mont_mul(uint64_t r[4], const uint64_t a[4], const uint64_t b[4]) //sm2_z512_print(stderr, 0, 0, "z", z); // t = low(z) * p' - sm2_z256_mul(t, z, p_); + sm2_z256_mul(t, z, SM2_Z256_P_PRIME); //sm2_z256_print(stderr, 0, 0, "z * p' mod 2^256", t); // t = low(t) * p @@ -415,7 +426,7 @@ void sm2_z256_mont_mul(uint64_t r[4], const uint64_t a[4], const uint64_t b[4]) //sm2_z256_print(stderr, 0, 0, "r", r); if (c) { - sm2_z256_add(r, r, SM2_Z256_MONT_ONE); + sm2_z256_add(r, r, SM2_Z256_MODP_MONT_ONE); //sm2_z256_print(stderr, 0, 0, "r1", r); } else if (sm2_z256_cmp(r, SM2_Z256_P) >= 0) { @@ -424,12 +435,35 @@ void sm2_z256_mont_mul(uint64_t r[4], const uint64_t a[4], const uint64_t b[4]) } } -void sm2_z256_mont_sqr(uint64_t r[4], const uint64_t a[4]) +void sm2_z256_modp_mont_sqr(uint64_t r[4], const uint64_t a[4]) { - sm2_z256_mont_mul(r, a, a); + sm2_z256_modp_mont_mul(r, a, a); } -void sm2_z256_mont_inv(uint64_t r[4], const uint64_t a[4]) +void sm2_z256_modp_mont_exp(uint64_t r[4], const uint64_t a[4], const uint64_t e[4]) +{ + uint64_t t[4]; + uint64_t w; + int i, j; + + // t = mont(1) (mod p) + sm2_z256_copy(t, SM2_Z256_MODP_MONT_ONE); + + for (i = 3; i >= 0; i--) { + w = e[i]; + for (j = 0; j < 64; j++) { + sm2_z256_modp_mont_sqr(t, t); + if (w & 0x8000000000000000) { + sm2_z256_modp_mont_mul(t, t, a); + } + w <<= 1; + } + } + + sm2_z256_copy(r, t); +} + +void sm2_z256_modp_mont_inv(uint64_t r[4], const uint64_t a[4]) { uint64_t a1[4]; uint64_t a2[4]; @@ -438,105 +472,264 @@ void sm2_z256_mont_inv(uint64_t r[4], const uint64_t a[4]) uint64_t a5[4]; int i; - sm2_z256_mont_sqr(a1, a); - sm2_z256_mont_mul(a2, a1, a); - sm2_z256_mont_sqr(a3, a2); - sm2_z256_mont_sqr(a3, a3); - sm2_z256_mont_mul(a3, a3, a2); - sm2_z256_mont_sqr(a4, a3); - sm2_z256_mont_sqr(a4, a4); - sm2_z256_mont_sqr(a4, a4); - sm2_z256_mont_sqr(a4, a4); - sm2_z256_mont_mul(a4, a4, a3); - sm2_z256_mont_sqr(a5, a4); + sm2_z256_modp_mont_sqr(a1, a); + sm2_z256_modp_mont_mul(a2, a1, a); + sm2_z256_modp_mont_sqr(a3, a2); + sm2_z256_modp_mont_sqr(a3, a3); + sm2_z256_modp_mont_mul(a3, a3, a2); + sm2_z256_modp_mont_sqr(a4, a3); + sm2_z256_modp_mont_sqr(a4, a4); + sm2_z256_modp_mont_sqr(a4, a4); + sm2_z256_modp_mont_sqr(a4, a4); + sm2_z256_modp_mont_mul(a4, a4, a3); + sm2_z256_modp_mont_sqr(a5, a4); for (i = 1; i < 8; i++) { - sm2_z256_mont_sqr(a5, a5); + sm2_z256_modp_mont_sqr(a5, a5); } - sm2_z256_mont_mul(a5, a5, a4); + sm2_z256_modp_mont_mul(a5, a5, a4); for (i = 0; i < 8; i++) { - sm2_z256_mont_sqr(a5, a5); + sm2_z256_modp_mont_sqr(a5, a5); } - sm2_z256_mont_mul(a5, a5, a4); + sm2_z256_modp_mont_mul(a5, a5, a4); for (i = 0; i < 4; i++) { - sm2_z256_mont_sqr(a5, a5); + sm2_z256_modp_mont_sqr(a5, a5); } - sm2_z256_mont_mul(a5, a5, a3); - sm2_z256_mont_sqr(a5, a5); - sm2_z256_mont_sqr(a5, a5); - sm2_z256_mont_mul(a5, a5, a2); - sm2_z256_mont_sqr(a5, a5); - sm2_z256_mont_mul(a5, a5, a); - sm2_z256_mont_sqr(a4, a5); - sm2_z256_mont_mul(a3, a4, a1); - sm2_z256_mont_sqr(a5, a4); + sm2_z256_modp_mont_mul(a5, a5, a3); + sm2_z256_modp_mont_sqr(a5, a5); + sm2_z256_modp_mont_sqr(a5, a5); + sm2_z256_modp_mont_mul(a5, a5, a2); + sm2_z256_modp_mont_sqr(a5, a5); + sm2_z256_modp_mont_mul(a5, a5, a); + sm2_z256_modp_mont_sqr(a4, a5); + sm2_z256_modp_mont_mul(a3, a4, a1); + sm2_z256_modp_mont_sqr(a5, a4); for (i = 1; i< 31; i++) { - sm2_z256_mont_sqr(a5, a5); + sm2_z256_modp_mont_sqr(a5, a5); } - sm2_z256_mont_mul(a4, a5, a4); - sm2_z256_mont_sqr(a4, a4); - sm2_z256_mont_mul(a4, a4, a); - sm2_z256_mont_mul(a3, a4, a2); + sm2_z256_modp_mont_mul(a4, a5, a4); + sm2_z256_modp_mont_sqr(a4, a4); + sm2_z256_modp_mont_mul(a4, a4, a); + sm2_z256_modp_mont_mul(a3, a4, a2); for (i = 0; i < 33; i++) { - sm2_z256_mont_sqr(a5, a5); + sm2_z256_modp_mont_sqr(a5, a5); } - sm2_z256_mont_mul(a2, a5, a3); - sm2_z256_mont_mul(a3, a2, a3); + sm2_z256_modp_mont_mul(a2, a5, a3); + sm2_z256_modp_mont_mul(a3, a2, a3); for (i = 0; i < 32; i++) { - sm2_z256_mont_sqr(a5, a5); + sm2_z256_modp_mont_sqr(a5, a5); } - sm2_z256_mont_mul(a2, a5, a3); - sm2_z256_mont_mul(a3, a2, a3); - sm2_z256_mont_mul(a4, a2, a4); + sm2_z256_modp_mont_mul(a2, a5, a3); + sm2_z256_modp_mont_mul(a3, a2, a3); + sm2_z256_modp_mont_mul(a4, a2, a4); for (i = 0; i < 32; i++) { - sm2_z256_mont_sqr(a5, a5); + sm2_z256_modp_mont_sqr(a5, a5); } - sm2_z256_mont_mul(a2, a5, a3); - sm2_z256_mont_mul(a3, a2, a3); - sm2_z256_mont_mul(a4, a2, a4); + sm2_z256_modp_mont_mul(a2, a5, a3); + sm2_z256_modp_mont_mul(a3, a2, a3); + sm2_z256_modp_mont_mul(a4, a2, a4); for (i = 0; i < 32; i++) { - sm2_z256_mont_sqr(a5, a5); + sm2_z256_modp_mont_sqr(a5, a5); } - sm2_z256_mont_mul(a2, a5, a3); - sm2_z256_mont_mul(a3, a2, a3); - sm2_z256_mont_mul(a4, a2, a4); + sm2_z256_modp_mont_mul(a2, a5, a3); + sm2_z256_modp_mont_mul(a3, a2, a3); + sm2_z256_modp_mont_mul(a4, a2, a4); for (i = 0; i < 32; i++) { - sm2_z256_mont_sqr(a5, a5); + sm2_z256_modp_mont_sqr(a5, a5); } - sm2_z256_mont_mul(a2, a5, a3); - sm2_z256_mont_mul(a3, a2, a3); - sm2_z256_mont_mul(a4, a2, a4); + sm2_z256_modp_mont_mul(a2, a5, a3); + sm2_z256_modp_mont_mul(a3, a2, a3); + sm2_z256_modp_mont_mul(a4, a2, a4); for (i = 0; i < 32; i++) { - sm2_z256_mont_sqr(a5, a5); + sm2_z256_modp_mont_sqr(a5, a5); } - sm2_z256_mont_mul(r, a4, a5); + sm2_z256_modp_mont_mul(r, a4, a5); } // mont(mont(a), 1) = aR * 1 * R^-1 (mod p) = a (mod p) -void sm2_z256_from_mont(uint64_t r[4], const uint64_t a[4]) +void sm2_z256_modp_from_mont(uint64_t r[4], const uint64_t a[4]) { - const uint64_t SM2_Z256_ONE[4] = { 1,0,0,0 }; - sm2_z256_mont_mul(r, a, SM2_Z256_ONE); + sm2_z256_modp_mont_mul(r, a, SM2_Z256_ONE); } +// 2^512 (mod p) +const uint64_t SM2_Z256_2e512modp[4] = { + 0x0000000200000003, 0x00000002ffffffff, 0x0000000100000001, 0x0000000400000002 +}; + // mont(a) = a * 2^256 (mod p) = mont_mul(a, 2^512 mod p) -void sm2_z256_to_mont(const uint64_t a[4], uint64_t r[4]) +void sm2_z256_modp_to_mont(const uint64_t a[4], uint64_t r[4]) { - // 2^512 (mod p) - const uint64_t SM2_Z256_2e512modp[4] = { - 0x0000000200000003, 0x00000002ffffffff, 0x0000000100000001, 0x0000000400000002 - }; - - sm2_z256_mont_mul(r, a, SM2_Z256_2e512modp); + sm2_z256_modp_mont_mul(r, a, SM2_Z256_2e512modp); } -int sm2_z256_mont_print(FILE *fp, int ind, int fmt, const char *label, const uint64_t a[4]) +int sm2_z256_modp_mont_print(FILE *fp, int ind, int fmt, const char *label, const uint64_t a[4]) { uint64_t r[4]; - sm2_z256_from_mont(r, a); + sm2_z256_modp_from_mont(r, a); sm2_z256_print(fp, ind, fmt, label, r); return 1; } +// GF(n) + +// n = 0xfffffffeffffffffffffffffffffffff7203df6b21c6052b53bbf40939d54123 +const uint64_t SM2_Z256_N[4] = { + 0x53bbf40939d54123, 0x7203df6b21c6052b, 0xffffffffffffffff, 0xfffffffeffffffff, +}; + +// 2^256 - n = 0x10000000000000000000000008dfc2094de39fad4ac440bf6c62abedd +const uint64_t SM2_Z256_NEG_N[4] = { + 0xac440bf6c62abedd, 0x8dfc2094de39fad4, 0x0000000000000000, 0x0000000100000000, +}; + +void sm2_z256_modn_add(uint64_t r[4], const uint64_t a[4], const uint64_t b[4]) +{ + uint64_t c; + + c = sm2_z256_add(r, a, b); + + if (c) { + // a + b - n = (a + b - 2^256) + (2^256 - n) + (void)sm2_z256_add(r, r, SM2_Z256_NEG_N); + return; + } + + if (sm2_z256_cmp(r, SM2_Z256_N) >= 0) { + (void)sm2_z256_sub(r, r, SM2_Z256_N); + } +} + +void sm2_z256_modn_sub(uint64_t r[4], const uint64_t a[4], const uint64_t b[4]) +{ + uint64_t c; + + c = sm2_z256_sub(r, a, b); + + if (c) { + // a - b + n = (a - b + 2^256) - (2^256 - n) + (void)sm2_z256_sub(r, r, SM2_Z256_NEG_N); + } +} + +void sm2_z256_modn_neg(uint64_t r[4], const uint64_t a[4]) +{ + (void)sm2_z256_sub(r, SM2_Z256_N, a); +} + +// n' = -n^(-1) mod 2^256 +// = 0x6f39132f82e4c7bc2b0068d3b08941d4df1e8d34fc8319a5327f9e8872350975 +// sage: -(IntegerModRing(2^256)(n))^-1 +const uint64_t SM2_Z256_N_PRIME[4] = { + 0x327f9e8872350975, 0xdf1e8d34fc8319a5, 0x2b0068d3b08941d4, 0x6f39132f82e4c7bc, +}; + +// mont(1) (mod n) = 2^256 - n +const uint64_t *SM2_Z256_MODN_MONT_ONE = SM2_Z256_NEG_N; + +void sm2_z256_modn_mont_mul(uint64_t r[4], const uint64_t a[4], const uint64_t b[4]) +{ + uint64_t z[8]; + uint64_t t[8]; + uint64_t c; + + //sm2_z256_print(stderr, 0, 0, "a", a); + //sm2_z256_print(stderr, 0, 0, "b", b); + + // z = a * b + sm2_z256_mul(z, a, b); + //sm2_z512_print(stderr, 0, 0, "z", z); + + // t = low(z) * n' + sm2_z256_mul(t, z, SM2_Z256_N_PRIME); + //sm2_z256_print(stderr, 0, 0, "z * n' mod 2^256", t); + + // t = low(t) * n + sm2_z256_mul(t, t, SM2_Z256_N); + //sm2_z512_print(stderr, 0, 0, "(z * n' mod 2^256) * n", t); + + // z = z + t + c = sm2_z512_add(z, z, t); + //sm2_z512_print(stderr, 0, 0, "z", z); + + // r = high(r) + sm2_z256_copy(r, z + 4); + //sm2_z256_print(stderr, 0, 0, "r", r); + + if (c) { + sm2_z256_add(r, r, SM2_Z256_MODN_MONT_ONE); + //sm2_z256_print(stderr, 0, 0, "r1", r); + + } else if (sm2_z256_cmp(r, SM2_Z256_N) >= 0) { + (void)sm2_z256_sub(r, r, SM2_Z256_N); + //sm2_z256_print(stderr, 0, 0, "r2", r); + } +} + +void sm2_z256_modn_mont_sqr(uint64_t r[4], const uint64_t a[4]) +{ + sm2_z256_modn_mont_mul(r, a, a); +} + +void sm2_z256_modn_mont_exp(uint64_t r[4], const uint64_t a[4], const uint64_t e[4]) +{ + uint64_t t[4]; + uint64_t w; + int i, j; + + // t = mont(1) + sm2_z256_copy(t, SM2_Z256_MODN_MONT_ONE); + + for (i = 3; i >= 0; i--) { + w = e[i]; + for (j = 0; j < 64; j++) { + sm2_z256_modn_mont_sqr(t, t); + if (w & 0x8000000000000000) { + sm2_z256_modn_mont_mul(t, t, a); + } + w <<= 1; + } + } + + sm2_z256_copy(r, t); +} + +// n - 2 = 0xfffffffeffffffffffffffffffffffff7203df6b21c6052b53bbf40939d54121 +const uint64_t SM2_Z256_N_MINUS_TWO[4] = { + 0x53bbf40939d54121, 0x7203df6b21c6052b, 0xffffffffffffffff, 0xfffffffeffffffff, +}; + +void sm2_z256_modn_mont_inv(uint64_t r[4], const uint64_t a[4]) +{ + sm2_z256_modn_mont_exp(r, a, SM2_Z256_N_MINUS_TWO); +} + +// mont(mont(a), 1) = aR * 1 * R^-1 (mod n) = a (mod p) +void sm2_z256_modn_from_mont(uint64_t r[4], const uint64_t a[4]) +{ + sm2_z256_modn_mont_mul(r, a, SM2_Z256_ONE); +} + + +// 2^512 (mod n) = 0x1eb5e412a22b3d3b620fc84c3affe0d43464504ade6fa2fa901192af7c114f20 +const uint64_t SM2_Z256_2e512modn[4] = { + 0x901192af7c114f20, 0x3464504ade6fa2fa, 0x620fc84c3affe0d4, 0x1eb5e412a22b3d3b, +}; + +// mont(a) = a * 2^256 (mod n) = mont_mul(a, 2^512 mod n) +void sm2_z256_modn_to_mont(const uint64_t a[4], uint64_t r[4]) +{ + sm2_z256_modn_mont_mul(r, a, SM2_Z256_2e512modn); +} + +int sm2_z256_modn_mont_print(FILE *fp, int ind, int fmt, const char *label, const uint64_t a[4]) +{ + uint64_t r[4]; + sm2_z256_modn_from_mont(r, a); + sm2_z256_print(fp, ind, fmt, label, r); + return 1; +} + + // Jacobian Point with Montgomery coordinates void sm2_z256_point_dbl(SM2_Z256_POINT *R, const SM2_Z256_POINT *A) @@ -554,75 +747,75 @@ void sm2_z256_point_dbl(SM2_Z256_POINT *R, const SM2_Z256_POINT *A) // S = 2*Y1 sm2_z256_modp_mul_by_2(S, Y1); - //sm2_z256_mont_print(stderr, 0, 0, "1", S); + //sm2_z256_modp_mont_print(stderr, 0, 0, "1", S); // Zsqr = Z1^2 - sm2_z256_mont_sqr(Zsqr, Z1); - //sm2_z256_mont_print(stderr, 0, 0, "2", Zsqr); + sm2_z256_modp_mont_sqr(Zsqr, Z1); + //sm2_z256_modp_mont_print(stderr, 0, 0, "2", Zsqr); // S = S^2 = 4*Y1^2 - sm2_z256_mont_sqr(S, S); - //sm2_z256_mont_print(stderr, 0, 0, "3", S); + sm2_z256_modp_mont_sqr(S, S); + //sm2_z256_modp_mont_print(stderr, 0, 0, "3", S); // Z3 = Z1 * Y1 - sm2_z256_mont_mul(Z3, Z1, Y1); - //sm2_z256_mont_print(stderr, 0, 0, "4", Z3); + sm2_z256_modp_mont_mul(Z3, Z1, Y1); + //sm2_z256_modp_mont_print(stderr, 0, 0, "4", Z3); // Z3 = 2 * Z3 = 2*Y1*Z1 sm2_z256_modp_mul_by_2(Z3, Z3); - //sm2_z256_mont_print(stderr, 0, 0, "5", Z3); + //sm2_z256_modp_mont_print(stderr, 0, 0, "5", Z3); // M = X1 + Zsqr = X1 + Z1^2 sm2_z256_modp_add(M, X1, Zsqr); - //sm2_z256_mont_print(stderr, 0, 0, "6", M); + //sm2_z256_modp_mont_print(stderr, 0, 0, "6", M); // Zsqr = X1 - Zsqr = X1 - Z1^2 sm2_z256_modp_sub(Zsqr, X1, Zsqr); - //sm2_z256_mont_print(stderr, 0, 0, "7", Zsqr); + //sm2_z256_modp_mont_print(stderr, 0, 0, "7", Zsqr); // Y3 = S^2 = 16 * Y1^4 - sm2_z256_mont_sqr(Y3, S); - //sm2_z256_mont_print(stderr, 0, 0, "8", Y3); + sm2_z256_modp_mont_sqr(Y3, S); + //sm2_z256_modp_mont_print(stderr, 0, 0, "8", Y3); // Y3 = Y3/2 = 8 * Y1^4 sm2_z256_modp_div_by_2(Y3, Y3); - //sm2_z256_mont_print(stderr, 0, 0, "9", Y3); + //sm2_z256_modp_mont_print(stderr, 0, 0, "9", Y3); // M = M * Zsqr = (X1 + Z1^2)(X1 - Z1^2) - sm2_z256_mont_mul(M, M, Zsqr); - //sm2_z256_mont_print(stderr, 0, 0, "10", M); + sm2_z256_modp_mont_mul(M, M, Zsqr); + //sm2_z256_modp_mont_print(stderr, 0, 0, "10", M); // M = 3*M = 3(X1 + Z1^2)(X1 - Z1^2) sm2_z256_modp_mul_by_3(M, M); - //sm2_z256_mont_print(stderr, 0, 0, "11", M); + //sm2_z256_modp_mont_print(stderr, 0, 0, "11", M); // S = S * X1 = 4 * X1 * Y1^2 - sm2_z256_mont_mul(S, S, X1); - //sm2_z256_mont_print(stderr, 0, 0, "12", S); + sm2_z256_modp_mont_mul(S, S, X1); + //sm2_z256_modp_mont_print(stderr, 0, 0, "12", S); // tmp0 = 2 * S = 8 * X1 * Y1^2 sm2_z256_modp_mul_by_2(tmp0, S); - //sm2_z256_mont_print(stderr, 0, 0, "13", tmp0); + //sm2_z256_modp_mont_print(stderr, 0, 0, "13", tmp0); // X3 = M^2 = (3(X1 + Z1^2)(X1 - Z1^2))^2 - sm2_z256_mont_sqr(X3, M); - //sm2_z256_mont_print(stderr, 0, 0, "14", X3); + sm2_z256_modp_mont_sqr(X3, M); + //sm2_z256_modp_mont_print(stderr, 0, 0, "14", X3); // X3 = X3 - tmp0 = (3(X1 + Z1^2)(X1 - Z1^2))^2 - 8 * X1 * Y1^2 sm2_z256_modp_sub(X3, X3, tmp0); - //sm2_z256_mont_print(stderr, 0, 0, "15", X3); + //sm2_z256_modp_mont_print(stderr, 0, 0, "15", X3); // S = S - X3 = 4 * X1 * Y1^2 - X3 sm2_z256_modp_sub(S, S, X3); - //sm2_z256_mont_print(stderr, 0, 0, "16", S); + //sm2_z256_modp_mont_print(stderr, 0, 0, "16", S); // S = S * M = 3(X1 + Z1^2)(X1 - Z1^2)(4 * X1 * Y1^2 - X3) - sm2_z256_mont_mul(S, S, M); - //sm2_z256_mont_print(stderr, 0, 0, "17", S); + sm2_z256_modp_mont_mul(S, S, M); + //sm2_z256_modp_mont_print(stderr, 0, 0, "17", S); // Y3 = S - Y3 = 3(X1 + Z1^2)(X1 - Z1^2)(4 * X1 * Y1^2 - X3) - 8 * Y1^4 sm2_z256_modp_sub(Y3, S, Y3); - //sm2_z256_mont_print(stderr, 0, 0, "18", Y3); + //sm2_z256_modp_mont_print(stderr, 0, 0, "18", Y3); } void sm2_z256_point_add(SM2_Z256_POINT *r, const SM2_Z256_POINT *a, const SM2_Z256_POINT *b) @@ -660,18 +853,18 @@ void sm2_z256_point_add(SM2_Z256_POINT *r, const SM2_Z256_POINT *a, const SM2_Z2 in1infty = is_zero(in1infty); in2infty = is_zero(in2infty); - sm2_z256_mont_sqr(Z2sqr, in2_z); /* Z2^2 */ - sm2_z256_mont_sqr(Z1sqr, in1_z); /* Z1^2 */ + sm2_z256_modp_mont_sqr(Z2sqr, in2_z); /* Z2^2 */ + sm2_z256_modp_mont_sqr(Z1sqr, in1_z); /* Z1^2 */ - sm2_z256_mont_mul(S1, Z2sqr, in2_z); /* S1 = Z2^3 */ - sm2_z256_mont_mul(S2, Z1sqr, in1_z); /* S2 = Z1^3 */ + sm2_z256_modp_mont_mul(S1, Z2sqr, in2_z); /* S1 = Z2^3 */ + sm2_z256_modp_mont_mul(S2, Z1sqr, in1_z); /* S2 = Z1^3 */ - sm2_z256_mont_mul(S1, S1, in1_y); /* S1 = Y1*Z2^3 */ - sm2_z256_mont_mul(S2, S2, in2_y); /* S2 = Y2*Z1^3 */ + sm2_z256_modp_mont_mul(S1, S1, in1_y); /* S1 = Y1*Z2^3 */ + sm2_z256_modp_mont_mul(S2, S2, in2_y); /* S2 = Y2*Z1^3 */ sm2_z256_modp_sub(R, S2, S1); /* R = S2 - S1 */ - sm2_z256_mont_mul(U1, in1_x, Z2sqr); /* U1 = X1*Z2^2 */ - sm2_z256_mont_mul(U2, in2_x, Z1sqr); /* U2 = X2*Z1^2 */ + sm2_z256_modp_mont_mul(U1, in1_x, Z2sqr); /* U1 = X1*Z2^2 */ + sm2_z256_modp_mont_mul(U2, in2_x, Z1sqr); /* U2 = X2*Z1^2 */ sm2_z256_modp_sub(H, U2, U1); /* H = U2 - U1 */ /* @@ -687,13 +880,13 @@ void sm2_z256_point_add(SM2_Z256_POINT *r, const SM2_Z256_POINT *a, const SM2_Z2 } } - sm2_z256_mont_sqr(Rsqr, R); /* R^2 */ - sm2_z256_mont_mul(res_z, H, in1_z); /* Z3 = H*Z1*Z2 */ - sm2_z256_mont_sqr(Hsqr, H); /* H^2 */ - sm2_z256_mont_mul(res_z, res_z, in2_z); /* Z3 = H*Z1*Z2 */ - sm2_z256_mont_mul(Hcub, Hsqr, H); /* H^3 */ + sm2_z256_modp_mont_sqr(Rsqr, R); /* R^2 */ + sm2_z256_modp_mont_mul(res_z, H, in1_z); /* Z3 = H*Z1*Z2 */ + sm2_z256_modp_mont_sqr(Hsqr, H); /* H^2 */ + sm2_z256_modp_mont_mul(res_z, res_z, in2_z); /* Z3 = H*Z1*Z2 */ + sm2_z256_modp_mont_mul(Hcub, Hsqr, H); /* H^3 */ - sm2_z256_mont_mul(U2, U1, Hsqr); /* U1*H^2 */ + sm2_z256_modp_mont_mul(U2, U1, Hsqr); /* U1*H^2 */ sm2_z256_modp_mul_by_2(Hsqr, U2); /* 2*U1*H^2 */ sm2_z256_modp_sub(res_x, Rsqr, Hsqr); @@ -701,8 +894,8 @@ void sm2_z256_point_add(SM2_Z256_POINT *r, const SM2_Z256_POINT *a, const SM2_Z2 sm2_z256_modp_sub(res_y, U2, res_x); - sm2_z256_mont_mul(S2, S1, Hcub); - sm2_z256_mont_mul(res_y, R, res_y); + sm2_z256_modp_mont_mul(S2, S1, Hcub); + sm2_z256_modp_mont_mul(res_y, R, res_y); sm2_z256_modp_sub(res_y, res_y, S2); sm2_z256_copy_conditional(res_x, in2_x, in1infty); @@ -739,34 +932,31 @@ void sm2_z256_point_get_affine(const SM2_Z256_POINT *P, uint64_t x[4], uint64_t uint64_t y_out[4]; // z_inv = 1/Z - sm2_z256_mont_inv(z_inv, P->Z); + sm2_z256_modp_mont_inv(z_inv, P->Z); // y_out = Y/Z if (y) { - sm2_z256_mont_mul(y_out, P->Y, z_inv); + sm2_z256_modp_mont_mul(y_out, P->Y, z_inv); } // z_inv = 1/Z^2 - sm2_z256_mont_sqr(z_inv, z_inv); + sm2_z256_modp_mont_sqr(z_inv, z_inv); // x_out = X/Z^2 - sm2_z256_mont_mul(x_out, P->X, z_inv); - sm2_z256_from_mont(x, x_out); + sm2_z256_modp_mont_mul(x_out, P->X, z_inv); + sm2_z256_modp_from_mont(x, x_out); if (y) { // y_out = Y/Z^3 - sm2_z256_mont_mul(y_out, y_out, z_inv); - sm2_z256_from_mont(y, y_out); + sm2_z256_modp_mont_mul(y_out, y_out, z_inv); + sm2_z256_modp_from_mont(y, y_out); } } - - - void sm2_z256_point_copy_affine(SM2_Z256_POINT *R, const SM2_Z256_POINT_AFFINE *P) { memcpy(R, P, sizeof(SM2_Z256_POINT_AFFINE)); - sm2_z256_copy(R->Z, SM2_Z256_MONT_ONE); + sm2_z256_copy(R->Z, SM2_Z256_MODP_MONT_ONE); } void sm2_z256_point_add_affine(SM2_Z256_POINT *r, const SM2_Z256_POINT *a, const SM2_Z256_POINT_AFFINE *b) @@ -807,33 +997,33 @@ void sm2_z256_point_add_affine(SM2_Z256_POINT *r, const SM2_Z256_POINT *a, const /* Z1^2 */ - sm2_z256_mont_sqr(Z1sqr, in1_z); + sm2_z256_modp_mont_sqr(Z1sqr, in1_z); /* U2 = X2*Z1^2 */ - sm2_z256_mont_mul(U2, in2_x, Z1sqr); + sm2_z256_modp_mont_mul(U2, in2_x, Z1sqr); /* H = U2 - U1 */ sm2_z256_modp_sub(H, U2, in1_x); - sm2_z256_mont_mul(S2, Z1sqr, in1_z); /* S2 = Z1^3 */ + sm2_z256_modp_mont_mul(S2, Z1sqr, in1_z); /* S2 = Z1^3 */ - sm2_z256_mont_mul(res_z, H, in1_z); /* Z3 = H*Z1*Z2 */ + sm2_z256_modp_mont_mul(res_z, H, in1_z); /* Z3 = H*Z1*Z2 */ - sm2_z256_mont_mul(S2, S2, in2_y); /* S2 = Y2*Z1^3 */ + sm2_z256_modp_mont_mul(S2, S2, in2_y); /* S2 = Y2*Z1^3 */ sm2_z256_modp_sub(R, S2, in1_y); /* R = S2 - S1 */ - sm2_z256_mont_sqr(Hsqr, H); /* H^2 */ - sm2_z256_mont_sqr(Rsqr, R); /* R^2 */ - sm2_z256_mont_mul(Hcub, Hsqr, H); /* H^3 */ + sm2_z256_modp_mont_sqr(Hsqr, H); /* H^2 */ + sm2_z256_modp_mont_sqr(Rsqr, R); /* R^2 */ + sm2_z256_modp_mont_mul(Hcub, Hsqr, H); /* H^3 */ - sm2_z256_mont_mul(U2, in1_x, Hsqr); /* U1*H^2 */ + sm2_z256_modp_mont_mul(U2, in1_x, Hsqr); /* U1*H^2 */ sm2_z256_modp_mul_by_2(Hsqr, U2); /* 2*U1*H^2 */ sm2_z256_modp_sub(res_x, Rsqr, Hsqr); sm2_z256_modp_sub(res_x, res_x, Hcub); sm2_z256_modp_sub(H, U2, res_x); - sm2_z256_mont_mul(S2, in1_y, Hcub); - sm2_z256_mont_mul(H, H, R); + sm2_z256_modp_mont_mul(S2, in1_y, Hcub); + sm2_z256_modp_mont_mul(H, H, R); sm2_z256_modp_sub(res_y, H, S2); sm2_z256_copy_conditional(res_x, in2_x, in1infty); @@ -842,7 +1032,7 @@ void sm2_z256_point_add_affine(SM2_Z256_POINT *r, const SM2_Z256_POINT *a, const sm2_z256_copy_conditional(res_y, in2_y, in1infty); sm2_z256_copy_conditional(res_y, in1_y, in2infty); - sm2_z256_copy_conditional(res_z, SM2_Z256_MONT_ONE, in1infty); + sm2_z256_copy_conditional(res_z, SM2_Z256_MODP_MONT_ONE, in1infty); sm2_z256_copy_conditional(res_z, in1_z, in2infty); memcpy(r->X, res_x, sizeof(res_x)); @@ -880,10 +1070,10 @@ int sm2_z256_point_affine_print(FILE *fp, int fmt, int ind, const char *label, c uint8_t affine[64]; uint64_t a[4]; - sm2_z256_from_mont(a, P->x); + sm2_z256_modp_from_mont(a, P->x); sm2_z256_to_bytes(a, affine); - sm2_z256_from_mont(a, P->y); + sm2_z256_modp_from_mont(a, P->y); sm2_z256_to_bytes(a, affine + 32); format_bytes(fp, fmt, ind, label, affine, 64); @@ -985,7 +1175,6 @@ void sm2_z256_point_mul_sum(SM2_Z256_POINT *R, const uint64_t t[4], const SM2_Z2 sm2_z256_point_add(R, R, &Q); } - void sm2_z256_point_to_bytes(const SM2_Z256_POINT *P, uint8_t out[64]) { uint64_t x[4]; @@ -995,10 +1184,3 @@ void sm2_z256_point_to_bytes(const SM2_Z256_POINT *P, uint8_t out[64]) sm2_z256_to_bytes(x, out); sm2_z256_to_bytes(y, out + 32); } - - - - - - - diff --git a/tests/sm2_z256test.c b/tests/sm2_z256test.c index 0374deb0..d95041b2 100644 --- a/tests/sm2_z256test.c +++ b/tests/sm2_z256test.c @@ -17,69 +17,366 @@ #include #include +enum { + OP_ADD, + OP_SUB, + OP_NEG, + OP_MUL, + OP_SQR, + OP_EXP, + OP_INV, +}; + +static int test_sm2_z256_modp(void) +{ + struct { + char *label; + int op; + char *r; + char *a; + char *b; + } tests[] = { + { + "x + y (mod p)", OP_ADD, + "eefbe4cf140ff8b5b956d329d5a2eae8608c933cb89053217439786e54866567", + "32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7", + "bc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0", + }, + { + "x - y (mod p)", OP_SUB, + "768d77882a23097d05db3562fed0a840bf3984422c3bc4a26e7b12a412128426", + "32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7", + "bc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0", + }, + { + "y - x (mod p)", OP_SUB, + "89728876d5dcf682fa24ca9d012f57bf40c67bbcd3c43b5e9184ed5beded7bd9", + "bc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0", + "32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7", + }, + { + "-x (mod p)", OP_NEG, + "cd3b51d2e0e67ee6a066fbb995c6366b701cf43f0d99f41f8ea5ba76ccb38b38", + "32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7", + NULL, + }, + { + "x * y (mod p)", OP_MUL, + "edd7e745bdc4630ccfa1da1057033a525346dbf202f082f3c431349991ace76a", + "32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7", + "bc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0", + }, + { + "x^2 (mod p)", OP_SQR, + "f4e2cca0bcfd67fba8531eebff519e4cb3d47f9fe8c5eff5151f4c497ec99fbf", + "32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7", + NULL, + }, + { + "x^y (mod p)", OP_EXP, + "8cafd11b1a0d2072b82911ba87e0d376103a1be5986fce91d8d297b758f68146", + "32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7", + "bc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0", + }, + { + "x^-1 (mod p)", OP_INV, + "053b878fb82e213c17e554b9a574b7bd31775222704b7fd9c7d6f8441026cd80", + "32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7", + NULL, + }, + }; + + uint64_t r[4]; + uint64_t a[4]; + uint64_t b[4]; + uint64_t c[4]; + size_t i; + + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + + sm2_z256_from_hex(r, tests[i].r); + sm2_z256_from_hex(a, tests[i].a); + if (tests[i].b) { + sm2_z256_from_hex(b, tests[i].b); + } + + switch (tests[i].op) { + case OP_ADD: + sm2_z256_modp_add(c, a, b); + break; + case OP_SUB: + sm2_z256_modp_sub(c, a, b); + break; + case OP_NEG: + sm2_z256_modp_neg(c, a); + break; + case OP_MUL: + sm2_z256_modp_to_mont(a, a); + sm2_z256_modp_to_mont(b, b); + sm2_z256_modp_mont_mul(c, a, b); + sm2_z256_modp_from_mont(c, c); + break; + case OP_SQR: + sm2_z256_modp_to_mont(a, a); + sm2_z256_modp_mont_sqr(c, a); + sm2_z256_modp_from_mont(c, c); + break; + case OP_EXP: + sm2_z256_modp_to_mont(a, a); + sm2_z256_modp_mont_exp(c, a, b); + sm2_z256_modp_from_mont(c, c); + break; + case OP_INV: + sm2_z256_modp_to_mont(a, a); + sm2_z256_modp_mont_inv(c, a); + sm2_z256_modp_from_mont(c, c); + break; + default: + error_print(); + return -1; + } + + if (sm2_z256_cmp(r, c) != 0) { + + fprintf(stderr, "%s: error\n", __FUNCTION__); + fprintf(stderr, " %s\n", tests[i].label); + sm2_z256_print(stderr, 0, 8, "err", c); + fprintf(stderr, " ret: %s\n", tests[i].r); + fprintf(stderr, " op1: %s\n", tests[i].a); + if (tests[i].b) { + fprintf(stderr, " op2: %s\n", tests[i].b); + } + + error_print(); + return -1; + } + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + +static int test_sm2_z256_modn(void) +{ + struct { + char *label; + int op; + char *r; + char *a; + char *b; + } tests[] = { + { + "x + y (mod n)", OP_ADD, + "eefbe4cf140ff8b5b956d329d5a2eae8608c933cb89053217439786e54866567", + "32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7", + "bc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0", + }, + { + "x - y (mod n)", OP_SUB, + "768d77882a23097d05db3562fed0a840313d63ae4e01c9ccc23706ad4be7c54a", + "32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7", + "bc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0", + }, + { + "y - x (mod n)", OP_SUB, + "89728876d5dcf682fa24ca9d012f57bf40c67bbcd3c43b5e9184ed5beded7bd9", + "bc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0", + "32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7", + }, + { + "-x (mod n)", OP_NEG, + "cd3b51d2e0e67ee6a066fbb995c6366ae220d3ab2f5ff949e261ae800688cc5c", + "32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7", + NULL, + }, + { + "x * y (mod n)", OP_MUL, + "cf7296d5cbf0b64bb5e9a11b294962e9c779b41c038e9c8d815234a0df9d6623", + "32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7", + "bc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0", + }, + { + "x^2 (mod n)", OP_SQR, + "82d3d1b296d3a3803888b7ffc78f23eca824e7ec8d7ddaf231ffb0d256a19da2", + "32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7", + NULL, + }, + { + "x^y (mod n)", OP_EXP, + "0cf4df7e76d7d49ff23b94853a98aba1e36e9ca0358acbf23a3bbda406f46df3", + "32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7", + "bc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0", + }, + { + "x^-1 (mod n)", OP_INV, + "96340ec8b80f44e9b345a706bdb5c9e3ab8a6474a5cb4e0d4645dbaecf1cf03d", + "32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7", + NULL, + }, + }; + + uint64_t r[4]; + uint64_t a[4]; + uint64_t b[4]; + uint64_t c[4]; + size_t i; + + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + + sm2_z256_from_hex(r, tests[i].r); + sm2_z256_from_hex(a, tests[i].a); + if (tests[i].b) { + sm2_z256_from_hex(b, tests[i].b); + } + + switch (tests[i].op) { + case OP_ADD: + sm2_z256_modn_add(c, a, b); + break; + case OP_SUB: + sm2_z256_modn_sub(c, a, b); + break; + case OP_NEG: + sm2_z256_modn_neg(c, a); + break; + case OP_MUL: + sm2_z256_modn_to_mont(a, a); + sm2_z256_modn_to_mont(b, b); + sm2_z256_modn_mont_mul(c, a, b); + sm2_z256_modn_from_mont(c, c); + break; + case OP_SQR: + sm2_z256_modn_to_mont(a, a); + sm2_z256_modn_mont_sqr(c, a); + sm2_z256_modn_from_mont(c, c); + break; + case OP_EXP: + sm2_z256_modn_to_mont(a, a); + sm2_z256_modn_mont_exp(c, a, b); + sm2_z256_modn_from_mont(c, c); + break; + case OP_INV: + sm2_z256_modn_to_mont(a, a); + sm2_z256_modn_mont_inv(c, a); + sm2_z256_modn_from_mont(c, c); + break; + default: + error_print(); + return -1; + } + + if (sm2_z256_cmp(r, c) != 0) { + + fprintf(stderr, "%s: error\n", __FUNCTION__); + fprintf(stderr, " %s\n", tests[i].label); + sm2_z256_print(stderr, 0, 8, "err", c); + fprintf(stderr, " ret: %s\n", tests[i].r); + fprintf(stderr, " op1: %s\n", tests[i].a); + if (tests[i].b) { + fprintf(stderr, " op2: %s\n", tests[i].b); + } + + error_print(); + return -1; + } + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} static int test_sm2_z256_point_mul_generator(void) { struct { + char *label; char *k; char *kG; } tests[] = { - // k = 0 - {"0000000000000000000000000000000000000000000000000000000000000000", - "0000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000"}, - // k = 1 - {"0000000000000000000000000000000000000000000000000000000000000001", - "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7" - "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0"}, - // k = 2 - {"0000000000000000000000000000000000000000000000000000000000000002", - "56CEFD60D7C87C000D58EF57FA73BA4D9C0DFA08C08A7331495C2E1DA3F2BD52" - "31B7E7E6CC8189F668535CE0F8EAF1BD6DE84C182F6C8E716F780D3A970A23C3"}, - // k = 3 - {"0000000000000000000000000000000000000000000000000000000000000003", - "A97F7CD4B3C993B4BE2DAA8CDB41E24CA13F6BD945302244E26918F1D0509EBF" - "530B5DD88C688EF5CCC5CEC08A72150F7C400EE5CD045292AAACDD037458F6E6"}, - // k = 4 - {"0000000000000000000000000000000000000000000000000000000000000004", - "C239507105C683242A81052FF641ED69009A084AD5CC937DB21646CD34A0CED5" - "B1BF7EC4080F3C8735F1294AC0DB19686BEE2E96AB8C71FB7A253666CB66E009"}, - // k = 5 - {"0000000000000000000000000000000000000000000000000000000000000005", - "C749061668652E26040E008FDD5EB77A344A417B7FCE19DBA575DA57CC372A9E" - "F2DF5DB2D144E9454504C622B51CF38F5006206EB579FF7DA6976EFF5FBE6480"}, - // k = 6 - {"0000000000000000000000000000000000000000000000000000000000000006", - "0927AFB57D93483BBB17C93E71F22A3105FF8856A66016892C8B1A1A3C4B0D30" - "150C6B1AB4D1FC7EAC1C0EF6EBF2664581ADF1F0855A064DD572103000088F63"}, - // k = 7 - {"0000000000000000000000000000000000000000000000000000000000000007", - "DDF092555409C19DFDBE86A75C139906A80198337744EE78CD27E384D9FCAF15" - "847D18FFB38E87065CD6B6E9C12D2922037937707D6A49A2223B949657E52BC1"}, + { + "[0]G", + "0000000000000000000000000000000000000000000000000000000000000000", + "0000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "[1]G", + "0000000000000000000000000000000000000000000000000000000000000001", + "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7" + "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", + }, + { + "[2]G", + "0000000000000000000000000000000000000000000000000000000000000002", + "56CEFD60D7C87C000D58EF57FA73BA4D9C0DFA08C08A7331495C2E1DA3F2BD52" + "31B7E7E6CC8189F668535CE0F8EAF1BD6DE84C182F6C8E716F780D3A970A23C3", + }, + { + "[3]G", + "0000000000000000000000000000000000000000000000000000000000000003", + "A97F7CD4B3C993B4BE2DAA8CDB41E24CA13F6BD945302244E26918F1D0509EBF" + "530B5DD88C688EF5CCC5CEC08A72150F7C400EE5CD045292AAACDD037458F6E6", + }, + { + "[4]G", + "0000000000000000000000000000000000000000000000000000000000000004", + "C239507105C683242A81052FF641ED69009A084AD5CC937DB21646CD34A0CED5" + "B1BF7EC4080F3C8735F1294AC0DB19686BEE2E96AB8C71FB7A253666CB66E009", + }, + { + "[5]G", + "0000000000000000000000000000000000000000000000000000000000000005", + "C749061668652E26040E008FDD5EB77A344A417B7FCE19DBA575DA57CC372A9E" + "F2DF5DB2D144E9454504C622B51CF38F5006206EB579FF7DA6976EFF5FBE6480", + }, + { + "[6]G", + "0000000000000000000000000000000000000000000000000000000000000006", + "0927AFB57D93483BBB17C93E71F22A3105FF8856A66016892C8B1A1A3C4B0D30" + "150C6B1AB4D1FC7EAC1C0EF6EBF2664581ADF1F0855A064DD572103000088F63", + }, + { + "[7]G", + "0000000000000000000000000000000000000000000000000000000000000007", + "DDF092555409C19DFDBE86A75C139906A80198337744EE78CD27E384D9FCAF15" + "847D18FFB38E87065CD6B6E9C12D2922037937707D6A49A2223B949657E52BC1", + }, // k = G.x - {"32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", - "782E1941B8A8C802543BC831E19F3548235C94A9C42AAD1EA8952CEAAECF12BA" - "EEE0D9A6939E87F3B47A85863F873B324B9859136E2BF3235E17B3270164202D"}, - // k = G.y - {"BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", - "1000165E3FFF85F1DFFFB3AA1DF9F5E62B9A86A9A2927B4FF1AC16D19FEFF330" - "3116F22B65320DD3B7F73DCF4A4028063A9BE6EFBD1DB0915C72F1EE067C5ECF"}, - // k = n - 1 = -1 - {"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54122", - "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7" - "43C8C95C0B098863A642311C9496DEAC2F56788239D5B8C0FD20CD1ADEC60F5F"}, - // k = n = 0 - {"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", - "0000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000"}, - // k = n + 1 = 1 - {"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54124", - "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7" - "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0"}, - // k = 2^256 - 1 - {"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", - "B3217D884BC175E6BA6B360EB0E6D4396EAEA725C3D66E87BFA5BEB6C0D3456B" - "A5199445C54B56602AA60025E1907BFD26B30E867DB6C58A034263AE4A2E27C2"}, + { + "[x]G", + "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", + "782E1941B8A8C802543BC831E19F3548235C94A9C42AAD1EA8952CEAAECF12BA" + "EEE0D9A6939E87F3B47A85863F873B324B9859136E2BF3235E17B3270164202D", + }, + { + "[y]G", + "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", + "1000165E3FFF85F1DFFFB3AA1DF9F5E62B9A86A9A2927B4FF1AC16D19FEFF330" + "3116F22B65320DD3B7F73DCF4A4028063A9BE6EFBD1DB0915C72F1EE067C5ECF", + }, + { + "[n-1]G", + "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54122", + "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7" + "43C8C95C0B098863A642311C9496DEAC2F56788239D5B8C0FD20CD1ADEC60F5F", + }, + { + "[n]G", + "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", + "0000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "[n+1]G", + "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54124", + "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7" + "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", + }, + { + "[2^256 - 1]G", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + "B3217D884BC175E6BA6B360EB0E6D4396EAEA725C3D66E87BFA5BEB6C0D3456B" + "A5199445C54B56602AA60025E1907BFD26B30E867DB6C58A034263AE4A2E27C2", + }, }; uint64_t k[4]; @@ -97,6 +394,13 @@ static int test_sm2_z256_point_mul_generator(void) sm2_z256_point_to_bytes(&P, P_bytes); if (memcmp(P_bytes, kG_bytes, 64) != 0) { + + fprintf(stderr, "%s: error\n", __FUNCTION__); + fprintf(stderr, " %s\n", tests[i].label); + fprintf(stderr, " k: %s\n", tests[i].k); + fprintf(stderr, " R: %s\n", tests[i].kG); + format_bytes(stderr, 0, 4, "P", P_bytes, 64); + error_print(); return -1; } @@ -108,62 +412,8 @@ static int test_sm2_z256_point_mul_generator(void) int main(void) { -/* - SM2_POINT P; - uint8_t k[32] = {0}; - uint8_t i; - - for (i = 0; i < 8; i++) { - k[31] = i; - - format_bytes(stderr, 0, 0, "k", k, 32); - - sm2_point_mul_generator(&P, k); - sm2_point_print(stdout, 0, 4, "kG", &P); - } - - size_t len; - - char *xG = "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7"; - char *yG = "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0"; - - hex_to_bytes(xG, strlen(xG), k, &len); - - sm2_point_mul_generator(&P, k); - format_bytes(stderr, 0, 0, "k", k, 32); - sm2_point_print(stdout, 0, 4, "kG", &P); - - hex_to_bytes(yG, strlen(yG), k, &len); - sm2_point_mul_generator(&P, k); - format_bytes(stderr, 0, 0, "k", k, 32); - sm2_point_print(stdout, 0, 4, "kG", &P); - - char *n = "fffffffeffffffffffffffffffffffff7203df6b21c6052b53bbf40939d54123"; - char *n_minus_one = "fffffffeffffffffffffffffffffffff7203df6b21c6052b53bbf40939d54122"; - char *n_plus_one = "fffffffeffffffffffffffffffffffff7203df6b21c6052b53bbf40939d54124"; - char *max256 = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; - - hex_to_bytes(n_minus_one, strlen(n_minus_one), k, &len); - sm2_point_mul_generator(&P, k); - format_bytes(stderr, 0, 0, "n-1", k, 32); - sm2_point_print(stdout, 0, 4, "kG", &P); - - hex_to_bytes(n, strlen(n), k, &len); - sm2_point_mul_generator(&P, k); - format_bytes(stderr, 0, 0, "n", k, 32); - sm2_point_print(stdout, 0, 4, "kG", &P); - - hex_to_bytes(n_plus_one, strlen(n_plus_one), k, &len); - sm2_point_mul_generator(&P, k); - format_bytes(stderr, 0, 0, "n+1", k, 32); - sm2_point_print(stdout, 0, 4, "kG", &P); - - hex_to_bytes(max256, strlen(max256), k, &len); - sm2_point_mul_generator(&P, k); - format_bytes(stderr, 0, 0, "n+1", k, 32); - sm2_point_print(stdout, 0, 4, "kG", &P); - -*/ + if (test_sm2_z256_modp() != 1) goto err; + if (test_sm2_z256_modn() != 1) goto err; if (test_sm2_z256_point_mul_generator() != 1) goto err; printf("%s all tests passed\n", __FILE__); return 0;