diff --git a/include/gmssl/sm2.h b/include/gmssl/sm2.h index a648c95e..c047a3dc 100644 --- a/include/gmssl/sm2.h +++ b/include/gmssl/sm2.h @@ -193,6 +193,8 @@ int sm2_point_from_x(SM2_POINT *P, const uint8_t x[32], int y); int sm2_point_from_xy(SM2_POINT *P, const uint8_t x[32], const uint8_t y[32]); int sm2_point_is_on_curve(const SM2_POINT *P); int sm2_point_add(SM2_POINT *R, const SM2_POINT *P, const SM2_POINT *Q); +int sm2_point_sub(SM2_POINT *R, const SM2_POINT *P, const SM2_POINT *Q); +int sm2_point_neg(SM2_POINT *R, const SM2_POINT *P); int sm2_point_dbl(SM2_POINT *R, const SM2_POINT *P); int sm2_point_mul(SM2_POINT *R, const uint8_t k[32], const SM2_POINT *P); int sm2_point_mul_generator(SM2_POINT *R, const uint8_t k[32]); diff --git a/src/sm2_alg.c b/src/sm2_alg.c index 612744d4..b68832c1 100644 --- a/src/sm2_alg.c +++ b/src/sm2_alg.c @@ -797,19 +797,22 @@ void sm2_jacobian_point_set_xy(SM2_JACOBIAN_POINT *R, const SM2_BN x, const SM2_ void sm2_jacobian_point_get_xy(const SM2_JACOBIAN_POINT *P, SM2_BN x, SM2_BN y) { - SM2_BN z_inv; - if (sm2_bn_is_one(P->Z)) { sm2_bn_copy(x, P->X); - sm2_bn_copy(y, P->Y); + if (y) { + sm2_bn_copy(y, P->Y); + } } else { + SM2_BN z_inv; sm2_fp_inv(z_inv, P->Z); - if (y) + if (y) { sm2_fp_mul(y, P->Y, z_inv); + } sm2_fp_sqr(z_inv, z_inv); sm2_fp_mul(x, P->X, z_inv); - if (y) + if (y) { sm2_fp_mul(y, y, z_inv); + } } } @@ -1147,6 +1150,30 @@ int sm2_point_add(SM2_POINT *R, const SM2_POINT *P, const SM2_POINT *Q) return 1; } +int sm2_point_sub(SM2_POINT *R, const SM2_POINT *P, const SM2_POINT *Q) +{ + SM2_JACOBIAN_POINT P_; + SM2_JACOBIAN_POINT Q_; + + sm2_jacobian_point_from_bytes(&P_, (uint8_t *)P); + sm2_jacobian_point_from_bytes(&Q_, (uint8_t *)Q); + sm2_jacobian_point_sub(&P_, &P_, &Q_); + sm2_jacobian_point_to_bytes(&P_, (uint8_t *)R); + + return 1; +} + +int sm2_point_neg(SM2_POINT *R, const SM2_POINT *P) +{ + SM2_JACOBIAN_POINT P_; + + sm2_jacobian_point_from_bytes(&P_, (uint8_t *)P); + sm2_jacobian_point_neg(&P_, &P_); + sm2_jacobian_point_to_bytes(&P_, (uint8_t *)R); + + return 1; +} + int sm2_point_dbl(SM2_POINT *R, const SM2_POINT *P) { SM2_JACOBIAN_POINT P_; diff --git a/src/sm2_elgamal.c b/src/sm2_elgamal.c index 037e7ed4..a553f751 100644 --- a/src/sm2_elgamal.c +++ b/src/sm2_elgamal.c @@ -12,141 +12,226 @@ #include #include #include +#include +#include #include #include #include -#include "sm2_elgamal.h" -int sm2_elgamal_encrypt(const SM2_KEY *pub_key, sm2_elgamal_plaintext_t in, SM2_ELGAMAL_CIPHERTEXT *out) +#define SM2_PRE_COMPUTE_MAX_OFFSETS 6 + +typedef struct { + uint16_t offset[SM2_PRE_COMPUTE_MAX_OFFSETS]; + uint8_t offset_count; + uint8_t x_coordinate[32]; +} SM2_PRE_COMPUTE; + +// generate baby-step table +int sm2_elgamal_decrypt_pre_compute(SM2_PRE_COMPUTE table[1<<16]) { - SM2_Fn k; - uint8_t k_bytes[32]; - SM2_Fn m; - uint8_t m_bytes[32]; + SM2_JACOBIAN_POINT P; + SM2_BN x; + uint32_t i, j; - do { - sm2_fn_rand(k); // FIXME: sm2_fn_rand() return value! - } while (sm2_bn_is_zero(k)); - sm2_bn_to_bytes(k, k_bytes); + memset(table, 0, sizeof(SM2_PRE_COMPUTE) * (1<<16)); + sm2_jacobian_point_set_infinity(&P); + for (i = 0; i < (1<<16); i++) { + sm2_jacobian_point_add(&P, &P, SM2_G); + sm2_jacobian_point_get_xy(&P, x, NULL); + sm2_bn_to_bytes(x, table[i].x_coordinate); - if (sm2_point_mul_generator(&out->C1, k_bytes) != 1) { - error_print(); - return -1; - } + j = ((uint16_t)table[i].x_coordinate[30] << 8) | table[i].x_coordinate[31]; + assert(table[j].offset_count <= SM2_PRE_COMPUTE_MAX_OFFSETS); - sm2_bn_set_word(m, in); - sm2_bn_to_bytes(m, m_bytes); - - if (sm2_point_mul_sum(&out->C2, k_bytes, &pub_key->public_key, m_bytes) != 1) { - error_print(); - return -1; + table[j].offset[ table[j].offset_count ] = (uint16_t)i; + (table[j].offset_count)++; } return 1; } - -// M = m * G = -[x]C1 + C2 -int sm2_elgamal_decrypt(const SM2_KEY *key, const SM2_ELGAMAL_CIPHERTEXT *in, sm2_elgamal_plaintext_t *out) +static int sm2_pre_compute_get_offset(const SM2_PRE_COMPUTE table[1<<16], const uint8_t x[32], uint16_t *offset) { - SM2_Fn x; - SM2_JACOBIAN_POINT M; - SM2_JACOBIAN_POINT M_; - SM2_JACOBIAN_POINT C1; - SM2_JACOBIAN_POINT C2; - uint8_t bytes[64]; - uint32_t m; + uint32_t i = ((uint16_t)x[30] << 8) | x[31]; + uint16_t j; + uint8_t w; - sm2_bn_from_bytes(x, key->private_key); - sm2_jacobian_point_from_bytes(&C1, (const uint8_t *)&in->C1); - sm2_jacobian_point_from_bytes(&C2, (const uint8_t *)&in->C2); - - sm2_jacobian_point_mul(&C1, x, &C1); - sm2_jacobian_point_neg(&C1, &C1); - sm2_jacobian_point_add(&M, &C1, &C2); - - sm2_jacobian_point_to_bytes(&M, bytes); - - sm2_jacobian_point_init(&M_); - - // TODO: a real algor required - for (m = 1; m < INT_MAX; m++) { - uint8_t point[64]; - - sm2_jacobian_point_add(&M_, &M_, SM2_G); - sm2_jacobian_point_to_bytes(&M_, point); - if (memcmp(point, bytes, 64) == 0) { - *out = m; + for (w = 0; w < table[i].offset_count; w++) { + j = table[i].offset[w]; + if (memcmp(x, table[j].x_coordinate, 32) == 0) { + *offset = j; return 1; } } - - error_print(); - return -1; + return 0; } -int test_sm2_elgamal_encrypt(void) +// run gaint-step +int sm2_elgamal_solve_ecdlp(const SM2_PRE_COMPUTE table[1<<16], const SM2_POINT *point, uint32_t *private) { - SM2_KEY key; - SM2_ELGAMAL_CIPHERTEXT C1; - SM2_ELGAMAL_CIPHERTEXT C2; - sm2_elgamal_plaintext_t m = 1555; + int ret = 0; + SM2_JACOBIAN_POINT P; + SM2_JACOBIAN_POINT Q; + SM2_BN k; + SM2_BN x; + uint8_t x_bytes[32]; + uint8_t Q_bytes[64]; + uint32_t i; + uint16_t j; + sm2_jacobian_point_from_bytes(&P, (uint8_t *)point); - sm2_key_generate(&key); - sm2_elgamal_encrypt(&key, m, &C1); + // Q = -[2^16]G + sm2_bn_set_word(k, 65536); + sm2_jacobian_point_mul_generator(&Q, k); + sm2_jacobian_point_neg(&Q, &Q); - m = 0; - sm2_elgamal_decrypt(&key, &C1, &m); + // Q to Affine + sm2_jacobian_point_to_bytes(&Q, Q_bytes); + sm2_jacobian_point_from_bytes(&Q, Q_bytes); - printf("m = %u\n", m); + for (i = 0; i < (1<<16); i++) { + // P - i*(kG) == O ==> d = i*k + if (sm2_jacobian_point_is_at_infinity(&P)) { + *private = (i << 16); + ret = 1; + goto ok; + } - return 1; + sm2_jacobian_point_get_xy(&P, x, NULL); + sm2_bn_to_bytes(x, x_bytes); + if (sm2_pre_compute_get_offset(table, x_bytes, &j) == 1) { + // P - i*(kG) == j*G ==> d = j + i*k + *private = (i<<16) + j + 1; // table[0] is 1*G, so j + 1 + ret = 1; + goto ok; + } + sm2_jacobian_point_add(&P, &P, &Q); + } + printf("gaint steps failed\n"); +ok: + i = j = 0; + gmssl_secure_clear(x, sizeof(x)); + return ret; } +typedef struct { + SM2_POINT C1; + SM2_POINT C2; +} SM2_ELGAMAL_CIPHERTEXT; -// ([k1]G, [m1]G + [k1]P) + ([k2]G, [m2]G + [k2]P) => -// ([k1]G + [k2]G + [r]G, [m1]G + [m2]G + [k1]P + [k2]P + [r]P) +int sm2_elgamal_do_encrypt(const SM2_KEY *pub_key, uint32_t in, SM2_ELGAMAL_CIPHERTEXT *out) +{ + int ret = -1; + SM2_Fn k; + SM2_Fn m; + uint8_t k_bytes[32]; + uint8_t m_bytes[32]; + if (!pub_key || !out) { + error_print(); + return -1; + } + + do { + if (sm2_fn_rand(k) != 1) { + error_print(); + return -1; + } + } while (sm2_bn_is_zero(k)); + sm2_bn_to_bytes(k, k_bytes); + + // C1 = k * G + if (sm2_point_mul_generator(&out->C1, k_bytes) != 1) { + error_print(); + goto end; + } + + // C2 = k * P + m * G + sm2_bn_set_word(m, in); + sm2_bn_to_bytes(m, m_bytes); + if (sm2_point_mul_sum(&out->C2, k_bytes, &pub_key->public_key, m_bytes) != 1) { + error_print(); + goto end; + } + ret = 1; + +end: + gmssl_secure_clear(k, sizeof(k)); + gmssl_secure_clear(m, sizeof(m)); + gmssl_secure_clear(k_bytes, sizeof(k_bytes)); + gmssl_secure_clear(m_bytes, sizeof(m_bytes)); + return ret; +} + +// M = m*G = -x*C1 + C2 +int sm2_elgamal_do_decrypt(const SM2_KEY *key, const SM2_ELGAMAL_CIPHERTEXT *in, uint32_t *out) +{ + static SM2_PRE_COMPUTE *table = NULL; + SM2_POINT M; + + if (!key || !in || !out) { + error_print(); + return -1; + } + + sm2_point_mul(&M, key->private_key, &in->C1); + sm2_point_sub(&M, &in->C2, &M); + + if (!table) { + if (!(table = malloc(sizeof(SM2_PRE_COMPUTE) * (1<<16)))) { + error_print(); + return -1; + } + sm2_elgamal_decrypt_pre_compute(table); + } + + if (sm2_elgamal_solve_ecdlp(table, &M, out) != 1) { + error_print(); + return -1; + } + return 1; +} + +// (A1, A2) = (k1*G, m1*G + k1*P) +// (B1, B2) = (k2*G, m2*G + k2*P) +// (R1, R2) = (A1 + B1 + k*G, A2 + B2 + k*P) int sm2_elgamal_ciphertext_add(SM2_ELGAMAL_CIPHERTEXT *r, const SM2_ELGAMAL_CIPHERTEXT *a, const SM2_ELGAMAL_CIPHERTEXT *b, const SM2_KEY *pub_key) { SM2_Fn k; - SM2_JACOBIAN_POINT A1; - SM2_JACOBIAN_POINT A2; - SM2_JACOBIAN_POINT B1; - SM2_JACOBIAN_POINT B2; - SM2_JACOBIAN_POINT R1; - SM2_JACOBIAN_POINT R2; + uint8_t k_bytes[32]; + SM2_POINT R; - sm2_jacobian_point_from_bytes(&A1, (uint8_t *)&a->C1); - sm2_jacobian_point_from_bytes(&A2, (uint8_t *)&a->C2); - sm2_jacobian_point_from_bytes(&B1, (uint8_t *)&b->C1); - sm2_jacobian_point_from_bytes(&B2, (uint8_t *)&b->C2); - - sm2_jacobian_point_add(&A1, &A1, &B1); - sm2_jacobian_point_add(&A2, &A2, &B2); + if (!r || !a || !b || !pub_key) { + error_print(); + return -1; + } do { - sm2_fn_rand(k); + if (sm2_fn_rand(k) != 1) { + error_print(); + return -1; + } } while (sm2_bn_is_zero(k)); + sm2_bn_to_bytes(k, k_bytes); - sm2_jacobian_point_mul_generator(&R1, k); - sm2_jacobian_point_add(&A1, &A1, &R1); + // R1 = A1 + B1 + k*G + sm2_point_add(&r->C1, &a->C1, &b->C1); + sm2_point_mul_generator(&R, k_bytes); + sm2_point_add(&r->C1, &r->C1, &R); + // R2 = A2 + B2 + k*P + sm2_point_add(&r->C2, &a->C2, &b->C2); + sm2_point_mul(&R, k_bytes, &pub_key->public_key); + sm2_point_add(&r->C2, &r->C2, &R); - sm2_jacobian_point_from_bytes(&R2, (const uint8_t *)&pub_key->public_key); - sm2_jacobian_point_mul(&R2, k, &R2); - sm2_jacobian_point_add(&A2, &A2, &R2); - - - sm2_jacobian_point_to_bytes(&A1, (uint8_t *)&r->C1); - sm2_jacobian_point_to_bytes(&A2, (uint8_t *)&r->C2); - + gmssl_secure_clear(k, sizeof(k)); + gmssl_secure_clear(k_bytes, sizeof(k_bytes)); return 1; } @@ -154,41 +239,103 @@ int sm2_elgamal_cipehrtext_sub(SM2_ELGAMAL_CIPHERTEXT *r, const SM2_ELGAMAL_CIPHERTEXT *a, const SM2_ELGAMAL_CIPHERTEXT *b, const SM2_KEY *pub_key) { - error_print(); - return -1; -} + SM2_Fn k; + uint8_t k_bytes[32]; + SM2_POINT R; -int sm2_elgamal_cipehrtext_neg(SM2_ELGAMAL_CIPHERTEXT *r, const SM2_ELGAMAL_CIPHERTEXT *a, const SM2_KEY *pub_key) -{ - error_print(); - return -1; -} - -// s * (C1, C2) := ([s]C1 + [r]G, [s]C2 + [r]P) -int sm2_elgamal_ciphertext_scalar_mul(SM2_ELGAMAL_CIPHERTEXT *r, const uint8_t scalar[32], const SM2_ELGAMAL_CIPHERTEXT *a, const SM2_KEY *pub_key) -{ - SM2_BN r; - uint8_t r_bytes[32]; - - SM2_BN s; - SM2_JACOBIAN_POINT C; - SM2_JACOBIAN_POINT P; + if (!r || !a || !b || !pub_key) { + error_print(); + return -1; + } do { - sm2_fn_rand(r); // FIXME: return value - } while (sm2_bn_is_zero(r)); - sm2_bn_to_bytes(r, r_bytes); + if (sm2_fn_rand(k) != 1) { + error_print(); + return -1; + } + } while (sm2_bn_is_zero(k)); + sm2_bn_to_bytes(k, k_bytes); - sm2_point_mul_sum(&r->C1, scalar, &a->C1, r_bytes); + // R1 = A1 - B1 + k*G + sm2_point_sub(&r->C1, &a->C1, &b->C1); + sm2_point_mul_generator(&R, k_bytes); + sm2_point_add(&r->C1, &a->C1, &R); - sm2_bn_from_bytes(s, scalar); - sm2_jacobian_point_from_bytes(&C, &a->C2); - sm2_jacobian_point_from_bytes(&P, &pub_key->public_key); - sm2_jacobian_point_mul(&C, s, &C); - sm2_jacobian_point_mul(&P, r, &P); - sm2_jacobian_point_add(&C, &C, &P); - sm2_jacobian_point_to_bytes(&C, (uint8_t *)&r->C2); + // R2 = A2 - B2 + k*P + sm2_point_sub(&r->C2, &a->C2, &b->C2); + sm2_point_mul(&R, k_bytes, &pub_key->public_key); + sm2_point_add(&r->C2, &r->C2, &R); + gmssl_secure_clear(k, sizeof(k)); + gmssl_secure_clear(k_bytes, sizeof(k_bytes)); + return 1; +} + +int sm2_elgamal_cipehrtext_neg(SM2_ELGAMAL_CIPHERTEXT *r, + const SM2_ELGAMAL_CIPHERTEXT *a, const SM2_KEY *pub_key) +{ + SM2_Fn k; + uint8_t k_bytes[32]; + SM2_POINT R; + + if (!r || !a || !pub_key) { + error_print(); + return -1; + } + + do { + if (sm2_fn_rand(k) != 1) { + error_print(); + return -1; + } + } while (sm2_bn_is_zero(k)); + sm2_bn_to_bytes(k, k_bytes); + + // R1 = -A1 + k*G = -r*G + k*G + sm2_point_mul_generator(&R, k_bytes); + sm2_point_sub(&r->C1, &R, &a->C1); + + // R2 = -A2 + k*P = -m*G -r*P + k*P + sm2_point_mul(&R, k_bytes, &pub_key->public_key); + sm2_point_sub(&r->C2, &R, &a->C2); + + gmssl_secure_clear(k, sizeof(k)); + gmssl_secure_clear(k_bytes, sizeof(k_bytes)); + return 1; +} + +// s * (C1, C2) := (s*C1 + r*G, s*C2 + r*P) +int sm2_elgamal_ciphertext_scalar_mul(SM2_ELGAMAL_CIPHERTEXT *R, + const uint8_t scalar[32], const SM2_ELGAMAL_CIPHERTEXT *A, + const SM2_KEY *pub_key) +{ + SM2_Fn k; + uint8_t k_bytes[32]; + SM2_POINT kP; + + if (!R || !scalar || !A || !pub_key) { + error_print(); + return -1; + } + + do { + if (sm2_fn_rand(k) != 1) { + error_print(); + return -1; + } + } while (sm2_bn_is_zero(k)); + sm2_bn_to_bytes(k, k_bytes); + + // R1 = s*C1 + k*G + sm2_point_mul_sum(&R->C1, scalar, &A->C1, k_bytes); + + // R2 = s*C2 + r*P + sm2_point_mul(&kP, k_bytes, &pub_key->public_key); + sm2_point_mul(&R->C2, scalar, &A->C2); + sm2_point_add(&R->C2, &R->C2, &kP); + + gmssl_secure_clear(k, sizeof(k)); + gmssl_secure_clear(k_bytes, sizeof(k_bytes)); return 1; } @@ -241,13 +388,45 @@ int sm2_elgamal_ciphertext_from_der(SM2_ELGAMAL_CIPHERTEXT *c, const uint8_t **i return 1; } -#if 0 -int main(void) +int sm2_elgamal_encrypt(const SM2_KEY *pub_key, uint32_t in, uint8_t *out, size_t *outlen) { + SM2_ELGAMAL_CIPHERTEXT C; - test_sm2_elgamal_encrypt(); - - return 0; + if (sm2_elgamal_do_encrypt(pub_key, in, &C) != 1) { + error_print(); + return -1; + } + *outlen = 0; + if (sm2_elgamal_ciphertext_to_der(&C, &out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int sm2_elgamal_decrypt(SM2_KEY *key, const uint8_t *in, size_t inlen, uint32_t *out) +{ + SM2_ELGAMAL_CIPHERTEXT C; + + if (sm2_elgamal_ciphertext_from_der(&C, &in, &inlen) != 1 + || asn1_length_is_zero(inlen) != 1) { + error_print(); + return -1; + } + if (sm2_elgamal_do_decrypt(key, &C, out) != 1) { + error_print(); + return -1; + } + return 1; +} + +int test_sm2_elgamal_do_encrypt(void) +{ + return -1; +} + +int test_sm2_elgamal_encrypt(void) +{ + return -1; } -#endif