Add ECDSA with curve P-256

for TLS testing
This commit is contained in:
Zhi Guan
2026-01-24 12:27:12 +08:00
parent 05ba2f8e54
commit a15e0f34c7
20 changed files with 3663 additions and 31 deletions

View File

@@ -54,6 +54,8 @@ option(ENABLE_SM4_CBC_MAC "Enable SM4-CBC-MAC" ON)
option(ENABLE_SM2_EXTS "Enable SM2 Extensions" OFF)
option(ENABLE_SECP256R1 "Enable ECDH/ECDSA on curve secp256r1" ON)
option(ENABLE_LMS "Enable LMS/HSS signature" ON)
option(ENABLE_XMSS "Enable XMSS/XMSS^MT signature" ON)
option(ENABLE_SPHINCS "Enable SPHINCS+ signature" ON)
@@ -108,6 +110,7 @@ set(src
src/sm4_cbc_sm3_hmac.c
src/sm4_ctr_sm3_hmac.c
src/pkcs8.c
src/bn.c
src/ec.c
src/rsa.c
src/asn1.c
@@ -128,6 +131,7 @@ set(src
src/tls_trace.c
src/tlcp.c
src/tls12.c
src/tls12_handshake.c
src/tls13.c
src/file.c
src/file.c
@@ -203,6 +207,7 @@ set(tests
gf128
ghash
pkcs8
bn
ec
asn1
hex
@@ -419,6 +424,14 @@ if (ENABLE_SM2_EXTS)
endif()
if (ENABLE_SECP256R1)
message(STATUS "ENABLE_SECP256R1 is ON")
add_definitions(-DENABLE_SECP256R1)
list(APPEND src src/secp256r1.c src/secp256r1_key.c src/ecdsa.c)
list(APPEND tests secp256r1 secp256r1_key ecdsa)
endif()
if (ENABLE_LMS)
message(STATUS "ENABLE_LMS is ON")
add_definitions(-DENABLE_LMS)

86
include/gmssl/bn.h Normal file
View File

@@ -0,0 +1,86 @@
/*
* Copyright 2014-2026 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
*/
#ifndef GMSSL_BN_H
#define GMSSL_BN_H
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
void bn_set_word(uint32_t *r, uint32_t a, size_t k);
void bn_copy(uint32_t *r, const uint32_t *a, size_t k);
int bn_cmp(const uint32_t *a, const uint32_t *b, size_t k);
int bn_is_zero(const uint32_t *a, size_t k);
int bn_is_one(const uint32_t *a, size_t k);
int bn_add(uint32_t *r, const uint32_t *a, const uint32_t *b, size_t k);
int bn_sub(uint32_t *r, const uint32_t *a, const uint32_t *b, size_t k);
void bn_mul(uint32_t *r, const uint32_t *a, const uint32_t *b, size_t k);
void bn_mul_lo(uint32_t *r, const uint32_t *a, const uint32_t *b, size_t k);
void bn_to_bytes(const uint32_t *a, size_t k, uint8_t *out);
void bn_from_bytes(uint32_t *a, size_t k, const uint8_t *in);
int bn_print(FILE *fp, int fmt, int ind, const char *label, const uint32_t *a, size_t k);
void bn_mod_add(uint32_t *r, const uint32_t *a, const uint32_t *b, const uint32_t *p, size_t k);
void bn_mod_sub(uint32_t *r, const uint32_t *a, const uint32_t *b, const uint32_t *p, size_t k);
void bn_mod_neg(uint32_t *r, const uint32_t *a, const uint32_t *p, size_t k);
// multiplication with barrett reduction, need caller prepare temp values
// u = floor(2^512 / p) for bn256
void bn_barrett_mod_mul(uint32_t *r, const uint32_t *a, const uint32_t *b, const uint32_t *p,
const uint32_t *u, // uint32_t u[k + 1]
uint32_t *tmp, // uint32_t tmp[6*k + 4]
size_t k);
void bn_barrett_mod_sqr(uint32_t *r, const uint32_t *a, const uint32_t *p,
const uint32_t *u, // uint32_t u[k + 1]
uint32_t *tmp, // uint32_t tmp[6*k + 4]
size_t k);
void bn_barrett_mod_exp(uint32_t *r, const uint32_t *a, const uint32_t *e, const uint32_t *p,
const uint32_t *u, // uint32_t u[k + 1]
uint32_t *tmp, // uint32_t tmp[7*k + 4]
size_t k);
void bn_barrett_mod_inv(uint32_t *r, const uint32_t *a, const uint32_t *p,
const uint32_t *u, // uint32_t u[k + 1]
uint32_t *tmp, // uint32_t tmp[8*k + 4]
size_t k);
// montgomery multiplication, all values in montgomery format, need caller prepare temp values
void bn_mont_mod_mul(uint32_t *r, const uint32_t *a, const uint32_t *b, const uint32_t *p, const uint32_t *p_inv_neg,
uint32_t *tmp, // uint32_t tmp[5 * k]
size_t k);
void bn_mont_mod_sqr(uint32_t *r, const uint32_t *a, const uint32_t *p, const uint32_t *p_inv_neg,
uint32_t *tmp, // uint32_t tmp[5 * k]
size_t k);
void bn_mont_mod_exp(uint32_t *r, const uint32_t *a, const uint32_t *e, const uint32_t *p, const uint32_t *p_inv_neg,
uint32_t *tmp, // uint32_t tmp[6 * k]
size_t k);
void bn_mont_mod_inv(uint32_t *r, const uint32_t *a, const uint32_t *p, const uint32_t *p_inv_neg,
uint32_t *tmp, // uint32_t tmp[7 * k]
size_t k);
void bn_mont_set(uint32_t *r, const uint32_t *a, const uint32_t *one_sqr, const uint32_t *p, const uint32_t *p_inv_neg,
uint32_t *tmp, // uint32_t tmp[5 * k]
size_t k);
void bn_mont_get(uint32_t *r, const uint32_t *a, const uint32_t *p, const uint32_t *p_inv_neg,
uint32_t *tmp, // uint32_t tmp[5 * k]
size_t k);
#ifdef __cplusplus
}
#endif
#endif

68
include/gmssl/ecdsa.h Normal file
View File

@@ -0,0 +1,68 @@
/*
* Copyright 2014-2026 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
*/
#ifndef GMSSL_ECDSA_H
#define GMSSL_ECDSA_H
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <gmssl/sha2.h>
#include <gmssl/secp256r1_key.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
secp256r1_t r;
secp256r1_t s;
} ECDSA_SIGNATURE;
#define ECDSA_SIGNATURE_COMPACT_SIZE 70
#define ECDSA_SIGNATURE_TYPICAL_SIZE 71
#define ECDSA_SIGNATURE_MAX_SIZE 72
int ecdsa_signature_to_der(const ECDSA_SIGNATURE *sig, uint8_t **out, size_t *outlen);
int ecdsa_signature_from_der(ECDSA_SIGNATURE *sig, const uint8_t **in, size_t *inlen);
int ecdsa_signature_print_ex(FILE *fp, int fmt, int ind, const char *label, const ECDSA_SIGNATURE *sig);
int ecdsa_signature_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *sig, size_t siglen);
int ecdsa_do_sign_ex(const SECP256R1_KEY *key, const secp256r1_t k, const uint8_t dgst[32], ECDSA_SIGNATURE *sig);
int ecdsa_do_sign(const SECP256R1_KEY *key, const uint8_t dgst[32], ECDSA_SIGNATURE *sig);
int ecdsa_do_verify(const SECP256R1_KEY *key, const uint8_t dgst[32], const ECDSA_SIGNATURE *sig);
int ecdsa_sign(const SECP256R1_KEY *key, const uint8_t dgst[32], uint8_t *sig, size_t *siglen);
int ecdsa_sign_fixlen(const SECP256R1_KEY *key, const uint8_t dgst[32], size_t siglen, uint8_t *sig);
int ecdsa_verify(const SECP256R1_KEY *key, const uint8_t dgst[32], const uint8_t *sig, size_t siglen);
typedef struct {
SHA256_CTX sha256_ctx;
SECP256R1_KEY key;
ECDSA_SIGNATURE sig;
} ECDSA_SIGN_CTX;
int ecdsa_sign_init(ECDSA_SIGN_CTX *ctx, const SECP256R1_KEY *key);
int ecdsa_sign_update(ECDSA_SIGN_CTX *ctx, const uint8_t *data, size_t datalen);
int ecdsa_sign_finish(ECDSA_SIGN_CTX *ctx, uint8_t *sig, size_t *siglen);
int ecdsa_sign_finish_fixlen(ECDSA_SIGN_CTX *ctx, size_t siglen, uint8_t *sig);
int ecdsa_verify_init(ECDSA_SIGN_CTX *ctx, const SECP256R1_KEY *key, const uint8_t *sig, size_t siglen);
int ecdsa_verify_update(ECDSA_SIGN_CTX *ctx, const uint8_t *data, size_t datalen);
int ecdsa_verify_finish(ECDSA_SIGN_CTX *ctx);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -210,6 +210,7 @@ enum {
#define OID_secp256r1 OID_prime256v1
#define oid_cnt(nodes) (sizeof(nodes)/sizeof((nodes)[0]))

108
include/gmssl/secp256r1.h Normal file
View File

@@ -0,0 +1,108 @@
/*
* Copyright 2014-2026 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
*/
#ifndef GMSSL_SECP256R1_H
#define GMSSL_SECP256R1_H
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
// p = 2^256 - 2^224 + 2^192 + 2^96 - 1
// = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF
// a = -3
// b = 0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b
// x = 0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296
// y = 0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5
// n = 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551
// h = 1
typedef uint32_t secp256r1_t[8];
#define SECP256R1_K (sizeof(secp256r1_t)/sizeof(uint32_t))
extern const secp256r1_t SECP256R1_P;
extern const secp256r1_t SECP256R1_B;
extern const secp256r1_t SECP256R1_N;
extern const uint32_t SECP256R1_U_P[9];
extern const uint32_t SECP256R1_U_N[9];
int secp256r1_is_zero(const secp256r1_t a);
int secp256r1_is_one(const secp256r1_t a);
int secp256r1_cmp(const secp256r1_t a, const secp256r1_t b);
void secp256r1_set_zero(secp256r1_t r);
void secp256r1_set_one(secp256r1_t r);
void secp256r1_copy(secp256r1_t r, const secp256r1_t a);
void secp256r1_to_32bytes(const secp256r1_t a, uint8_t out[32]);
void secp256r1_from_32bytes(secp256r1_t r, const uint8_t in[32]);
int secp256r1_print(FILE *fp, int fmt, int ind, const char *label, const secp256r1_t a);
void secp256r1_modp_add(secp256r1_t r, const secp256r1_t a, const secp256r1_t b);
void secp256r1_modp_dbl(secp256r1_t r, const secp256r1_t a);
void secp256r1_modp_tri(secp256r1_t r, const secp256r1_t a);
void secp256r1_modp_sub(secp256r1_t r, const secp256r1_t a, const secp256r1_t b);
void secp256r1_modp_neg(secp256r1_t r, const secp256r1_t a);
void secp256r1_modp_haf(secp256r1_t r, const secp256r1_t a);
void secp256r1_modp_mul(secp256r1_t r, const secp256r1_t a, const secp256r1_t b);
void secp256r1_modp_sqr(secp256r1_t r, const secp256r1_t a);
void secp256r1_modp_exp(secp256r1_t r, const secp256r1_t a, const secp256r1_t e);
void secp256r1_modp_inv(secp256r1_t r, const secp256r1_t a);
void secp256r1_modn(secp256r1_t r, const secp256r1_t a);
void secp256r1_modn_add(secp256r1_t r, const secp256r1_t a, const secp256r1_t b);
void secp256r1_modn_dbl(secp256r1_t r, const secp256r1_t a);
void secp256r1_modn_tri(secp256r1_t r, const secp256r1_t a);
void secp256r1_modn_sub(secp256r1_t r, const secp256r1_t a, const secp256r1_t b);
void secp256r1_modn_neg(secp256r1_t r, const secp256r1_t a);
void secp256r1_modn_mul(secp256r1_t r, const secp256r1_t a, const secp256r1_t b);
void secp256r1_modn_sqr(secp256r1_t r, const secp256r1_t a);
void secp256r1_modn_exp(secp256r1_t r, const secp256r1_t a, const secp256r1_t e);
void secp256r1_modn_inv(secp256r1_t r, const secp256r1_t a);
typedef struct {
secp256r1_t X;
secp256r1_t Y;
secp256r1_t Z;
} SECP256R1_POINT;
extern const SECP256R1_POINT SECP256R1_POINT_G;
void secp256r1_point_set_infinity(SECP256R1_POINT *R);
int secp256r1_point_is_at_infinity(const SECP256R1_POINT *P);
int secp256r1_point_is_on_curve(const SECP256R1_POINT *P);
int secp256r1_point_equ(const SECP256R1_POINT *P, const SECP256R1_POINT *Q);
int secp256r1_point_set_xy(SECP256R1_POINT *R, const secp256r1_t x, const secp256r1_t y);
int secp256r1_point_get_xy(const SECP256R1_POINT *P, secp256r1_t x, secp256r1_t y);
void secp256r1_point_copy(SECP256R1_POINT *R, const SECP256R1_POINT *P);
void secp256r1_point_dbl(SECP256R1_POINT *R, const SECP256R1_POINT *P);
void secp256r1_point_add(SECP256R1_POINT *R, const SECP256R1_POINT *P, const SECP256R1_POINT *Q);
void secp256r1_point_neg(SECP256R1_POINT *R, const SECP256R1_POINT *P);
void secp256r1_point_sub(SECP256R1_POINT *R, const SECP256R1_POINT *P, const SECP256R1_POINT *Q);
void secp256r1_point_mul(SECP256R1_POINT *R, const secp256r1_t k, const SECP256R1_POINT *P);
void secp256r1_point_mul_generator(SECP256R1_POINT *R, const secp256r1_t k);
int secp256r1_point_print(FILE *fp, int fmt, int ind, const char *label, const SECP256R1_POINT *P);
int secp256r1_point_to_uncompressed_octets(const SECP256R1_POINT *P, uint8_t octets[65]);
int secp256r1_point_from_uncompressed_octets(SECP256R1_POINT *P, const uint8_t octets[65]);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,56 @@
/*
* Copyright 2014-2026 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
*/
#ifndef GMSSL_SECP256R1_KEY_H
#define GMSSL_SECP256R1_KEY_H
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <gmssl/secp256r1.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
SECP256R1_POINT public_key;
secp256r1_t private_key;
} SECP256R1_KEY;
int secp256r1_key_generate(SECP256R1_KEY *key);
int secp256r1_key_set_private_key(SECP256R1_KEY *key, const secp256r1_t private_key);
int secp256r1_public_key_equ(const SECP256R1_KEY *key, const SECP256R1_KEY *pub);
void secp256r1_key_cleanup(SECP256R1_KEY *key);
int secp256r1_public_key_print(FILE *fp, int fmt, int ind, const char *label, const SECP256R1_KEY *key);
int secp256r1_private_key_print(FILE *fp, int fmt, int ind, const char *label, const SECP256R1_KEY *key);
int secp256r1_public_key_to_bytes(const SECP256R1_KEY *key, uint8_t **out, size_t *outlen);
int secp256r1_public_key_from_bytes(SECP256R1_KEY *key, const uint8_t **in, size_t *inlen);
int secp256r1_public_key_to_der(const SECP256R1_KEY *key, uint8_t **out, size_t *outlen);
int secp256r1_public_key_from_der(SECP256R1_KEY *key, const uint8_t **in, size_t *inlen);
int secp256r1_private_key_to_der(const SECP256R1_KEY *key, uint8_t **out, size_t *outlen);
int secp256r1_private_key_from_der(SECP256R1_KEY *key, const uint8_t **in, size_t *inlen);
int secp256r1_private_key_info_to_der(const SECP256R1_KEY *key, uint8_t **out, size_t *outlen);
int secp256r1_private_key_info_from_der(SECP256R1_KEY *key, const uint8_t **attrs, size_t *attrslen,
const uint8_t **in, size_t *inlen);
int secp256r1_private_key_info_encrypt_to_der(const SECP256R1_KEY *ec_key, const char *pass,
uint8_t **out, size_t *outlen);
int secp256r1_private_key_info_decrypt_from_der(SECP256R1_KEY *ec_key,
const uint8_t **attrs, size_t *attrs_len,
const char *pass, const uint8_t **in, size_t *inlen);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -752,6 +752,11 @@ typedef struct {
BLOCK_CIPHER_KEY server_write_key;
int quiet;
// handshake state for state machine
int state;
SM3_CTX sm3_ctx;
SM2_SIGN_CTX sign_ctx;
} TLS_CONNECT;

View File

@@ -19,6 +19,8 @@
#include <gmssl/oid.h>
#include <gmssl/asn1.h>
#include <gmssl/sm2.h>
#include <gmssl/secp256r1_key.h>
#include <gmssl/ecdsa.h>
#include <gmssl/lms.h>
#include <gmssl/xmss.h>
#include <gmssl/sphincs.h>
@@ -51,11 +53,13 @@ typedef struct {
XMSS_KEY xmss_key;
XMSSMT_KEY xmssmt_key;
SPHINCS_KEY sphincs_key;
SECP256R1_KEY secp256r1_key;
} u;
} X509_KEY;
int x509_key_set_sm2_key(X509_KEY *x509_key, const SM2_KEY *sm2_key);
int x509_key_set_secp256r1_key(X509_KEY *x509_key, const SECP256R1_KEY *secp256r1_key);
int x509_key_set_lms_key(X509_KEY *x509_key, const LMS_KEY *lms_key);
int x509_key_set_hss_key(X509_KEY *x509_key, const HSS_KEY *hss_key);
int x509_key_set_xmss_key(X509_KEY *x509_key, const XMSS_KEY *xmss_key);
@@ -107,6 +111,7 @@ typedef union {
typedef struct {
union {
SM2_SIGN_CTX sm2_sign_ctx;
ECDSA_SIGN_CTX ecdsa_sign_ctx;
SM2_VERIFY_CTX sm2_verify_ctx;
HSS_SIGN_CTX hss_sign_ctx;
XMSS_SIGN_CTX xmss_sign_ctx;

379
src/bn.c Normal file
View File

@@ -0,0 +1,379 @@
/*
* Copyright 2014-2026 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <gmssl/endian.h>
void bn_set_word(uint32_t *r, uint32_t a, size_t k)
{
r[0] = a;
while (k-- > 1) {
r[k] = 0;
}
}
void bn_copy(uint32_t *r, const uint32_t *a, size_t k)
{
while (k-- > 0) {
r[k] = a[k];
}
}
int bn_cmp(const uint32_t *a, const uint32_t *b, size_t k)
{
while (k-- > 0) {
if (a[k] > b[k]) return 1;
else if (a[k] < b[k]) return -1;
}
return 0;
}
int bn_is_zero(const uint32_t *a, size_t k)
{
while (k-- > 0) {
if (a[k]) {
return 0;
}
}
return 1;
}
int bn_is_one(const uint32_t *a, size_t k)
{
if (a[0] != 1) {
return 0;
}
while (k-- > 1) {
if (a[k]) {
return 0;
}
}
return 1;
}
int bn_add(uint32_t *r, const uint32_t *a, const uint32_t *b, size_t k)
{
uint64_t w = 0;
size_t i;
for (i = 0; i < k; i++) {
w += (uint64_t)a[i] + (uint64_t)b[i];
r[i] = w & 0xffffffff;
w >>= 32;
}
return (int)w;
}
int bn_sub(uint32_t *r, const uint32_t *a, const uint32_t *b, size_t k)
{
int64_t w = 0;
size_t i;
for (i = 0; i < k; i++) {
w += (int64_t)a[i] - (int64_t)b[i];
r[i] = w & 0xffffffff;
w >>= 32;
}
return (int)w;
}
void bn_mul(uint32_t *r, const uint32_t *a, const uint32_t *b, size_t k)
{
uint64_t w;
size_t i, j;
for (i = 0; i < k; i++) {
r[i] = 0;
}
for (i = 0; i < k; i++) {
w = 0;
for (j = 0; j < k; j++) {
w += (uint64_t)r[i + j] + (uint64_t)a[i] * (uint64_t)b[j];
r[i + j] = w & 0xffffffff;
w >>= 32;
}
r[i + k] = w;
}
}
void bn_mul_lo(uint32_t *r, const uint32_t *a, const uint32_t *b, size_t k)
{
uint64_t w;
size_t i, j;
for (i = 0; i < k; i++) {
r[i] = 0;
}
for (i = 0; i < k; i++) {
w = 0;
for (j = 0; j < k - i; j++) {
w += (uint64_t)r[i + j] + (uint64_t)a[i] * (uint64_t)b[j];
r[i + j] = w & 0xffffffff;
w >>= 32;
}
}
}
void bn_to_bytes(const uint32_t *a, size_t k, uint8_t *out)
{
while (k-- > 0) {
PUTU32(out, a[k]);
out += 4;
}
}
void bn_from_bytes(uint32_t *a, size_t k, const uint8_t *in)
{
while (k-- > 0) {
a[k] = GETU32(in);
in += 4;
}
}
int bn_print(FILE *fp, int fmt, int ind, const char *label, const uint32_t *a, size_t k)
{
fprintf(fp, "%s: ", label);
int i;
for (i = 0; i < k; i++) {
fprintf(fp, "0x%08x, ", a[i]);
}
fprintf(fp, "\n");
while (k-- > 0) {
fprintf(fp, "%08x", a[k]);
}
fprintf(fp, "\n");
return 1;
}
void bn_mod_add(uint32_t *r, const uint32_t *a, const uint32_t *b, const uint32_t *p, size_t k)
{
int carry;
carry = bn_add(r, a, b, k);
if (carry) {
bn_sub(r, r, p, k);
} else if (bn_cmp(r, p, k) >= 0) {
bn_sub(r, r, p, k);
}
}
void bn_mod_sub(uint32_t *r, const uint32_t *a, const uint32_t *b, const uint32_t *p, size_t k)
{
if (bn_cmp(a, b, k) >= 0) {
bn_sub(r, a, b, k);
} else {
bn_sub(r, b, a, k);
bn_sub(r, p, r, k);
}
}
void bn_mod_neg(uint32_t *r, const uint32_t *a, const uint32_t *p, size_t k)
{
bn_sub(r, p, a, k);
}
void bn_barrett_mod_mul(uint32_t *r, // uint32_t r[k] = a * b mod p
const uint32_t *a, // uint32_t a[k]
const uint32_t *b, // uint32_t b[k]
const uint32_t *p, // uint32_t p[k]
const uint32_t *u, // uint32_t u[k + 1] = floor((2^32)^(2*k) / p)
uint32_t *tmp, // uint32_t tmp[6*k + 4]
size_t k)
{
uint32_t *p_; // uint32_t p_[k + 1];
uint32_t *z; // uint32_t z[2 * k];
uint32_t *q; // uint32_t q[2 * (k + 1)];
uint32_t *t_; // uint32_t t_[k + 1];
size_t i;
p_ = tmp; tmp += k + 1;
z = tmp; tmp += 2 * k;
q = tmp; tmp += 2 * (k + 1);
t_ = tmp; tmp += k + 1;
for (i = 0; i < k; i++) {
p_[i] = p[i];
}
p_[k] = 0;
bn_mul(z, a, b, k);
bn_mul(q, z + k - 1, u, k + 1);
bn_mul_lo(t_, q + k + 1, p_, k + 1);
bn_sub(t_, z, t_, k + 1);
// reduce at most twice
if (bn_cmp(t_, p_, k + 1) >= 0) {
bn_sub(t_, t_, p_, k + 1);
}
if (bn_cmp(t_, p_, k) >= 0) {
bn_sub(t_, t_, p_, k);
}
bn_copy(r, t_, k);
}
void bn_barrett_mod_sqr(uint32_t *r, const uint32_t *a, const uint32_t *p,
const uint32_t *u, // uint32_t u[k + 1]
uint32_t *tmp, // uint32_t tmp[6*k + 4]
size_t k)
{
bn_barrett_mod_mul(r, a, a, p, u, tmp, k);
}
void bn_barrett_mod_exp(uint32_t *r, const uint32_t *a, const uint32_t *e, const uint32_t *p,
const uint32_t *u, //
uint32_t *tmp, // uint32_t tmp[7*k + 4]
size_t k)
{
uint32_t *t; // uint32_t t[k];
uint32_t w;
int i, j;
// t = 1
t = tmp; tmp += k;
bn_set_word(t, 1, k);
for (i = k - 1; i >= 0; i--) {
w = e[i];
for (j = 0; j < 32; j++) {
bn_barrett_mod_sqr(t, t, p, u, tmp, k);
if (w & 0x80000000) {
bn_barrett_mod_mul(t, t, a, p, u, tmp, k);
}
w <<= 1;
}
}
bn_copy(r, t, k);
}
// FIXME: 如果 a = 0 (mod p) 会发生什么
void bn_barrett_mod_inv(uint32_t *r, const uint32_t *a, const uint32_t *p, const uint32_t *u,
uint32_t *tmp, // uint32_t tmp[8*k + 4]
size_t k)
{
uint32_t *e; // uint32_t e[k];
// e = p - 2
e = tmp; tmp += k;
bn_set_word(e, 2, k);
bn_sub(e, p, e, k);
// a^-1 = a^(p - 2) (mod p)
bn_barrett_mod_exp(r, a, e, p, u, tmp, k);
}
// mont(aR, bR) = aR * bR * R^-1 = abR (mod p)
void bn_mont_mod_mul(uint32_t *r, const uint32_t *a, const uint32_t *b, const uint32_t *p,
const uint32_t *p_inv_neg,
uint32_t *tmp, // uint32_t tmp[5 * k]
size_t k)
{
uint32_t *z; // uint32_t z[k * 2];
uint32_t *c; // uint32_t c[k * 2];
uint32_t *t; // uint32_t t[k];
z = tmp; tmp += 2 * k;
c = tmp; tmp += 2 * k;
t = tmp; tmp += k;
bn_mul(z, a, b, k);
bn_mul_lo(t, z, p_inv_neg, k);
bn_mul(c, t, p, k);
bn_add(c, c, z, k * 2);
if (bn_cmp(c + k, p, k) >= 0) {
bn_sub(c + k, c + k, p, k);
}
bn_copy(r, c + k, k);
}
void bn_mont_mod_sqr(uint32_t *r, const uint32_t *a, const uint32_t *p,
const uint32_t *p_inv_neg,
uint32_t *tmp, // uint32_t tmp[5 * k]
size_t k)
{
bn_mont_mod_mul(r, a, a, p, p_inv_neg, tmp, k);
}
void bn_mont_mod_exp(
uint32_t *r,
const uint32_t *a,
const uint32_t *e,
const uint32_t *p,
const uint32_t *p_inv_neg,
uint32_t *tmp, // uint32_t tmp[6 * k];
size_t k)
{
uint32_t *t; // uint32_t t[k];
uint32_t w;
int i, j;
// t = 1
t = tmp; tmp += k;
bn_set_word(t, 1, k);
for (i = k - 1; i >= 0; i--) {
w = e[i];
for (j = 0; j < 32; j++) {
bn_mont_mod_sqr(t, t, p, p_inv_neg, tmp, k);
if (w & 0x80000000) {
bn_mont_mod_mul(t, t, a, p, p_inv_neg, tmp, k);
}
w <<= 1;
}
}
bn_copy(r, t, k);
}
// FIXME: 如果 a = 0 (mod p) 会发生什么
void bn_mont_mod_inv(uint32_t *r, const uint32_t *a, const uint32_t *p,
const uint32_t *p_inv_neg,
uint32_t *tmp, // uint32_t tmp[7 * k];
size_t k)
{
uint32_t *e; // uint32_t e[k];
// e = p - 2
e = tmp; tmp += k;
bn_set_word(e, 2, k);
bn_sub(e, p, e, k);
// a^-1 = a^(p - 2) (mod p)
bn_mont_mod_exp(r, a, e, p, p_inv_neg, tmp, k);
}
// mont(a, R^2) = a * R^2 * R^-1 = a * R mod p
void bn_mont_set(uint32_t *r,
const uint32_t *a,
const uint32_t *R_sqr,
const uint32_t *p,
const uint32_t *p_inv_neg,
uint32_t *tmp, // uint32_t tmp[5 * k]
size_t k)
{
bn_mont_mod_mul(r, a, R_sqr, p, p_inv_neg, tmp, k);
}
// mont(aR, 1) = aR * 1 * R^-1 = a (mod p)
void bn_mont_get(uint32_t *r,
const uint32_t *a,
const uint32_t *p,
const uint32_t *p_inv_neg,
uint32_t *tmp, // uint32_t tmp[5 * k]
size_t k)
{
uint32_t one[k];
bn_set_word(one, 1, k);
bn_mont_mod_mul(r, a, one, p, p_inv_neg, tmp, k);
}

12
src/ecdh.c Normal file
View File

@@ -0,0 +1,12 @@
/*
* Copyright 2014-2026 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
*/

387
src/ecdsa.c Normal file
View File

@@ -0,0 +1,387 @@
/*
* Copyright 2014-2026 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 <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <gmssl/asn1.h>
#include <gmssl/sha2.h>
#include <gmssl/rand.h>
#include <gmssl/error.h>
#include <gmssl/ecdsa.h>
#include <gmssl/bn.h>
#include <gmssl/sm2.h>
int ecdsa_signature_print_ex(FILE *fp, int fmt, int ind, const char *label, const ECDSA_SIGNATURE *sig)
{
format_print(fp, fmt, ind, "%s\n", label);
ind += 4;
secp256r1_print(fp, fmt, ind, "r", sig->r);
secp256r1_print(fp, fmt, ind, "s", sig->s);
return 1;
}
int ecdsa_signature_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *sigbuf, size_t siglen)
{
ECDSA_SIGNATURE sig;
if (ecdsa_signature_from_der(&sig, &sigbuf, &siglen) != 1) {
error_print();
return -1;
}
ecdsa_signature_print_ex(fp, fmt, ind, label, &sig);
if (siglen) {
error_print();
return -1;
}
return 1;
}
int ecdsa_do_sign_ex(const SECP256R1_KEY *key, const secp256r1_t k, const uint8_t dgst[32], ECDSA_SIGNATURE *sig)
{
secp256r1_t e;
secp256r1_t x1;
secp256r1_t y1;
secp256r1_t k_inv;
SECP256R1_POINT P;
// e = hash(m)
secp256r1_from_32bytes(e, dgst);
secp256r1_modn(e, e);
// (x1, y1) = k*G
secp256r1_point_mul_generator(&P, k);
secp256r1_point_get_xy(&P, x1, y1);
// r = x1 mod n
secp256r1_modn(sig->r, x1);
// s = k^-1 * (e + d * r) mod n
secp256r1_modn_inv(k_inv, k);
secp256r1_modn_mul(sig->s, key->private_key, sig->r);
secp256r1_modn_add(sig->s, sig->s, e);
secp256r1_modn_mul(sig->s, sig->s, k_inv);
return 1;
}
int ecdsa_do_sign(const SECP256R1_KEY *key, const uint8_t dgst[32], ECDSA_SIGNATURE *sig)
{
secp256r1_t k;
// rand k in [1, n-1]
do {
if (rand_bytes((uint8_t *)k, sizeof(k)) != 1) {
error_print();
return -1;
}
} while (secp256r1_is_zero(k) || secp256r1_cmp(k, SECP256R1_N) >= 0);
if (ecdsa_do_sign_ex(key, k, dgst, sig) != 1) {
error_print();
return -1;
}
return 1;
}
int ecdsa_do_verify(const SECP256R1_KEY *key, const uint8_t dgst[32], const ECDSA_SIGNATURE *sig)
{
secp256r1_t e;
secp256r1_t w;
secp256r1_t u1;
secp256r1_t u2;
secp256r1_t x1;
secp256r1_t y1;
SECP256R1_POINT P;
SECP256R1_POINT Q;
SECP256R1_POINT R;
// check r, s in [1, n-1]
if (secp256r1_is_zero(sig->r)
|| secp256r1_cmp(sig->r, SECP256R1_N) >= 0
|| secp256r1_is_zero(sig->s)
|| secp256r1_cmp(sig->s, SECP256R1_N) >= 0) {
error_print();
return -1;
}
// e = hash(m)
secp256r1_from_32bytes(e, dgst);
secp256r1_modn(e, e);
// w = s^-1 (mod n)
secp256r1_modn_inv(w, sig->s);
// u1 = e * w (mod n)
secp256r1_modn_mul(u1, e, w);
// u2 = r * w (mod n)
secp256r1_modn_mul(u2, sig->r, w);
// (x1, y1) = u1*G + u2*Q
secp256r1_point_mul_generator(&P, u1);
secp256r1_point_mul(&Q, u2, &key->public_key);
secp256r1_point_add(&R, &P, &Q);
secp256r1_point_get_xy(&R, x1, y1);
// x1 = x1 mod n
secp256r1_modn(x1, x1);
if (secp256r1_cmp(x1, sig->r) != 0) {
return 0;
}
return 1;
}
int ecdsa_signature_to_der(const ECDSA_SIGNATURE *sig, uint8_t **out, size_t *outlen)
{
size_t len = 0;
uint8_t r[32];
uint8_t s[32];
if (!sig) {
return 0;
}
secp256r1_to_32bytes(sig->r, r);
secp256r1_to_32bytes(sig->s, s);
if (asn1_integer_to_der(r, 32, NULL, &len) != 1
|| asn1_integer_to_der(s, 32, NULL, &len) != 1
|| asn1_sequence_header_to_der(len, out, outlen) != 1
|| asn1_integer_to_der(r, 32, out, outlen) != 1
|| asn1_integer_to_der(s, 32, out, outlen) != 1) {
error_print();
return -1;
}
return 1;
}
int ecdsa_signature_from_der(ECDSA_SIGNATURE *sig, const uint8_t **in, size_t *inlen)
{
int ret;
const uint8_t *d;
const uint8_t *r;
const uint8_t *s;
size_t dlen, rlen, slen;
if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) {
if (ret < 0) error_print();
return ret;
}
if (asn1_integer_from_der(&r, &rlen, &d, &dlen) != 1
|| asn1_integer_from_der(&s, &slen, &d, &dlen) != 1
|| asn1_length_le(rlen, 32) != 1
|| asn1_length_le(slen, 32) != 1
|| asn1_length_is_zero(dlen) != 1) {
error_print();
return -1;
}
secp256r1_from_32bytes(sig->r, r);
secp256r1_from_32bytes(sig->s, s);
return 1;
}
int ecdsa_sign(const SECP256R1_KEY *key, const uint8_t dgst[32], uint8_t *sigbuf, size_t *siglen)
{
ECDSA_SIGNATURE sig;
if (ecdsa_do_sign(key, dgst, &sig) != 1) {
error_print();
return -1;
}
*siglen = 0;
if (ecdsa_signature_to_der(&sig, &sigbuf, siglen) != 1) {
error_print();
return -1;
}
return 1;
}
int ecdsa_sign_fixlen(const SECP256R1_KEY *key, const uint8_t dgst[32], size_t siglen, uint8_t *sig)
{
unsigned int trys = 200;
uint8_t buf[ECDSA_SIGNATURE_MAX_SIZE];
size_t len;
switch (siglen) {
case ECDSA_SIGNATURE_COMPACT_SIZE:
case ECDSA_SIGNATURE_TYPICAL_SIZE:
case ECDSA_SIGNATURE_MAX_SIZE:
break;
default:
error_print();
return -1;
}
while (trys--) {
if (ecdsa_sign(key, dgst, buf, &len) != 1) {
error_print();
return -1;
}
if (len == siglen) {
memcpy(sig, buf, len);
return 1;
}
}
// might caused by bad randomness
error_print();
return -1;
}
int ecdsa_verify(const SECP256R1_KEY *key, const uint8_t dgst[32], const uint8_t *sigbuf, size_t siglen)
{
int ret;
ECDSA_SIGNATURE sig;
if (ecdsa_signature_from_der(&sig, &sigbuf, &siglen) != 1) {
error_print();
return -1;
}
if (siglen) {
error_print();
return -1;
}
if ((ret = ecdsa_do_verify(key, dgst, &sig)) < 0) {
error_print();
return -1;
}
return ret;
}
int ecdsa_sign_init(ECDSA_SIGN_CTX *ctx, const SECP256R1_KEY *key)
{
if (!ctx || !key) {
error_print();
return -1;
}
memset(ctx, 0, sizeof(ECDSA_SIGN_CTX));
ctx->key = *key;
sha256_init(&ctx->sha256_ctx);
return 1;
}
int ecdsa_sign_update(ECDSA_SIGN_CTX *ctx, const uint8_t *data, size_t datalen)
{
if (!ctx) {
error_print();
return -1;
}
if (data && datalen) {
sha256_update(&ctx->sha256_ctx, data, datalen);
}
return 1;
}
int ecdsa_sign_finish(ECDSA_SIGN_CTX *ctx, uint8_t *sig, size_t *siglen)
{
uint8_t dgst[32];
if (!ctx || !sig || !siglen) {
error_print();
return -1;
}
sha256_finish(&ctx->sha256_ctx, dgst);
if (ecdsa_sign(&ctx->key, dgst, sig, siglen) != 1) {
error_print();
return -1;
}
return 1;
}
int ecdsa_sign_finish_fixlen(ECDSA_SIGN_CTX *ctx, size_t siglen, uint8_t *sig)
{
uint8_t dgst[32];
if (!ctx || !sig || !siglen) {
error_print();
return -1;
}
sha256_finish(&ctx->sha256_ctx, dgst);
if (ecdsa_sign_fixlen(&ctx->key, dgst, siglen, sig) != 1) {
error_print();
return -1;
}
return 1;
}
int ecdsa_verify_init(ECDSA_SIGN_CTX *ctx, const SECP256R1_KEY *key, const uint8_t *sig, size_t siglen)
{
if (!ctx || !key || !sig || !siglen) {
error_print();
return -1;
}
if (ecdsa_signature_from_der(&ctx->sig, &sig, &siglen) != 1) {
error_print();
return -1;
}
if (siglen) {
error_print();
return -1;
}
ctx->key = *key;
sha256_init(&ctx->sha256_ctx);
return 1;
}
int ecdsa_verify_update(ECDSA_SIGN_CTX *ctx, const uint8_t *data, size_t datalen)
{
if (!ctx) {
error_print();
return -1;
}
if (data && datalen) {
sha256_update(&ctx->sha256_ctx, data, datalen);
}
return 1;
}
int ecdsa_verify_finish(ECDSA_SIGN_CTX *ctx)
{
uint8_t dgst[32];
int ret;
if (!ctx) {
error_print();
return -1;
}
sha256_finish(&ctx->sha256_ctx, dgst);
if ((ret = ecdsa_do_verify(&ctx->key, dgst, &ctx->sig)) < 0) {
error_print();
return -1;
}
return ret;
}

593
src/secp256r1.c Normal file
View File

@@ -0,0 +1,593 @@
/*
* Copyright 2014-2026 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <gmssl/bn.h>
#include <gmssl/rand.h>
#include <gmssl/error.h>
#include <gmssl/secp256r1.h>
const secp256r1_t SECP256R1_P = {
0xffffffff, 0xffffffff, 0xffffffff, 0x00000000,
0x00000000, 0x00000000, 0x00000001, 0xffffffff,
};
const secp256r1_t SECP256R1_B = {
0x27d2604b, 0x3bce3c3e, 0xcc53b0f6, 0x651d06b0,
0x769886bc, 0xb3ebbd55, 0xaa3a93e7, 0x5ac635d8,
};
const secp256r1_t SECP256R1_N = {
0xfc632551, 0xf3b9cac2, 0xa7179e84, 0xbce6faad,
0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
};
const uint32_t SECP256R1_U_P[9] = {
0x00000003, 0x00000000, 0xffffffff, 0xfffffffe,
0xfffffffe, 0xfffffffe, 0xffffffff, 0x00000000,
0x00000001,
};
const uint32_t SECP256R1_U_N[9] = {
0xeedf9bfe, 0x012ffd85, 0xdf1a6c21, 0x43190552,
0xffffffff, 0xfffffffe, 0xffffffff, 0x00000000,
0x00000001,
};
int secp256r1_is_zero(const secp256r1_t a) {
return bn_is_zero(a, SECP256R1_K);
}
int secp256r1_is_one(const secp256r1_t a) {
return bn_is_one(a, SECP256R1_K);
}
int secp256r1_cmp(const secp256r1_t a, const secp256r1_t b) {
return bn_cmp(a, b, SECP256R1_K);
}
void secp256r1_set_zero(secp256r1_t r) {
bn_set_word(r, 0, SECP256R1_K);
}
void secp256r1_set_one(secp256r1_t r) {
bn_set_word(r, 1, SECP256R1_K);
}
void secp256r1_copy(secp256r1_t r, const secp256r1_t a) {
bn_copy(r, a, SECP256R1_K);
}
void secp256r1_to_32bytes(const secp256r1_t a, uint8_t out[32]) {
bn_to_bytes(a, SECP256R1_K, out);
}
void secp256r1_from_32bytes(secp256r1_t r, const uint8_t in[32]) {
bn_from_bytes(r, SECP256R1_K, in);
}
int secp256r1_print(FILE *fp, int fmt, int ind, const char *label, const secp256r1_t a) {
uint8_t bytes[32];
secp256r1_to_32bytes(a, bytes);
format_bytes(fp, fmt, ind, label, bytes, 32);
return 1;
}
void secp256r1_modp_add(secp256r1_t r, const secp256r1_t a, const secp256r1_t b) {
bn_mod_add(r, a, b, SECP256R1_P, SECP256R1_K);
}
void secp256r1_modp_dbl(secp256r1_t r, const secp256r1_t a) {
bn_mod_add(r, a, a, SECP256R1_P, SECP256R1_K);
}
void secp256r1_modp_tri(secp256r1_t r, const secp256r1_t a) {
secp256r1_t tmp;
// 这里就出错了,真是太奇怪了!
bn_mod_add(tmp, a, a, SECP256R1_P, SECP256R1_K);
bn_mod_add(r, tmp, a, SECP256R1_P, SECP256R1_K);
}
void secp256r1_modp_sub(secp256r1_t r, const secp256r1_t a, const secp256r1_t b) {
bn_mod_sub(r, a, b, SECP256R1_P, SECP256R1_K);
}
void secp256r1_modp_neg(secp256r1_t r, const secp256r1_t a) {
bn_mod_neg(r, a, SECP256R1_P, SECP256R1_K);
}
void secp256r1_modp_haf(secp256r1_t r, const secp256r1_t a) {
int c = 0;
if (a[0] & 1) {
c = bn_add(r, a, SECP256R1_P, SECP256R1_K);
} else {
bn_copy(r, a, SECP256R1_K);
}
r[0] = (r[0] >> 1) | ((r[1] & 1) << 31);
r[1] = (r[1] >> 1) | ((r[2] & 1) << 31);
r[2] = (r[2] >> 1) | ((r[3] & 1) << 31);
r[3] = (r[3] >> 1) | ((r[4] & 1) << 31);
r[4] = (r[4] >> 1) | ((r[5] & 1) << 31);
r[5] = (r[5] >> 1) | ((r[6] & 1) << 31);
r[6] = (r[6] >> 1) | ((r[7] & 1) << 31);
r[7] = (r[7] >> 1) | ((c & 1) << 31);
}
void secp256r1_modp_mul(secp256r1_t r, const secp256r1_t a, const secp256r1_t b) {
uint32_t tmp[6*8 + 4];
bn_barrett_mod_mul(r, a, b, SECP256R1_P, SECP256R1_U_P, tmp, SECP256R1_K);
}
void secp256r1_modp_sqr(secp256r1_t r, const secp256r1_t a) {
uint32_t tmp[6*8 + 4];
bn_barrett_mod_mul(r, a, a, SECP256R1_P, SECP256R1_U_P, tmp, SECP256R1_K);
}
void secp256r1_modp_exp(secp256r1_t r, const secp256r1_t a, const secp256r1_t e) {
uint32_t tmp[7*8 + 4];
bn_barrett_mod_exp(r, a, e, SECP256R1_P, SECP256R1_U_P, tmp, SECP256R1_K);
}
// FIXME: 如果 a = 0 (mod p) 会发生什么
void secp256r1_modp_inv(secp256r1_t r, const secp256r1_t a) {
uint32_t tmp[8*8 + 4];
bn_barrett_mod_inv(r, a, SECP256R1_P, SECP256R1_U_P, tmp, SECP256R1_K);
}
void secp256r1_modn(secp256r1_t r, const secp256r1_t a) {
if (bn_cmp(a, SECP256R1_N, SECP256R1_K) >= 0) {
bn_sub(r, a, SECP256R1_N, SECP256R1_K);
} else {
bn_copy(r, a, SECP256R1_K);
}
}
void secp256r1_modn_add(secp256r1_t r, const secp256r1_t a, const secp256r1_t b) {
bn_mod_add(r, a, b, SECP256R1_N, SECP256R1_K);
}
void secp256r1_modn_dbl(secp256r1_t r, const secp256r1_t a) {
bn_mod_add(r, a, a, SECP256R1_N, SECP256R1_K);
}
void secp256r1_modn_tri(secp256r1_t r, const secp256r1_t a) {
secp256r1_t tmp;
bn_mod_add(tmp, a, a, SECP256R1_N, SECP256R1_K);
bn_mod_add(r, tmp, a, SECP256R1_N, SECP256R1_K);
}
void secp256r1_modn_sub(secp256r1_t r, const secp256r1_t a, const secp256r1_t b) {
bn_mod_sub(r, a, b, SECP256R1_N, SECP256R1_K);
}
void secp256r1_modn_neg(secp256r1_t r, const secp256r1_t a) {
bn_mod_neg(r, a, SECP256R1_N, SECP256R1_K);
}
void secp256r1_modn_mul(secp256r1_t r, const secp256r1_t a, const secp256r1_t b) {
uint32_t tmp[6*8 + 4];
bn_barrett_mod_mul(r, a, b, SECP256R1_N, SECP256R1_U_N, tmp, SECP256R1_K);
}
void secp256r1_modn_sqr(secp256r1_t r, const secp256r1_t a) {
uint32_t tmp[6*8 + 4];
bn_barrett_mod_mul(r, a, a, SECP256R1_N, SECP256R1_U_N, tmp, SECP256R1_K);
}
void secp256r1_modn_exp(secp256r1_t r, const secp256r1_t a, const secp256r1_t e) {
uint32_t tmp[7*8 + 4];
bn_barrett_mod_exp(r, a, e, SECP256R1_N, SECP256R1_U_N, tmp, SECP256R1_K);
}
// FIXME: 如果 a = 0 (mod p) 会发生什么
void secp256r1_modn_inv(secp256r1_t r, const secp256r1_t a) {
uint32_t tmp[8*8 + 4];
bn_barrett_mod_inv(r, a, SECP256R1_N, SECP256R1_U_N, tmp, SECP256R1_K);
}
const SECP256R1_POINT SECP256R1_POINT_G = {
{ 0xd898c296, 0xf4a13945, 0x2deb33a0, 0x77037d81,
0x63a440f2, 0xf8bce6e5, 0xe12c4247, 0x6b17d1f2, },
{ 0x37bf51f5, 0xcbb64068, 0x6b315ece, 0x2bce3357,
0x7c0f9e16, 0x8ee7eb4a, 0xfe1a7f9b, 0x4fe342e2, },
{ 1,0,0,0,0,0,0,0, },
};
void secp256r1_point_set_infinity(SECP256R1_POINT *R)
{
secp256r1_set_one(R->X);
secp256r1_set_one(R->Y);
secp256r1_set_zero(R->Z);
}
int secp256r1_point_is_at_infinity(const SECP256R1_POINT *P)
{
if (secp256r1_is_zero(P->Z)) {
return 1;
}
return 0;
}
int secp256r1_point_is_on_curve(const SECP256R1_POINT *P)
{
secp256r1_t t0;
secp256r1_t t1;
secp256r1_t t2;
if (secp256r1_point_is_at_infinity(P)) {
return 1;
}
// check Y^2 + 3 * X * Z^4 == X^3 + b * Z^6
// t0 = Y^2
secp256r1_modp_sqr(t0, P->Y);
// t1 = Z^2
secp256r1_modp_sqr(t1, P->Z);
// t2 = Z^4
secp256r1_modp_sqr(t2, t1);
// t1 = Z^6
secp256r1_modp_mul(t1, t1, t2);
// t1 = b * Z^6
secp256r1_modp_mul(t1, t1, SECP256R1_B);
// t2 = X * Z^4
secp256r1_modp_mul(t2, t2, P->X);
// t0 = Y^2 + 3 * X * Z^4
secp256r1_modp_add(t0, t0, t2);
secp256r1_modp_add(t0, t0, t2);
secp256r1_modp_add(t0, t0, t2);
// t2 = X^2
secp256r1_modp_sqr(t2, P->X);
// t2 = X^3
secp256r1_modp_mul(t2, t2, P->X);
// t1 = b * Z^6 + X^3
secp256r1_modp_add(t1, t1, t2);
if (secp256r1_cmp(t0, t1) != 0) {
return 0;
}
return 1;
}
void secp256r1_point_copy(SECP256R1_POINT *R, const SECP256R1_POINT *P)
{
secp256r1_copy(R->X, P->X);
secp256r1_copy(R->Y, P->Y);
secp256r1_copy(R->Z, P->Z);
}
int secp256r1_point_set_xy(SECP256R1_POINT *R, const secp256r1_t x, const secp256r1_t y)
{
if (secp256r1_cmp(x, SECP256R1_P) >= 0) {
error_print();
return -1;
}
if (secp256r1_cmp(y, SECP256R1_P) >= 0) {
error_print();
return -1;
}
secp256r1_copy(R->X, x);
secp256r1_copy(R->Y, y);
secp256r1_set_one(R->Z);
if (!secp256r1_point_is_on_curve(R)) {
error_print();
return -1;
}
return 1;
}
int secp256r1_point_get_xy(const SECP256R1_POINT *P, secp256r1_t x, secp256r1_t y)
{
secp256r1_t Z_inv;
if (secp256r1_point_is_at_infinity(P)) {
return 0;
}
secp256r1_modp_inv(Z_inv, P->Z);
secp256r1_modp_mul(y, P->Y, Z_inv);
secp256r1_modp_sqr(Z_inv, Z_inv);
secp256r1_modp_mul(x, P->X, Z_inv);
secp256r1_modp_mul(y, y, Z_inv);
return 1;
}
void secp256r1_point_dbl(SECP256R1_POINT *R, const SECP256R1_POINT *P)
{
/*
secp256r1_t T_0;
secp256r1_t T_1;
secp256r1_t T_2;
secp256r1_t T_3;
secp256r1_t T_4;
if (secp256r1_point_is_at_infinity(P)) {
secp256r1_point_set_infinity(R);
return;
}
secp256r1_modp_sqr(T_0, P->X);
secp256r1_modp_tri(T_0, T_0);
secp256r1_modp_sqr(T_1, T_0);
secp256r1_modp_sqr(T_2, P->Y);
secp256r1_modp_mul(T_3, P->X, T_2);
secp256r1_modp_dbl(T_3, T_3);
secp256r1_modp_dbl(T_3, T_3);
secp256r1_modp_dbl(T_4, T_3);
secp256r1_modp_sub(T_1, T_1, T_4);
secp256r1_modp_sub(T_3, T_3, T_1);
secp256r1_modp_mul(T_0, T_0, T_3);
secp256r1_modp_dbl(T_2, T_2);
secp256r1_modp_sqr(T_2, T_2);
secp256r1_modp_dbl(T_2, T_2);
secp256r1_modp_sub(T_0, T_0, T_2);
secp256r1_modp_mul(T_2, P->Y, P->Z);
secp256r1_modp_dbl(T_2, T_2);
secp256r1_copy(R->X, T_1);
secp256r1_copy(R->Y, T_0);
secp256r1_copy(R->Z, T_2);
*/
const uint32_t *X1 = P->X;
const uint32_t *Y1 = P->Y;
const uint32_t *Z1 = P->Z;
uint32_t *X3 = R->X;
uint32_t *Y3 = R->Y;
uint32_t *Z3 = R->Z;
secp256r1_t S;
secp256r1_t M;
secp256r1_t Zsqr;
secp256r1_t tmp0;
// 1. S = 2Y
secp256r1_modp_dbl(S, Y1);
// 2. Zsqr = Z^2
secp256r1_modp_sqr(Zsqr, Z1);
// 3. S = S^2 = 4Y^2
secp256r1_modp_sqr(S, S);
// 4. Z = Z*Y
secp256r1_modp_mul(Z3, Z1, Y1);
// 5. Z = 2*Z = 2*Y*Z ===> Z3
secp256r1_modp_dbl(Z3, Z3);
// 6. M = X + Zsqr = X + Z^2
secp256r1_modp_add(M, X1, Zsqr);
// 7. Zsqr = X - Zsqr = X - Z^2
secp256r1_modp_sub(Zsqr, X1, Zsqr);
// 8. Y = S^2 = 16Y^4
secp256r1_modp_sqr(Y3, S);
// 9. Y = Y/2 = 8Y^4
secp256r1_modp_haf(Y3, Y3);
// 10. M = M * Zsqr = (X + Z^2)*(X - Z^2) = X^2 - Z^4
secp256r1_modp_mul(M, M, Zsqr);
// 11. M = 3M = 3X^2 - 3Z^4
secp256r1_modp_tri(M, M);
// 12. S = S * X = 4X*Y^2
secp256r1_modp_mul(S, S, X1);
// 13. tmp0 = 2 * S = 8X*Y^2
secp256r1_modp_dbl(tmp0, S);
// 14. X = M^2 = (3X^2 - 3Z^4)^2
secp256r1_modp_sqr(X3, M);
// 15. X = X - tmp0 = (3X^2 - 3Z^4)^2 - 8X*Y^2 ===> X3
secp256r1_modp_sub(X3, X3, tmp0);
// 16. S = S - X3 = 4X*Y^2 - X3
secp256r1_modp_sub(S, S, X3);
// 17. S = S * M = (3X^2 - 3Z^4)*(4X*Y^2 - X3)
secp256r1_modp_mul(S, S, M);
// 18. Y = S - Y = (3X^2 - 3Z^4)*(4X*Y^2 - X3) - 8Y^4 ===> Y3
secp256r1_modp_sub(Y3, S, Y3);
}
void secp256r1_point_add(SECP256R1_POINT *R, const SECP256R1_POINT *P, const SECP256R1_POINT *Q)
{
secp256r1_t T_1;
secp256r1_t T_2;
secp256r1_t T_3;
secp256r1_t T_4;
secp256r1_t T_5;
secp256r1_t T_6;
secp256r1_t T_7;
secp256r1_t T_8;
if (secp256r1_point_is_at_infinity(P)) {
*R = *Q;
return;
}
if (secp256r1_point_is_at_infinity(Q)) {
*R = *P;
return;
}
// 这里的代码是来自zkrypt的不确定是否有问题
secp256r1_modp_sqr(T_1, P->Z); // T_1 = Z_1^2
secp256r1_modp_sqr(T_2, Q->Z); // T_2 = Z_2^2
secp256r1_modp_mul(T_3, Q->X, T_1); // T_3 = X_2 * Z_1^2
secp256r1_modp_mul(T_4, P->X, T_2); // T_4 = X_1 * Z_2^2
secp256r1_modp_add(T_5, T_3, T_4); // T_5 = X_2 * Z_1^2 + X_1 * Z_2^2 = C
secp256r1_modp_sub(T_3, T_3, T_4); // T_3 = X_2 * Z_1^2 - X_1 * Z_2^2 = B
secp256r1_modp_mul(T_1, T_1, P->Z); // T_1 = Z_1^3
secp256r1_modp_mul(T_1, T_1, Q->Y); // T_1 = Y_2 * Z_1^3
secp256r1_modp_mul(T_2, T_2, Q->Z); // T_2 = Z_2^3
secp256r1_modp_mul(T_2, T_2, P->Y); // T_2 = Y_1 * Z_2^3
secp256r1_modp_add(T_6, T_1, T_2); // T_6 = Y_2 * Z_1^3 + Y_1 * Z_2^3 = D
secp256r1_modp_sub(T_1, T_1, T_2); // T_1 = Y_2 * Z_1^3 - Y_1 * Z_2^3 = A
if (secp256r1_is_zero(T_1) && secp256r1_is_zero(T_3)) {
secp256r1_point_dbl(R, P);
return;
}
if (secp256r1_is_one(T_1) && secp256r1_is_zero(T_6)) {
secp256r1_point_set_infinity(R);
return;
}
secp256r1_modp_sqr(T_6, T_1); // T_6 = A^2
secp256r1_modp_mul(T_7, T_3, P->Z); // T_7 = B * Z_1
secp256r1_modp_mul(T_7, T_7, Q->Z); // T_7 = B * Z_1 * Z_2 = Z_3
secp256r1_modp_sqr(T_8, T_3); // T_8 = B^2
secp256r1_modp_mul(T_5, T_5, T_8); // T_5 = B^2 * C
secp256r1_modp_mul(T_3, T_3, T_8); // T_3 = B^3
secp256r1_modp_mul(T_4, T_4, T_8); // T_4 = B^2 * X_1 * Z_2^2
secp256r1_modp_sub(T_6, T_6, T_5); // T_6 = A^2 - B^2 * C = X_3
secp256r1_modp_sub(T_4, T_4, T_6); // T_4 = B^2 * X_1 * Z_2^2 - X_3
secp256r1_modp_mul(T_1, T_1, T_4); // T_1 = A * (B^2 * X_1 * Z_2^2 - X_3)
secp256r1_modp_mul(T_2, T_2, T_3); // T_2 = B^3 * Y_1 * Z_1^3
secp256r1_modp_sub(T_1, T_1, T_2); // T_1 = A * (B^2 * X_1 * Z_2^2 - X_3) - B^3 * Y_1 * Z_1^3 = Y_3
secp256r1_copy(R->X, T_6);
secp256r1_copy(R->Y, T_1);
secp256r1_copy(R->Z, T_7);
}
void secp256r1_point_neg(SECP256R1_POINT *R, const SECP256R1_POINT *P)
{
if (secp256r1_point_is_at_infinity(P)) {
secp256r1_point_set_infinity(R);
return;
}
secp256r1_copy(R->X, P->X);
secp256r1_modp_neg(R->Y, P->Y);
secp256r1_copy(R->Z, P->Z);
}
void secp256r1_point_sub(SECP256R1_POINT *R, const SECP256R1_POINT *P, const SECP256R1_POINT *Q)
{
SECP256R1_POINT T;
secp256r1_point_neg(&T, Q);
secp256r1_point_add(R, P, &T);
}
void secp256r1_point_mul(SECP256R1_POINT *R, const secp256r1_t k, const SECP256R1_POINT *P)
{
uint32_t bits;
int nbits;
int i;
secp256r1_point_set_infinity(R);
for (i = 7; i >= 0; i--) {
bits = k[i];
nbits = 32;
while (nbits-- > 0) {
secp256r1_point_dbl(R, R);
if (bits & 0x80000000) {
secp256r1_point_add(R, R, P);
}
bits <<= 1;
}
}
}
void secp256r1_point_mul_generator(SECP256R1_POINT *R, const secp256r1_t k)
{
secp256r1_point_mul(R, k, &SECP256R1_POINT_G);
}
int secp256r1_point_print(FILE *fp, int fmt, int ind, const char *label, const SECP256R1_POINT *P)
{
uint8_t bytes[32];
format_print(fp, fmt, ind, "%s\n", label);
ind += 4;
secp256r1_to_32bytes(P->X, bytes);
format_bytes(fp, fmt, ind, "X", bytes, 32);
secp256r1_to_32bytes(P->Y, bytes);
format_bytes(fp, fmt, ind, "Y", bytes, 32);
secp256r1_to_32bytes(P->Z, bytes);
format_bytes(fp, fmt, ind, "Z", bytes, 32);
return 1;
}
int secp256r1_point_to_uncompressed_octets(const SECP256R1_POINT *P, uint8_t octets[65])
{
secp256r1_t x;
secp256r1_t y;
if (secp256r1_point_get_xy(P, x, y) != 1) {
error_print();
return -1;
}
octets[0] = 0x04;
secp256r1_to_32bytes(x, octets + 1);
secp256r1_to_32bytes(y, octets + 33);
return 1;
}
int secp256r1_point_from_uncompressed_octets(SECP256R1_POINT *P, const uint8_t octets[65])
{
secp256r1_t x;
secp256r1_t y;
if (octets[0] != 0x04) {
error_print();
return -1;
}
secp256r1_from_32bytes(x, octets + 1);
secp256r1_from_32bytes(y, octets + 33);
if (secp256r1_point_set_xy(P, x, y) != 1) {
error_print();
return -1;
}
return 1;
}
int secp256r1_point_equ(const SECP256R1_POINT *P, const SECP256R1_POINT *Q)
{
uint8_t p_octets[65];
uint8_t q_octets[65];
(void)secp256r1_point_to_uncompressed_octets(P, p_octets);
(void)secp256r1_point_to_uncompressed_octets(Q, q_octets);
if (memcmp(p_octets, q_octets, 65) == 0) {
return 1;
} else {
return 0;
}
}

506
src/secp256r1_key.c Normal file
View File

@@ -0,0 +1,506 @@
/*
* Copyright 2014-2026 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <gmssl/bn.h>
#include <gmssl/ec.h>
#include <gmssl/mem.h>
#include <gmssl/oid.h>
#include <gmssl/sm4.h>
#include <gmssl/rand.h>
#include <gmssl/asn1.h>
#include <gmssl/error.h>
#include <gmssl/pkcs8.h>
#include <gmssl/x509_alg.h>
#include <gmssl/secp256r1_key.h>
int secp256r1_key_generate(SECP256R1_KEY *key)
{
do {
if (rand_bytes((uint8_t *)key->private_key, sizeof(secp256r1_t)) != 1) {
error_print();
return -1;
}
} while (secp256r1_is_zero(key->private_key) || secp256r1_cmp(key->private_key, SECP256R1_N) >= 0);
secp256r1_point_mul_generator(&key->public_key, key->private_key);
return 1;
}
int secp256r1_key_set_private_key(SECP256R1_KEY *key, const secp256r1_t private_key)
{
if (!key || !private_key) {
error_print();
return -1;
}
if (secp256r1_is_zero(private_key) || secp256r1_cmp(private_key, SECP256R1_N) >= 0) {
error_print();
return -1;
}
memset(key, 0, sizeof(SECP256R1_KEY));
secp256r1_copy(key->private_key, private_key);
secp256r1_point_mul_generator(&key->public_key, key->private_key);
return 1;
}
int secp256r1_public_key_equ(const SECP256R1_KEY *key, const SECP256R1_KEY *pub)
{
if (secp256r1_point_equ(&key->public_key, &pub->public_key) == 1) {
return 1;
} else {
return 0;
}
}
void secp256r1_key_cleanup(SECP256R1_KEY *key)
{
if (key) {
gmssl_secure_clear(key->private_key, sizeof(secp256r1_t));
memset(key, 0, sizeof(SECP256R1_KEY));
}
}
// SM2将这个命名为_to_octets应该更准确一些
int secp256r1_public_key_to_bytes(const SECP256R1_KEY *key, uint8_t **out, size_t *outlen)
{
if (!key || !outlen) {
error_print();
return -1;
}
if (out && *out) {
if (secp256r1_point_to_uncompressed_octets(&key->public_key, *out) != 1) {
error_print();
return -1;
}
*out += 65;
}
*outlen += 65;
return 1;
}
int secp256r1_public_key_from_bytes(SECP256R1_KEY *key, const uint8_t **in, size_t *inlen)
{
secp256r1_t x;
secp256r1_t y;
if (!key || !in || !(*in) || !inlen) {
error_print();
return -1;
}
if (*inlen < 65) {
error_print();
return -1;
}
memset(key, 0, sizeof(SECP256R1_KEY));
if (secp256r1_point_from_uncompressed_octets(&key->public_key, *in) != 1) {
error_print();
return -1;
}
*in += 65;
*inlen -= 65;
return 1;
}
int secp256r1_public_key_print(FILE *fp, int fmt, int ind, const char *label, const SECP256R1_KEY *key)
{
secp256r1_t x;
secp256r1_t y;
format_print(fp, fmt, ind, "%s\n", label);
ind += 4;
secp256r1_print(fp, fmt, ind, "X", key->public_key.X);
secp256r1_print(fp, fmt, ind, "Y", key->public_key.Y);
secp256r1_print(fp, fmt, ind, "Z", key->public_key.Z);
secp256r1_point_get_xy(&key->public_key, x, y);
secp256r1_print(fp, fmt, ind, "x", x);
secp256r1_print(fp, fmt, ind, "y", y);
return 1;
}
int secp256r1_private_key_print(FILE *fp, int fmt, int ind, const char *label, const SECP256R1_KEY *key)
{
uint8_t buf[32];
secp256r1_to_32bytes(key->private_key, buf);
format_print(fp, fmt, ind, "%s\n", label);
ind += 4;
if (secp256r1_public_key_print(fp, fmt, ind, "public_key", key) != 1) {
error_print();
return -1;
}
format_bytes(fp, fmt, ind, "private_key", buf, 32);
return 1;
}
int secp256r1_public_key_to_der(const SECP256R1_KEY *key, uint8_t **out, size_t *outlen)
{
uint8_t octets[65];
uint8_t *p = octets;
size_t len = 0;
if (!key) {
return 0;
}
// different from SM2
if (out && *out) {
if (secp256r1_public_key_to_bytes(key, &p, &len) != 1) {
error_print();
return -1;
}
}
if (asn1_bit_octets_to_der(octets, sizeof(octets), out, outlen) != 1) {
error_print();
return -1;
}
return 1;
}
int secp256r1_public_key_from_der(SECP256R1_KEY *key, const uint8_t **in, size_t *inlen)
{
int ret;
const uint8_t *d;
size_t dlen;
if ((ret = asn1_bit_octets_from_der(&d, &dlen, in, inlen)) != 1) {
if (ret < 0) error_print();
return ret;
}
if (secp256r1_public_key_from_bytes(key, &d, &dlen) != 1) {
error_print();
return -1;
}
if (dlen) {
error_print();
return -1;
}
return 1;
}
int secp256r1_private_key_to_der(const SECP256R1_KEY *key, uint8_t **out, size_t *outlen)
{
int curve = OID_secp256r1;
uint8_t params[64];
uint8_t pubkey[128];
uint8_t *params_ptr = params;
uint8_t *pubkey_ptr = pubkey;
size_t params_len = 0;
size_t pubkey_len = 0;
uint8_t prikey[32];
size_t len = 0;
if (!key) {
error_print();
return -1;
}
if (ec_named_curve_to_der(curve, &params_ptr, &params_len) != 1
|| secp256r1_public_key_to_der(key, &pubkey_ptr, &pubkey_len) != 1) {
error_print();
return -1;
}
// fprintf(stderr, "%s %d: params_len = %zu\n", params_len);
// fprintf(stderr, "%s %d: pubkey_len = %zu\n", pubkey_len);
secp256r1_to_32bytes(key->private_key, prikey);
if (asn1_int_to_der(EC_private_key_version, NULL, &len) != 1
|| asn1_octet_string_to_der(prikey, 32, NULL, &len) != 1
|| asn1_explicit_to_der(0, params, params_len, NULL, &len) != 1
|| asn1_explicit_to_der(1, pubkey, pubkey_len, NULL, &len) != 1
|| asn1_sequence_header_to_der(len, out, outlen) != 1
|| asn1_int_to_der(EC_private_key_version, out, outlen) != 1
|| asn1_octet_string_to_der(prikey, 32, out, outlen) != 1
|| asn1_explicit_to_der(0, params, params_len, out, outlen) != 1
|| asn1_explicit_to_der(1, pubkey, pubkey_len, out, outlen) != 1) {
gmssl_secure_clear(prikey, 32);
error_print();
return -1;
}
gmssl_secure_clear(prikey, 32);
return 1;
}
int secp256r1_private_key_from_der(SECP256R1_KEY *key, const uint8_t **in, size_t *inlen)
{
int ret;
const uint8_t *d;
size_t dlen;
int ver;
const uint8_t *prikey;
const uint8_t *params;
const uint8_t *pubkey;
size_t prikey_len, params_len, pubkey_len;
int curve;
SECP256R1_KEY tmp_key;
secp256r1_t private_key;
if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) {
if (ret < 0) error_print();
return ret;
}
if (asn1_int_from_der(&ver, &d, &dlen) != 1
|| asn1_octet_string_from_der(&prikey, &prikey_len, &d, &dlen) != 1
|| asn1_explicit_from_der(0, &params, &params_len, &d, &dlen) != 1
|| asn1_explicit_from_der(1, &pubkey, &pubkey_len, &d, &dlen) != 1
|| asn1_check(ver == EC_private_key_version) != 1
|| asn1_length_is_zero(dlen) != 1) {
error_print();
return -1;
}
if (!params || !pubkey) {
error_print();
return -1;
}
// public_key
if (ec_named_curve_from_der(&curve, &params, &params_len) != 1
|| asn1_check(curve == OID_secp256r1) != 1
|| asn1_length_is_zero(params_len) != 1) {
error_print();
return -1;
}
if (secp256r1_public_key_from_der(&tmp_key, &pubkey, &pubkey_len) != 1
|| asn1_length_is_zero(pubkey_len) != 1) {
error_print();
return -1;
}
// private_key
if (!prikey || prikey_len != 32) {
error_print();
return -1;
}
secp256r1_from_32bytes(private_key, prikey);
if (secp256r1_key_set_private_key(key, private_key) != 1) {
gmssl_secure_clear(private_key, 32);
error_print();
return -1;
}
gmssl_secure_clear(private_key, 32);
// check
if (secp256r1_public_key_equ(key, &tmp_key) != 1) {
secp256r1_key_cleanup(key);
error_print();
return -1;
}
return 1;
}
int secp256r1_private_key_info_to_der(const SECP256R1_KEY *key, uint8_t **out, size_t *outlen)
{
int algor = OID_ec_public_key;
int algor_param = OID_secp256r1;
size_t len = 0;
uint8_t prikey[256];
uint8_t *p = prikey;
size_t prikey_len = 0;
if (secp256r1_private_key_to_der(key, &p, &prikey_len) != 1) {
error_print();
return -1;
}
//fprintf(stderr, "%s %d: prikey_len = %zu\n", __FILE__, __LINE__, prikey_len);
if (asn1_int_to_der(PKCS8_private_key_info_version, NULL, &len) != 1
|| x509_public_key_algor_to_der(algor, algor_param, NULL, &len) != 1
|| asn1_octet_string_to_der(prikey, prikey_len, NULL, &len) != 1
|| asn1_sequence_header_to_der(len, out, outlen) != 1
|| asn1_int_to_der(PKCS8_private_key_info_version, out, outlen) != 1
|| x509_public_key_algor_to_der(algor, algor_param, out, outlen) != 1
|| asn1_octet_string_to_der(prikey, prikey_len, out, outlen) != 1) {
memset(prikey, 0, sizeof(prikey));
error_print();
return -1;
}
memset(prikey, 0, sizeof(prikey));
return 1;
}
int secp256r1_private_key_info_from_der(SECP256R1_KEY *key, const uint8_t **attrs, size_t *attrslen,
const uint8_t **in, size_t *inlen)
{
int ret;
const uint8_t *d;
size_t dlen;
int version;
int algor;
int algor_param;
const uint8_t *prikey;
size_t prikey_len;
if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) {
if (ret < 0) error_print();
return ret;
}
if (asn1_int_from_der(&version, &d, &dlen) != 1
|| x509_public_key_algor_from_der(&algor, &algor_param, &d, &dlen) != 1
|| asn1_octet_string_from_der(&prikey, &prikey_len, &d, &dlen) != 1
|| asn1_implicit_set_from_der(0, attrs, attrslen, &d, &dlen) < 0
|| asn1_length_is_zero(dlen) != 1) {
error_print();
return -1;
}
if (asn1_check(version == PKCS8_private_key_info_version) != 1
|| asn1_check(algor == OID_ec_public_key) != 1
|| asn1_check(algor_param == OID_secp256r1) != 1
|| secp256r1_private_key_from_der(key, &prikey, &prikey_len) != 1
|| asn1_length_is_zero(prikey_len) != 1) {
error_print();
return -1;
}
return 1;
}
int secp256r1_private_key_info_encrypt_to_der(const SECP256R1_KEY *ec_key, const char *pass,
uint8_t **out, size_t *outlen)
{
int ret = -1;
uint8_t pkey_info[512];
uint8_t *p = pkey_info;
size_t pkey_info_len = 0;
uint8_t salt[16];
int iter = 65536;
uint8_t iv[16];
uint8_t key[16];
SM4_KEY sm4_key;
uint8_t enced_pkey_info[sizeof(pkey_info) + 32];
size_t enced_pkey_info_len;
if (!ec_key || !pass || !outlen) {
error_print();
return -1;
}
if (secp256r1_private_key_info_to_der(ec_key, &p, &pkey_info_len) != 1
|| rand_bytes(salt, sizeof(salt)) != 1
|| rand_bytes(iv, sizeof(iv)) != 1
|| sm3_pbkdf2(pass, strlen(pass), salt, sizeof(salt), iter, sizeof(key), key) != 1) {
error_print();
goto end;
}
/*
if (pkey_info_len != sizeof(pkey_info)) {
error_print();
goto end;
}
*/
sm4_set_encrypt_key(&sm4_key, key);
if (sm4_cbc_padding_encrypt(
&sm4_key, iv, pkey_info, pkey_info_len,
enced_pkey_info, &enced_pkey_info_len) != 1
|| pkcs8_enced_private_key_info_to_der(
salt, sizeof(salt), iter, sizeof(key), OID_hmac_sm3,
OID_sm4_cbc, iv, sizeof(iv),
enced_pkey_info, enced_pkey_info_len, out, outlen) != 1) {
error_print();
goto end;
}
ret = 1;
end:
gmssl_secure_clear(pkey_info, sizeof(pkey_info));
gmssl_secure_clear(key, sizeof(key));
gmssl_secure_clear(&sm4_key, sizeof(sm4_key));
return ret;
}
int secp256r1_private_key_info_decrypt_from_der(SECP256R1_KEY *ec_key,
const uint8_t **attrs, size_t *attrs_len,
const char *pass, const uint8_t **in, size_t *inlen)
{
int ret = -1;
const uint8_t *salt;
size_t saltlen;
int iter;
int keylen;
int prf;
int cipher;
const uint8_t *iv;
size_t ivlen;
uint8_t key[16];
SM4_KEY sm4_key;
const uint8_t *enced_pkey_info;
size_t enced_pkey_info_len;
uint8_t pkey_info[256];
const uint8_t *cp = pkey_info;
size_t pkey_info_len;
if (!ec_key || !attrs || !attrs_len || !pass || !in || !(*in) || !inlen) {
error_print();
return -1;
}
if (pkcs8_enced_private_key_info_from_der(&salt, &saltlen, &iter, &keylen, &prf,
&cipher, &iv, &ivlen, &enced_pkey_info, &enced_pkey_info_len, in, inlen) != 1
|| asn1_check(keylen == -1 || keylen == 16) != 1
|| asn1_check(prf == - 1 || prf == OID_hmac_sm3) != 1
|| asn1_check(cipher == OID_sm4_cbc) != 1
|| asn1_check(ivlen == 16) != 1
|| asn1_length_le(enced_pkey_info_len, sizeof(pkey_info)) != 1) {
error_print();
return -1;
}
if (sm3_pbkdf2(pass, strlen(pass), salt, saltlen, iter, sizeof(key), key) != 1) {
error_print();
goto end;
}
sm4_set_decrypt_key(&sm4_key, key);
if (sm4_cbc_padding_decrypt(&sm4_key, iv, enced_pkey_info, enced_pkey_info_len,
pkey_info, &pkey_info_len) != 1
|| secp256r1_private_key_info_from_der(ec_key, attrs, attrs_len, &cp, &pkey_info_len) != 1
|| asn1_length_is_zero(pkey_info_len) != 1) {
error_print();
goto end;
}
ret = 1;
end:
gmssl_secure_clear(&sm4_key, sizeof(sm4_key));
gmssl_secure_clear(key, sizeof(key));
gmssl_secure_clear(pkey_info, sizeof(pkey_info));
return ret;
}

View File

@@ -1,4 +1,4 @@
/*
/*
* Copyright 2014-2026 The GmSSL Project. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the License); you may

309
src/tls12_handshake.c Normal file
View File

@@ -0,0 +1,309 @@
/*
* Copyright 2014-2026 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 <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gmssl/rand.h>
#include <gmssl/x509.h>
#include <gmssl/error.h>
#include <gmssl/sm2.h>
#include <gmssl/sm3.h>
#include <gmssl/sm4.h>
#include <gmssl/pem.h>
#include <gmssl/mem.h>
#include <gmssl/tls.h>
enum {
TLS_state_client_hello,
TLS_state_server_hello,
TLS_state_server_certificate,
TLS_state_server_key_exchange,
TLS_state_server_certificate_request,
TLS_state_server_hello_done,
TLS_state_client_certificate,
TLS_state_client_key_exchange,
TLS_state_client_certificate_verify,
TLS_state_client_change_cipher_spec,
TLS_state_client_finished,
TLS_state_server_change_cipher_spec,
TLS_state_server_finished,
};
static const int tls12_ciphers[] = {
TLS_cipher_ecdhe_sm4_cbc_sm3,
};
int tls_send_client_hello(TLS_CONNECT *conn)
{
const int ec_point_formats[] = { TLS_point_uncompressed };
size_t ec_point_formats_cnt = sizeof(ec_point_formats)/sizeof(ec_point_formats[0]);
const int supported_groups[] = { TLS_curve_sm2p256v1 };
size_t supported_groups_cnt = sizeof(supported_groups)/sizeof(supported_groups[0]);
const int signature_algors[] = { TLS_sig_sm2sig_sm3 };
size_t signature_algors_cnt = sizeof(signature_algors)/sizeof(signature_algors[0]);
uint8_t *record;
size_t recordlen;
uint8_t client_random[32];
uint8_t client_exts[TLS_MAX_EXTENSIONS_SIZE];
size_t client_exts_len;
uint8_t *p;
record = conn->record;
tls_record_set_protocol(record, TLS_protocol_tls1);
sm3_init(&conn->sm3_ctx);
if (conn->client_certs_len)
sm2_sign_init(&conn->sign_ctx, &conn->sign_key, SM2_DEFAULT_ID, SM2_DEFAULT_ID_LENGTH);
tls_random_generate(client_random);
p = client_exts;
client_exts_len = 0;
tls_ec_point_formats_ext_to_bytes(ec_point_formats, ec_point_formats_cnt, &p, &client_exts_len);
tls_supported_groups_ext_to_bytes(supported_groups, supported_groups_cnt, &p, &client_exts_len);
tls_signature_algorithms_ext_to_bytes(signature_algors, signature_algors_cnt, &p, &client_exts_len);
if (tls_record_set_handshake_client_hello(conn->record, &recordlen,
conn->protocol, client_random, NULL, 0,
tls12_ciphers, sizeof(tls12_ciphers)/sizeof(tls12_ciphers[0]),
client_exts, client_exts_len) != 1) {
error_print();
return -1;
}
tls_trace("send ClientHello\n");
tls12_record_trace(stderr, record, recordlen, 0, 0);
if (tls_record_send(record, recordlen, conn->sock) != 1) {
error_print();
return -1;
}
sm3_update(&conn->sm3_ctx, record + 5, recordlen - 5);
if (conn->client_certs_len) {
sm2_sign_update(&conn->sign_ctx, record + 5, recordlen - 5);
}
return 1;
}
int tls_recv_server_hello(TLS_CONNECT *conn)
{
uint8_t *record = conn->record;
size_t recordlen;
tls_trace("recv ServerHello\n");
if (tls_record_recv(record, &recordlen, conn->sock) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_unexpected_message);
return -1;
}
tls12_record_trace(stderr, record, recordlen, 0, 0);
if (tls_record_protocol(record) != conn->protocol) {
error_print();
tls_send_alert(conn, TLS_alert_protocol_version);
return -1;
}
// 这些值要放在哪儿呢是否放在CONNECT中
int protocol;
int cipher_suite;
uint8_t server_random[32];
const uint8_t *random;
const uint8_t *session_id;
size_t session_id_len;
const uint8_t *server_exts;
size_t server_exts_len;
// 扩展的协商结果,-1 表示服务器不支持该扩展(未给出响应)
int ec_point_format = -1;
int supported_group = -1;
int signature_algor = -1;
if (tls_record_get_handshake_server_hello(record,
&protocol, &random, &session_id, &session_id_len, &cipher_suite,
&server_exts, &server_exts_len) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_unexpected_message);
return -1;
}
if (protocol != conn->protocol) {
error_print();
tls_send_alert(conn, TLS_alert_protocol_version);
return -1;
}
// tls12_ciphers 应该改为conn的内部变量
if (tls_cipher_suite_in_list(cipher_suite, tls12_ciphers, sizeof(tls12_ciphers)/sizeof(tls12_ciphers[0])) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_handshake_failure);
return -1;
}
if (!server_exts) {
error_print();
tls_send_alert(conn, TLS_alert_unexpected_message);
return -1;
}
if (tls_process_server_hello_exts(server_exts, server_exts_len, &ec_point_format, &supported_group, &signature_algor) != 1
|| ec_point_format < 0
|| supported_group < 0
|| signature_algor < 0) {
error_print();
tls_send_alert(conn, TLS_alert_unexpected_message);
return -1;
}
memcpy(server_random, random, 32);
memcpy(conn->session_id, session_id, session_id_len);
conn->cipher_suite = cipher_suite;
sm3_update(&conn->sm3_ctx, record + 5, recordlen - 5);
if (conn->client_certs_len) {
sm2_sign_update(&conn->sign_ctx, record + 5, recordlen - 5);
}
return 1;
}
int tls_recv_server_certificate(TLS_CONNECT *conn)
{
const int depth = 5;
uint8_t *record = conn->record;
size_t recordlen;
int verify_result;
// recv ServerCertificate
tls_trace("recv ServerCertificate\n");
if (tls_record_recv(record, &recordlen, conn->sock) != 1
|| tls_record_protocol(record) != conn->protocol) {
error_print();
tls_send_alert(conn, TLS_alert_unexpected_message);
return -1;
}
tls12_record_trace(stderr, record, recordlen, 0, 0);
if (tls_record_get_handshake_certificate(record,
conn->server_certs, &conn->server_certs_len) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_unexpected_message);
return -1;
}
sm3_update(&conn->sm3_ctx, record + 5, recordlen - 5);
if (conn->client_certs_len)
sm2_sign_update(&conn->sign_ctx, record + 5, recordlen - 5);
// verify ServerCertificate
if (x509_certs_verify(conn->server_certs, conn->server_certs_len, X509_cert_chain_server,
conn->ca_certs, conn->ca_certs_len, depth, &verify_result) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_bad_certificate);
return -1;
}
return 1;
}
int tls_recv_server_key_exchange(TLS_CONNECT *conn)
{
return 1;
}
int tls_recv_server_certificate_request(TLS_CONNECT *conn)
{
return 1;
}
int tls_recv_server_hello_done(TLS_CONNECT *conn)
{
return 1;
}
int tls_send_client_certificate(TLS_CONNECT *conn)
{
return 1;
}
int tls_send_client_key_exchange(TLS_CONNECT *conn)
{
return 1;
}
int tls_send_certificate_verify(TLS_CONNECT *conn)
{
return 1;
}
int tls_send_client_finished(TLS_CONNECT *conn)
{
return 1;
}
int tls_recv_server_change_cipher_spec(TLS_CONNECT *conn)
{
return 1;
}
int tls_recv_server_finished(TLS_CONNECT *conn)
{
return 1;
}
int tls12_client_handshake(TLS_CONNECT *conn)
{
int ret;
switch (conn->state) {
case TLS_state_client_hello:
ret = tls_send_client_hello(conn);
break;
case TLS_state_server_hello:
ret = tls_recv_server_hello(conn);
break;
case TLS_state_server_certificate:
ret = tls_recv_server_certificate(conn);
break;
case TLS_state_server_key_exchange:
ret = tls_recv_server_key_exchange(conn);
break;
case TLS_state_server_certificate_request:
ret = tls_recv_server_certificate_request(conn);
break;
case TLS_state_server_hello_done:
ret = tls_recv_server_hello_done(conn);
break;
case TLS_state_client_certificate:
ret = tls_send_client_certificate(conn);
break;
case TLS_state_client_key_exchange:
ret = tls_send_client_key_exchange(conn);
break;
case TLS_state_client_certificate_verify:
ret = tls_send_certificate_verify(conn);
case TLS_state_client_change_cipher_spec:
break;
case TLS_state_client_finished:
ret = tls_send_client_finished(conn);
break;
case TLS_state_server_change_cipher_spec:
ret = tls_recv_server_change_cipher_spec(conn);
break;
case TLS_state_server_finished:
ret = tls_recv_server_finished(conn);
break;
default:
error_print();
return -1;
}
return 1;
}

View File

@@ -14,7 +14,6 @@
#include <gmssl/ec.h>
#include <gmssl/oid.h>
#include <gmssl/asn1.h>
#include <gmssl/sm2.h>
#include <gmssl/mem.h>
#include <gmssl/error.h>
#include <gmssl/x509_alg.h>
@@ -79,13 +78,16 @@ int x509_key_generate(X509_KEY *key, int algor, int algor_param)
switch (algor) {
case OID_ec_public_key:
if (algor_param != OID_sm2) {
error_print();
return -1;
}
if (sm2_key_generate(&key->u.sm2_key) != 1) {
error_print();
return -1;
if (algor_param == OID_sm2) {
if (sm2_key_generate(&key->u.sm2_key) != 1) {
error_print();
return -1;
}
} else if (algor_param == OID_secp256r1) {
if (secp256r1_key_generate(&key->u.secp256r1_key) != 1) {
error_print();
return -1;
}
}
break;
case OID_lms_hashsig:
@@ -156,7 +158,17 @@ int x509_public_key_print(FILE *fp, int fmt, int ind, const char *label, const X
{
switch (key->algor) {
case OID_ec_public_key:
if (sm2_public_key_print(fp, fmt, ind, label, &key->u.sm2_key) != 1) {
if (key->algor_param == OID_sm2) {
if (sm2_public_key_print(fp, fmt, ind, label, &key->u.sm2_key) != 1) {
error_print();
return -1;
}
} else if (key->algor_param == OID_secp256r1) {
if (secp256r1_public_key_print(fp, fmt, ind, label, &key->u.secp256r1_key) != 1) {
error_print();
return -1;
}
} else {
error_print();
return -1;
}
@@ -208,6 +220,15 @@ int x509_key_set_sm2_key(X509_KEY *x509_key, const SM2_KEY *sm2_key)
return 1;
}
int x509_key_set_secp256r1_key(X509_KEY *x509_key, const SECP256R1_KEY *secp256r1_key)
{
memset(x509_key, 0, sizeof(X509_KEY));
x509_key->algor = OID_ec_public_key;
x509_key->algor_param = OID_secp256r1;
x509_key->u.secp256r1_key = *secp256r1_key;
return 1;
}
int x509_key_set_lms_key(X509_KEY *x509_key, const LMS_KEY *lms_key)
{
memset(x509_key, 0, sizeof(X509_KEY));
@@ -288,11 +309,21 @@ int x509_public_key_digest(const X509_KEY *key, uint8_t dgst[32])
switch (key->algor) {
case OID_ec_public_key:
if (sm2_z256_point_to_uncompressed_octets(&key->u.sm2_key.public_key, bits) != 1) {
if (key->algor_param == OID_sm2) {
if (sm2_z256_point_to_uncompressed_octets(&key->u.sm2_key.public_key, bits) != 1) {
error_print();
return -1;
}
len = 65;
} else if (key->algor_param == OID_secp256r1) {
if (secp256r1_public_key_to_bytes(&key->u.secp256r1_key, &p, &len) != 1) {
error_print();
return -1;
}
} else {
error_print();
return -1;
}
len = 65;
break;
case OID_hss_lms_hashsig:
if (hss_public_key_to_bytes(&key->u.hss_key, &p, &len) != 1) {
@@ -340,7 +371,17 @@ int x509_public_key_equ(const X509_KEY *key, const X509_KEY *pub)
}
switch (key->algor) {
case OID_ec_public_key:
if (sm2_public_key_equ(&key->u.sm2_key, &pub->u.sm2_key) != 1) {
if (key->algor_param == OID_sm2) {
if (sm2_public_key_equ(&key->u.sm2_key, &pub->u.sm2_key) != 1) {
error_print();
return -1;
}
} else if (key->algor_param == OID_secp256r1) {
if (secp256r1_public_key_equ(&key->u.secp256r1_key, &pub->u.secp256r1_key) != 1) {
error_print();
return -1;
}
} else {
error_print();
return -1;
}
@@ -456,11 +497,22 @@ int x509_sign_init(X509_SIGN_CTX *ctx, X509_KEY *key, const char *signer_id, siz
ctx->sign_algor = key->algor;
break;
case OID_ec_public_key:
if (sm2_sign_init(&ctx->u.sm2_sign_ctx, &key->u.sm2_key, signer_id, signer_idlen) != 1) {
if (key->algor_param == OID_sm2) {
if (sm2_sign_init(&ctx->u.sm2_sign_ctx, &key->u.sm2_key, signer_id, signer_idlen) != 1) {
error_print();
return -1;
}
ctx->sign_algor = OID_sm2sign_with_sm3;
} else if (key->algor_param == OID_secp256r1) {
if (ecdsa_sign_init(&ctx->u.ecdsa_sign_ctx, &key->u.secp256r1_key) != 1) {
error_print();
return -1;
}
ctx->sign_algor = OID_ecdsa_with_sha256;
} else {
error_print();
return -1;
}
ctx->sign_algor = OID_sm2sign_with_sm3;
break;
default:
error_print();
@@ -497,6 +549,12 @@ int x509_sign_update(X509_SIGN_CTX *ctx, const uint8_t *data, size_t datalen)
return -1;
}
break;
case OID_ecdsa_with_sha256:
if (ecdsa_sign_update(&ctx->u.ecdsa_sign_ctx, data, datalen) != 1) {
error_print();
return -1;
}
break;
default:
error_print();
return -1;
@@ -536,6 +594,13 @@ int x509_sign_finish(X509_SIGN_CTX *ctx, uint8_t *sig, size_t *siglen)
return -1;
}
break;
case OID_ecdsa_with_sha256:
*siglen = ECDSA_SIGNATURE_TYPICAL_SIZE;
if (ecdsa_sign_finish_fixlen(&ctx->u.ecdsa_sign_ctx, *siglen, sig) != 1) {
error_print();
return -1;
}
break;
default:
error_print();
return -1;
@@ -574,17 +639,28 @@ int x509_verify_init(X509_SIGN_CTX *ctx, const X509_KEY *key, const char *signer
ctx->sign_algor = key->algor;
break;
case OID_ec_public_key:
if (sm2_verify_init(&ctx->u.sm2_verify_ctx, &key->u.sm2_key, signer_id, signer_idlen) != 1) {
if (key->algor_param == OID_sm2) {
if (sm2_verify_init(&ctx->u.sm2_verify_ctx, &key->u.sm2_key, signer_id, signer_idlen) != 1) {
error_print();
return -1;
}
ctx->sign_algor = OID_sm2sign_with_sm3;
if (siglen > sizeof(ctx->sig)) {
error_print();
return -1;
}
memcpy(ctx->sig, sig, siglen);
ctx->siglen = siglen;
} else if (key->algor_param == OID_secp256r1) {
if (ecdsa_verify_init(&ctx->u.ecdsa_sign_ctx, &key->u.secp256r1_key, sig, siglen) != 1) {
error_print();
return -1;
}
ctx->sign_algor = OID_ecdsa_with_sha256;
} else {
error_print();
return -1;
}
ctx->sign_algor = OID_sm2sign_with_sm3;
if (siglen > sizeof(ctx->sig)) {
error_print();
return -1;
}
memcpy(ctx->sig, sig, siglen);
ctx->siglen = siglen;
break;
default:
error_print();
@@ -620,6 +696,12 @@ int x509_verify_update(X509_SIGN_CTX *ctx, const uint8_t *data, size_t datalen)
return -1;
}
break;
case OID_ecdsa_with_sha256:
if (ecdsa_verify_update(&ctx->u.ecdsa_sign_ctx, data, datalen) != 1) {
error_print();
return -1;
}
break;
default:
error_print();
return -1;
@@ -652,7 +734,13 @@ int x509_verify_finish(X509_SIGN_CTX *ctx)
}
break;
case OID_sm2sign_with_sm3:
if ((ret = sm2_verify_update(&ctx->u.sm2_verify_ctx, ctx->sig, ctx->siglen)) < 0) {
if ((ret = sm2_verify_finish(&ctx->u.sm2_verify_ctx, ctx->sig, ctx->siglen)) < 0) {
error_print();
return -1;
}
break;
case OID_ecdsa_with_sha256:
if ((ret = ecdsa_verify_finish(&ctx->u.ecdsa_sign_ctx)) < 0) {
error_print();
return -1;
}
@@ -698,8 +786,15 @@ int x509_public_key_info_to_der(const X509_KEY *x509_key, uint8_t **out, size_t
}
break;
case OID_ec_public_key:
sm2_z256_point_to_uncompressed_octets(&x509_key->u.sm2_key.public_key, p);
keylen = 65;
if (x509_key->algor_param == OID_sm2) {
sm2_z256_point_to_uncompressed_octets(&x509_key->u.sm2_key.public_key, p);
keylen = 65;
} else if (x509_key->algor_param == OID_secp256r1) {
if (secp256r1_public_key_to_bytes(&x509_key->u.secp256r1_key, &p, &keylen) != 1) {
error_print();
return -1;
}
}
break;
default:
error_print();
@@ -758,15 +853,25 @@ int x509_public_key_info_from_der(X509_KEY *x509_key, const uint8_t **in, size_t
switch (algor) {
case OID_ec_public_key:
if (algor_param != OID_sm2) {
if (publen != 65) {
error_print();
return -1;
}
if (sm2_z256_point_from_octets(&x509_key->u.sm2_key.public_key, pub, publen) != 1) {
if (algor_param == OID_sm2) {
if (sm2_z256_point_from_octets(&x509_key->u.sm2_key.public_key, pub, publen) != 1) {
error_print();
return -1;
}
publen = 0;
} else if (algor_param == OID_secp256r1) {
if (secp256r1_public_key_from_bytes(&x509_key->u.secp256r1_key, &pub, &publen) != 1) {
error_print();
return -1;
}
} else {
error_print();
return -1;
}
publen = 0;
break;
case OID_hss_lms_hashsig:
if (hss_public_key_from_bytes(&x509_key->u.hss_key, &pub, &publen) != 1) {
@@ -806,6 +911,7 @@ int x509_public_key_info_from_der(X509_KEY *x509_key, const uint8_t **in, size_t
return 1;
}
// FIXME: this function can not parse depends on algor_param
int x509_private_key_from_file(X509_KEY *key, int algor, const char *pass, FILE *fp)
{
if (!key || !fp) {
@@ -821,6 +927,7 @@ int x509_private_key_from_file(X509_KEY *key, int algor, const char *pass, FILE
error_print();
return -1;
}
// FIXME: secp256r1
if (sm2_private_key_info_decrypt_from_pem(&key->u.sm2_key, pass, fp) != 1) {
error_print();
return -1;
@@ -901,8 +1008,12 @@ void x509_key_cleanup(X509_KEY *key)
if (key) {
switch (key->algor) {
case OID_ec_public_key:
//sm2_key_cleanup(&key->u.sm2_key);
gmssl_secure_clear(&key->u.sm2_key, sizeof(SM2_KEY));
if (key->algor_param == OID_sm2) {
//sm2_key_cleanup(&key->u.sm2_key);
gmssl_secure_clear(&key->u.sm2_key, sizeof(SM2_KEY));
} else if (key->algor_param == OID_secp256r1) {
secp256r1_key_cleanup(&key->u.secp256r1_key);
}
break;
case OID_lms_hashsig:
lms_key_cleanup(&key->u.lms_key);

128
tests/bntest.c Normal file
View File

@@ -0,0 +1,128 @@
/*
* Copyright 2014-2026 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 <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <gmssl/hex.h>
#include <gmssl/rand.h>
#include <gmssl/error.h>
#include <gmssl/bn.h>
static int test_print_consts(void)
{
// secp256r1 parameters
char *p = "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF";
char *b = "5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b";
char *x = "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296";
char *y = "4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5";
char *n = "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551";
char *u_p = "0000000100000000fffffffffffffffefffffffefffffffeffffffff0000000000000003"; // floor(2^512/p)
char *u_n = "0000000100000000fffffffffffffffeffffffff43190552df1a6c21012ffd85eedf9bfe"; // floor(2^512/n)
int k = 8;
uint32_t bn[9];
uint8_t buf[36];
size_t len;
hex_to_bytes(p, 64, buf, &len);
bn_from_bytes(bn, k, buf);
bn_print(stderr, 0, 4, "p", bn, k);
hex_to_bytes(b, 64, buf, &len);
bn_from_bytes(bn, k, buf);
bn_print(stderr, 0, 4, "a", bn, k);
hex_to_bytes(x, 64, buf, &len);
bn_from_bytes(bn, k, buf);
bn_print(stderr, 0, 4, "x", bn, k);
hex_to_bytes(y, 64, buf, &len);
bn_from_bytes(bn, k, buf);
bn_print(stderr, 0, 4, "y", bn, k);
hex_to_bytes(n, 64, buf, &len);
bn_from_bytes(bn, k, buf);
bn_print(stderr, 0, 4, "n", bn, k);
hex_to_bytes(u_p, 72, buf, &len);
bn_from_bytes(bn, k + 1, buf);
bn_print(stderr, 0, 4, "u_p = 2^512//p", bn, k + 1);
hex_to_bytes(u_n, 72, buf, &len);
bn_from_bytes(bn, k + 1, buf);
bn_print(stderr, 0, 4, "u_n = 2^512//n", bn, k + 1);
printf("%s() ok\n", __FUNCTION__);
return 1;
}
static int test_secp256r1(void)
{
char *x_hex = "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296";
char *p_hex = "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF";
int c;
uint32_t a[8];
uint32_t r[8];
uint8_t buf[32];
size_t len;
hex_to_bytes(x_hex, 64, buf, &len);
bn_from_bytes(a, 8, buf);
bn_add(r, a, a, 8);
bn_add(r, r, a, 8);
bn_print(stderr, 0, 4, "3*x", a, 8);
uint32_t p[8];
hex_to_bytes(p_hex, 64, buf, &len);
bn_from_bytes(p, 8, buf);
c = bn_sub(r, a, p, 8);
printf("carray = %d\n", c);
// 我知道了,这里有一个进位被忽略了
if (bn_cmp(a, p, 8) >= 0) {
error_print();
} else {
error_print();
}
printf("%s() ok\n", __FUNCTION__);
return 1;
}
int main(void)
{
if (test_print_consts() != 1) goto err;
if (test_secp256r1() != 1) goto err;
printf("%s all tests passed\n", __FILE__);
return 0;
err:
error_print();
return 1;
}

92
tests/ecdsatest.c Normal file
View File

@@ -0,0 +1,92 @@
/*
* Copyright 2014-2026 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 <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <gmssl/bn.h>
#include <gmssl/hex.h>
#include <gmssl/rand.h>
#include <gmssl/error.h>
#include <gmssl/ecdsa.h>
/*
d 0x5
xP 0x51590b7a515140d2d784c85608668fdfef8c82fd1f5be52421554a0dc3d033ed
yP 0xe0c17da8904a727d8ae1bf36bf8a79260d012f00d4d80888d1d0bb44fda16da4
x1 0x5ecbe4d1a6330a44c8f7ef951d4bf165e6c6b721efada985fb41661bc6e7fd6c
r 0x5ecbe4d1a6330a44c8f7ef951d4bf165e6c6b721efada985fb41661bc6e7fd6c
s 0x48a928086a55111cf99d39f886293cff41a8dda957c43b0851846697f76199ef
x1 0x5ecbe4d1a6330a44c8f7ef951d4bf165e6c6b721efada985fb41661bc6e7fd6c
v 0x5ecbe4d1a6330a44c8f7ef951d4bf165e6c6b721efada985fb41661bc6e7fd6c
*/
// 这个签名是没有问题的,看来验证签名是有问题的
static int test_ecdsa(void)
{
SECP256R1_KEY key;
ECDSA_SIGNATURE sig;
uint8_t dgst[32];
secp256r1_t d;
secp256r1_t k;
// d = 5
bn_set_word(d, 5, 8);
secp256r1_key_set_private_key(&key, d);
secp256r1_key_generate(&key);
secp256r1_private_key_print(stderr, 0, 0, "private_key", &key);
// k = 3
bn_set_word(k, 3, 8);
// e = 2
memset(dgst, 0, 31);
dgst[31] = 2;
/*
if (ecdsa_do_sign_ex(&key, k, dgst, &sig) != 1) {
error_print();
return -1;
}
*/
if (ecdsa_do_sign(&key, dgst, &sig) != 1) {
error_print();
return -1;
}
secp256r1_print(stderr, 0, 0, "r", sig.r);
secp256r1_print(stderr, 0, 0, "s", sig.s);
if (ecdsa_do_verify(&key, dgst, &sig) != 1) {
error_print();
return -1;
}
printf("%s() ok\n", __FUNCTION__);
return 1;
}
int main(void)
{
if (test_ecdsa() != 1) goto err;
printf("%s all tests passed\n", __FILE__);
return 0;
err:
error_print();
return 1;
}

292
tests/secp256r1_keytest.c Normal file
View File

@@ -0,0 +1,292 @@
/*
* Copyright 2014-2026 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 <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <gmssl/hex.h>
#include <gmssl/rand.h>
#include <gmssl/error.h>
#include <gmssl/secp256r1_key.h>
static int test_secp256r1_key_generate(void)
{
SECP256R1_KEY key;
if (secp256r1_key_generate(&key) != 1) {
error_print();
return -1;
}
secp256r1_public_key_print(stderr, 0, 4, "public_key", &key);
secp256r1_private_key_print(stderr, 0, 4, "private_key", &key);
secp256r1_key_cleanup(&key);
secp256r1_private_key_print(stderr, 0, 4, "private_key", &key);
printf("%s() ok\n", __FUNCTION__);
return 1;
}
static int test_secp256r1_key_set_private_key(void)
{
SECP256R1_KEY key;
secp256r1_t private_key;
uint8_t bytes[32];
size_t len;
// key = 1
memset(bytes, 0, sizeof(bytes));
bytes[31] = 1;
secp256r1_from_32bytes(private_key, bytes);
if (secp256r1_key_set_private_key(&key, private_key) != 1) {
error_print();
return -1;
}
secp256r1_private_key_print(stderr, 0, 4, "private_key = 1", &key);
// key = n-1
hex_to_bytes("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632550", 64, bytes, &len);
secp256r1_from_32bytes(private_key, bytes);
if (secp256r1_key_set_private_key(&key, private_key) != 1) {
error_print();
return -1;
}
// key = 0, should fail
memset(bytes, 0, sizeof(bytes));
secp256r1_from_32bytes(private_key, bytes);
if (secp256r1_key_set_private_key(&key, private_key) >= 0) {
error_print();
return -1;
}
// key = n, should fail
hex_to_bytes("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551", 64, bytes, &len);
secp256r1_from_32bytes(private_key, bytes);
if (secp256r1_key_set_private_key(&key, private_key) >= 0) {
error_print();
return -1;
}
// key = 0xff..f, should fail
memset(bytes, 0xff, sizeof(bytes));
secp256r1_from_32bytes(private_key, bytes);
if (secp256r1_key_set_private_key(&key, private_key) >= 0) {
error_print();
return -1;
}
printf("%s() ok\n", __FUNCTION__);
return 1;
}
static int test_secp256r1_public_key_to_bytes(void)
{
SECP256R1_KEY key;
SECP256R1_KEY key1;
uint8_t bytes[512];
uint8_t *p = bytes;
const uint8_t *cp = bytes;
size_t len = 0;
if (secp256r1_key_generate(&key) != 1) {
error_print();
return -1;
}
if (secp256r1_public_key_to_bytes(&key, &p, &len) != 1) {
error_print();
return -1;
}
if (secp256r1_public_key_from_bytes(&key1, &cp, &len) != 1) {
error_print();
return -1;
}
if (len) {
error_print();
return -1;
}
if (secp256r1_public_key_equ(&key, &key1) != 1) {
error_print();
return -1;
}
printf("%s() ok\n", __FUNCTION__);
return 1;
}
static int test_secp256r1_public_key_to_der(void)
{
SECP256R1_KEY key;
SECP256R1_KEY key1;
uint8_t bytes[512];
uint8_t *p = bytes;
const uint8_t *cp = bytes;
size_t len = 0;
if (secp256r1_key_generate(&key) != 1) {
error_print();
return -1;
}
if (secp256r1_public_key_to_der(&key, &p, &len) != 1) {
error_print();
return -1;
}
if (secp256r1_public_key_from_der(&key1, &cp, &len) != 1) {
error_print();
return -1;
}
if (len) {
error_print();
return -1;
}
if (secp256r1_public_key_equ(&key, &key1) != 1) {
error_print();
return -1;
}
printf("%s() ok\n", __FUNCTION__);
return 1;
}
static int test_secp256r1_private_key_to_der(void)
{
SECP256R1_KEY key;
SECP256R1_KEY key1;
uint8_t bytes[512];
uint8_t *p = bytes;
const uint8_t *cp = bytes;
size_t len = 0;
if (secp256r1_key_generate(&key) != 1) {
error_print();
return -1;
}
if (secp256r1_private_key_to_der(&key, &p, &len) != 1) {
error_print();
return -1;
}
if (secp256r1_private_key_from_der(&key1, &cp, &len) != 1) {
error_print();
return -1;
}
if (len) {
error_print();
return -1;
}
if (secp256r1_public_key_equ(&key, &key1) != 1) {
error_print();
return -1;
}
printf("%s() ok\n", __FUNCTION__);
return 1;
}
static int test_secp256r1_private_key_info_to_der(void)
{
SECP256R1_KEY key;
SECP256R1_KEY key1;
uint8_t bytes[512];
uint8_t *p = bytes;
const uint8_t *cp = bytes;
size_t len = 0;
const uint8_t *attrs;
size_t attrslen;
if (secp256r1_key_generate(&key) != 1) {
error_print();
return -1;
}
if (secp256r1_private_key_info_to_der(&key, &p, &len) != 1) {
error_print();
return -1;
}
if (secp256r1_private_key_info_from_der(&key1, &attrs, &attrslen, &cp, &len) != 1) {
error_print();
return -1;
}
if (len) {
error_print();
return -1;
}
if (secp256r1_public_key_equ(&key, &key1) != 1) {
error_print();
return -1;
}
printf("%s() ok\n", __FUNCTION__);
return 1;
}
static int test_secp256r1_private_key_info_encrypt_to_der(void)
{
SECP256R1_KEY key;
SECP256R1_KEY key1;
uint8_t bytes[512];
uint8_t *p = bytes;
const uint8_t *cp = bytes;
size_t len = 0;
char *pass = "password";
const uint8_t *attrs;
size_t attrslen;
if (secp256r1_key_generate(&key) != 1) {
error_print();
return -1;
}
if (secp256r1_private_key_info_encrypt_to_der(&key, pass, &p, &len) != 1) {
error_print();
return -1;
}
if (secp256r1_private_key_info_decrypt_from_der(&key1, &attrs, &attrslen, pass, &cp, &len) != 1) {
error_print();
return -1;
}
if (len) {
error_print();
return -1;
}
if (secp256r1_public_key_equ(&key, &key1) != 1) {
error_print();
return -1;
}
printf("%s() ok\n", __FUNCTION__);
return 1;
}
int main(void)
{
if (test_secp256r1_key_generate() != 1) goto err;
// if (test_secp256r1_key_set_private_key() != 1) goto err;
if (test_secp256r1_public_key_to_bytes() != 1) goto err;
if (test_secp256r1_public_key_to_der() != 1) goto err;
if (test_secp256r1_private_key_to_der() != 1) goto err;
if (test_secp256r1_private_key_info_to_der() != 1) goto err;
if (test_secp256r1_private_key_info_encrypt_to_der() != 1) goto err;
printf("%s all tests passed\n", __FILE__);
return 0;
err:
error_print();
return 1;
}

481
tests/secp256r1test.c Normal file
View File

@@ -0,0 +1,481 @@
/*
* Copyright 2014-2026 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 <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <gmssl/hex.h>
#include <gmssl/rand.h>
#include <gmssl/error.h>
#include <gmssl/secp256r1.h>
static const char *secp256r1_p = "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF";
static const char *secp256r1_b = "5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b";
static const char *secp256r1_x = "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296";
static const char *secp256r1_y = "4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5";
static const char *secp256r1_n = "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551";
static int test_secp256r1(void)
{
secp256r1_t a;
secp256r1_t b;
secp256r1_t r;
uint8_t buf[32];
secp256r1_set_zero(a);
if (!secp256r1_is_zero(a)) {
error_print();
return -1;
}
secp256r1_to_32bytes(a, buf);
format_bytes(stderr, 0, 4, "0", buf, sizeof(buf));
secp256r1_set_one(b);
if (!secp256r1_is_one(b)) {
error_print();
return -1;
}
secp256r1_to_32bytes(b, buf);
format_bytes(stderr, 0, 4, "1", buf, sizeof(buf));
if (secp256r1_cmp(a, b) >= 0) {
error_print();
return -1;
}
printf("%s() ok\n", __FUNCTION__);
return 1;
}
// 这个测试是有问题的mod_add很多情况下是引发进位和借位的
static int test_secp256r1_modp(void)
{
secp256r1_t x;
secp256r1_t y;
secp256r1_t r;
secp256r1_t v;
uint8_t buf[32];
size_t len;
hex_to_bytes("6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", 64, buf, &len);
secp256r1_from_32bytes(x, buf);
hex_to_bytes("4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5", 64, buf, &len);
secp256r1_from_32bytes(y, buf);
secp256r1_modp_add(r, x, y);
hex_to_bytes("bafb14d5df46c1e387a4d22fdfb3df08a2d1b0d8991c926fc05779ae1058148b", 64, buf, &len);
secp256r1_from_32bytes(v, buf);
if (secp256r1_cmp(r, v) != 0) {
error_print();
return -1;
}
secp256r1_modp_dbl(r, x);
hex_to_bytes("d62fa3e5c258848ff179cdcac74881e4ee06fb025bd66741e942728bb131852c", 64, buf, &len);
secp256r1_from_32bytes(v, buf);
if (secp256r1_cmp(r, v) != 0) {
error_print();
return -1;
}
secp256r1_modp_tri(r, x);
hex_to_bytes("414775d9a384c6d6ea36b4b02aecc2d7650a788289c19ae2dde3abd189ca47c3", 64, buf, &len);
secp256r1_from_32bytes(v, buf);
if (secp256r1_cmp(r, v) != 0) {
error_print();
return -1;
}
secp256r1_modp_sub(r, x, y);
hex_to_bytes("1b348f0fe311c2ac69d4fb9ae794a2dc4b354a29c2b9d4d228eaf8dda0d970a1", 64, buf, &len);
secp256r1_from_32bytes(v, buf);
if (secp256r1_cmp(r, v) != 0) {
error_print();
return -1;
}
secp256r1_modp_sub(r, y, x);
hex_to_bytes("e4cb70ef1cee3d54962b0465186b5d23b4cab5d73d462b2dd71507225f268f5e", 64, buf, &len);
secp256r1_from_32bytes(v, buf);
if (secp256r1_cmp(r, v) != 0) {
error_print();
return -1;
}
secp256r1_modp_neg(r, x);
hex_to_bytes("94e82e0c1ed3bdb90743191a9c5bbf0d88fc827fd214cc5f0b5ec6ba27673d69", 64, buf, &len);
secp256r1_from_32bytes(v, buf);
if (secp256r1_cmp(r, v) != 0) {
error_print();
return -1;
}
secp256r1_modp_mul(r, x, y);
hex_to_bytes("823cd15f6dd3c71933565064513a6b2bd183e554c6a08622f713ebbbface98be", 64, buf, &len);
secp256r1_from_32bytes(v, buf);
if (secp256r1_cmp(r, v) != 0) {
error_print();
return -1;
}
secp256r1_modp_sqr(r, x);
hex_to_bytes("98f6b84d29bef2b281819a5e0e3690d833b699495d694dd1002ae56c426b3f8c", 64, buf, &len);
secp256r1_from_32bytes(v, buf);
if (secp256r1_cmp(r, v) != 0) {
error_print();
return -1;
}
secp256r1_modp_exp(r, x, y);
hex_to_bytes("2f3db69bc9d93323c351f3e768d332806ad3a7652ea632e89e23312f7b5f9f96", 64, buf, &len);
secp256r1_from_32bytes(v, buf);
if (secp256r1_cmp(r, v) != 0) {
error_print();
return -1;
}
secp256r1_modp_inv(r, x);
hex_to_bytes("e060cbb088706d5d24936933b69b16ab707d656273744b65664c49e577f35238", 64, buf, &len);
secp256r1_from_32bytes(v, buf);
if (secp256r1_cmp(r, v) != 0) {
error_print();
return -1;
}
secp256r1_modp_inv(r, y);
hex_to_bytes("fa27a3da2c00618a828f8cd65c1a919effc67bf68b4dbb05bbdaa775c45d4034", 64, buf, &len);
secp256r1_from_32bytes(v, buf);
if (secp256r1_cmp(r, v) != 0) {
error_print();
return -1;
}
printf("%s() ok\n", __FUNCTION__);
return 1;
}
static int test_secp256r1_modn(void)
{
secp256r1_t x;
secp256r1_t y;
secp256r1_t r;
secp256r1_t v;
uint8_t buf[32];
size_t len;
hex_to_bytes("d62fa3e5c258848ff179cdcac74881e4ee06fb025bd66741e942728bb131852c", 64, buf, &len);
secp256r1_from_32bytes(x, buf);
hex_to_bytes("4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5", 64, buf, &len);
secp256r1_from_32bytes(y, buf);
secp256r1_modn_add(r, x, y);
hex_to_bytes("2612e6c9c073042a8061b91543581ffb5cee33ac1ff0278bc13ee830ec8db1d0", 64, buf, &len);
secp256r1_from_32bytes(v, buf);
if (secp256r1_cmp(r, v) != 0) {
error_print();
return -1;
}
secp256r1_modn_dbl(r, x);
hex_to_bytes("ac5f47cc84b1091ee2f39b958e9103ca1f26fb5710952ffedecb1a5465ffe507", 64, buf, &len);
secp256r1_from_32bytes(v, buf);
if (secp256r1_cmp(r, v) != 0) {
error_print();
return -1;
}
secp256r1_modn_tri(r, x);
hex_to_bytes("828eebb347098dadd46d696055d985af5046fbabc553f8bbd453c21d1ace44e2", 64, buf, &len);
secp256r1_from_32bytes(v, buf);
if (secp256r1_cmp(r, v) != 0) {
error_print();
return -1;
}
secp256r1_modn_sub(r, x, y);
hex_to_bytes("864c6102c43e04f46291e2804b38e3cec238c7aaf0a508731d8c322379723337", 64, buf, &len);
secp256r1_from_32bytes(v, buf);
if (secp256r1_cmp(r, v) != 0) {
error_print();
return -1;
}
secp256r1_modn_sub(r, y, x);
hex_to_bytes("79b39efc3bc1fb0c9d6e1d7fb4c71c30faae3302b6729611d62d989f82f0f21a", 64, buf, &len);
secp256r1_from_32bytes(v, buf);
if (secp256r1_cmp(r, v) != 0) {
error_print();
return -1;
}
secp256r1_modn_neg(r, x);
hex_to_bytes("29d05c193da77b710e86323538b77e1acedfffab4b4137430a7758374b31a025", 64, buf, &len);
secp256r1_from_32bytes(v, buf);
if (secp256r1_cmp(r, v) != 0) {
error_print();
return -1;
}
secp256r1_modn_mul(r, x, y);
hex_to_bytes("2a876a4e5df28cd6c2f3951aa6b65c55e2d6eb1883b463aee5d95035999c9a30", 64, buf, &len);
secp256r1_from_32bytes(v, buf);
if (secp256r1_cmp(r, v) != 0) {
error_print();
return -1;
}
secp256r1_modn_mul(r, y, x);
hex_to_bytes("2a876a4e5df28cd6c2f3951aa6b65c55e2d6eb1883b463aee5d95035999c9a30", 64, buf, &len);
secp256r1_from_32bytes(v, buf);
if (secp256r1_cmp(r, v) != 0) {
error_print();
return -1;
}
secp256r1_modn_sqr(r, x);
hex_to_bytes("22f25cab8043b82c9a5a6f0ca72c2122700737b557a11ba95ee80bddf671471f", 64, buf, &len);
secp256r1_from_32bytes(v, buf);
if (secp256r1_cmp(r, v) != 0) {
error_print();
return -1;
}
secp256r1_modn_exp(r, x, y);
hex_to_bytes("31e8d728b341541057e09242800bcd7321b523284104340f3ac3bedb55b516c7", 64, buf, &len);
secp256r1_from_32bytes(v, buf);
if (secp256r1_cmp(r, v) != 0) {
error_print();
return -1;
}
secp256r1_modn_inv(r, x);
hex_to_bytes("a546ddb0e12a46eedab8425e77558aa3e56b7fec1d73fd94c03235e2f2298172", 64, buf, &len);
secp256r1_from_32bytes(v, buf);
if (secp256r1_cmp(r, v) != 0) {
error_print();
return -1;
}
printf("%s() ok\n", __FUNCTION__);
return 1;
}
static int test_secp256r1_point_at_infinity(void)
{
SECP256R1_POINT P;
secp256r1_point_set_infinity(&P);
if (!secp256r1_point_is_at_infinity(&P)) {
error_print();
return -1;
}
secp256r1_point_print(stderr, 0, 4, "point_at_infinity", &P);
if (!secp256r1_point_is_on_curve(&P)) {
error_print();
return -1;
}
printf("%s() ok\n", __FUNCTION__);
return 1;
}
static int test_secp256r1_point_set_xy(void)
{
SECP256R1_POINT P;
secp256r1_t x;
secp256r1_t y;
secp256r1_t x1;
secp256r1_t y1;
uint8_t bytes[32];
size_t len;
hex_to_bytes(secp256r1_x, 64, bytes, &len);
secp256r1_from_32bytes(x, bytes);
hex_to_bytes(secp256r1_y, 64, bytes, &len);
secp256r1_from_32bytes(y, bytes);
if (secp256r1_point_set_xy(&P, x, y) != 1) {
error_print();
return -1;
}
secp256r1_point_get_xy(&P, x1, y1);
if (secp256r1_cmp(x, x1) != 0
|| secp256r1_cmp(y, y1) != 0) {
error_print();
return -1;
}
printf("%s() ok\n", __FUNCTION__);
return 1;
}
static int test_secp256r1_point_is_on_curve(void)
{
if (secp256r1_point_is_on_curve(&SECP256R1_POINT_G) != 1) {
error_print();
return -1;
}
printf("%s() ok\n", __FUNCTION__);
return 1;
}
// 这两个计算是应该分开的!
static int test_secp256r1_point_dbl_add(void)
{
SECP256R1_POINT P;
SECP256R1_POINT Q;
secp256r1_t x;
secp256r1_t y;
secp256r1_t x1;
secp256r1_t y1;
uint8_t bytes[32];
size_t len;
// test 2*G
secp256r1_point_dbl(&P, &SECP256R1_POINT_G);
secp256r1_point_get_xy(&P, x, y);
secp256r1_point_print(stderr, 0, 4, "2*G", &P);
hex_to_bytes("7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978", 64, bytes, &len);
secp256r1_from_32bytes(x1, bytes);
hex_to_bytes("07775510db8ed040293d9ac69f7430dbba7dade63ce982299e04b79d227873d1", 64, bytes, &len);
secp256r1_from_32bytes(y1, bytes);
if (secp256r1_cmp(x, x1) != 0 || secp256r1_cmp(y, y1) != 0) {
error_print();
return -1;
}
// test 2*G + G
secp256r1_point_add(&Q, &P, &SECP256R1_POINT_G);
secp256r1_point_get_xy(&Q, x, y);
hex_to_bytes("5ecbe4d1a6330a44c8f7ef951d4bf165e6c6b721efada985fb41661bc6e7fd6c", 64, bytes, &len);
secp256r1_from_32bytes(x1, bytes);
hex_to_bytes("8734640c4998ff7e374b06ce1a64a2ecd82ab036384fb83d9a79b127a27d5032", 64, bytes, &len);
secp256r1_from_32bytes(y1, bytes);
if (secp256r1_cmp(x, x1) != 0 || secp256r1_cmp(y, y1) != 0) {
error_print();
return -1;
}
printf("%s() ok\n", __FUNCTION__);
return 1;
}
static const char *secp256r1_x_2G = "7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978";
static const char *secp256r1_y_2G = "07775510db8ed040293d9ac69f7430dbba7dade63ce982299e04b79d227873d1";
static const char *secp256r1_x_3G = "5ecbe4d1a6330a44c8f7ef951d4bf165e6c6b721efada985fb41661bc6e7fd6c";
static const char *secp256r1_y_3G = "8734640c4998ff7e374b06ce1a64a2ecd82ab036384fb83d9a79b127a27d5032";
static int test_secp256r1_point_mul(void)
{
SECP256R1_POINT P;
secp256r1_t x;
secp256r1_t y;
secp256r1_t x1;
secp256r1_t y1;
secp256r1_t k;
uint8_t bytes[32] = {0};
size_t len;
// k = 3
bytes[31] = 3;
secp256r1_from_32bytes(k, bytes);
secp256r1_point_mul_generator(&P, k);
secp256r1_point_get_xy(&P, x, y); // 这个必须返回错误啊,否则没办法判断是否为无穷远点呢!
hex_to_bytes(secp256r1_x_3G, 64, bytes, &len);
secp256r1_from_32bytes(x1, bytes);
hex_to_bytes(secp256r1_y_3G, 64, bytes, &len);
secp256r1_from_32bytes(y1, bytes);
if (secp256r1_cmp(x, x1) != 0 || secp256r1_cmp(y, y1) != 0) {
error_print();
return -1;
}
// k = n
hex_to_bytes(secp256r1_n, 64, bytes, &len);
secp256r1_from_32bytes(k, bytes);
secp256r1_point_mul_generator(&P, k);
if (secp256r1_point_is_at_infinity(&P) != 1) {
error_print();
return -1;
}
printf("%s() ok\n", __FUNCTION__);
return 1;
}
static int test_secp256r1_point_to_uncompressed_octets(void)
{
SECP256R1_POINT P;
uint8_t octets[65];
secp256r1_point_copy(&P, &SECP256R1_POINT_G);
if (secp256r1_point_to_uncompressed_octets(&P, octets) != 1) {
error_print();
return -1;
}
if (secp256r1_point_from_uncompressed_octets(&P, octets) != 1) {
error_print();
return -1;
}
printf("%s() ok\n", __FUNCTION__);
return 1;
}
int main(void)
{
if (test_secp256r1() != 1) goto err;
if (test_secp256r1_modp() != 1) goto err;
if (test_secp256r1_modn() != 1) goto err;
if (test_secp256r1_point_at_infinity() != 1) goto err;
if (test_secp256r1_point_is_on_curve() != 1) goto err;
if (test_secp256r1_point_set_xy() != 1) goto err;
if (test_secp256r1_point_dbl_add() != 1) goto err;
if (test_secp256r1_point_mul() != 1) goto err;
if (test_secp256r1_point_to_uncompressed_octets() != 1) goto err;
printf("%s all tests passed\n", __FILE__);
return 0;
err:
error_print();
return 1;
}