From b58eb671d5804572a187c6e100f46a66ca446f21 Mon Sep 17 00:00:00 2001 From: Zhi Guan Date: Sun, 4 Jan 2026 09:59:29 +0800 Subject: [PATCH] Update Kyber --- CMakeLists.txt | 18 +-- include/gmssl/kyber.h | 68 +++++++--- src/kyber.c | 306 ++++++++++++++++++++++++++++++++---------- tests/kybertest.c | 135 ++++++++++++++++++- tools/gmssl.c | 18 +++ tools/kyberdecap.c | 171 +++++++++++++++++++++++ tools/kyberencap.c | 165 +++++++++++++++++++++++ tools/kyberkeygen.c | 129 ++++++++++++++++++ 8 files changed, 907 insertions(+), 103 deletions(-) create mode 100644 tools/kyberdecap.c create mode 100644 tools/kyberencap.c create mode 100644 tools/kyberkeygen.c diff --git a/CMakeLists.txt b/CMakeLists.txt index a68dea58..8991eec5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,7 +54,7 @@ option(ENABLE_SM4_CBC_MAC "Enable SM4-CBC-MAC" ON) option(ENABLE_SM2_EXTS "Enable SM2 Extensions" OFF) option(ENABLE_LMS_HSS "Enable LMS/HSS signature" ON) -option(ENABLE_XMSS "Enable XMSS/XMSS^MT signature" OFF) +option(ENABLE_XMSS "Enable XMSS/XMSS^MT signature" ON) option(ENABLE_SHA1 "Enable SHA1" ON) @@ -448,6 +448,15 @@ if (ENABLE_XMSS) endif() +if (ENABLE_KYBER) + message(STATUS "ENABLE_KYBER is ON") + add_definitions(-DENABLE_KYBER) + list(APPEND src src/kyber.c) + list(APPEND tools tools/kyberkeygen.c tools/kyberencap.c tools/kyberdecap.c) + list(APPEND tests kyber) +endif() + + if (ENABLE_SHA1) message(STATUS "ENABLE_SHA1 is ON") add_definitions(-DENABLE_SHA1) @@ -478,13 +487,6 @@ if (ENABLE_CHACHA20) endif() -if (ENABLE_KYBER) - message(STATUS "ENABLE_KYBER is ON") - list(APPEND src src/kyber.c) - list(APPEND tests kyber) -endif() - - if (ENABLE_INTEL_RDRAND) include(CheckSourceCompiles) set(CMAKE_REQUIRED_FLAGS "-rdrand") diff --git a/include/gmssl/kyber.h b/include/gmssl/kyber.h index ced52a5c..9e130f4a 100644 --- a/include/gmssl/kyber.h +++ b/include/gmssl/kyber.h @@ -15,12 +15,6 @@ #include #include #include -#include -#include -#include -#include -#include -#include #ifdef __cplusplus @@ -79,7 +73,6 @@ CRYSTALS-Kyber Algorithm Specifications and Supporing Documentation (version 3.0 */ - typedef int16_t kyber_poly_t[256]; typedef struct { @@ -88,6 +81,7 @@ typedef struct { } KYBER_CPA_PUBLIC_KEY; typedef struct { + KYBER_CPA_PUBLIC_KEY public_key; uint8_t s[KYBER_K][384]; } KYBER_CPA_PRIVATE_KEY; @@ -96,19 +90,13 @@ typedef struct { uint8_t c2[KYBER_C2_SIZE]; } KYBER_CPA_CIPHERTEXT; +int kyber_cpa_public_key_to_bytes(const KYBER_CPA_PUBLIC_KEY *key, uint8_t **out, size_t *outlen); +int kyber_cpa_public_key_from_bytes(KYBER_CPA_PUBLIC_KEY *key, const uint8_t **in, size_t *inlen); +int kyber_cpa_private_key_to_bytes(const KYBER_CPA_PRIVATE_KEY *key, uint8_t **out, size_t *outlen); +int kyber_cpa_private_key_from_bytes(KYBER_CPA_PRIVATE_KEY *key, const uint8_t **in, size_t *inlen); -typedef KYBER_CPA_PUBLIC_KEY KYBER_PUBLIC_KEY; - -typedef struct { - KYBER_CPA_PRIVATE_KEY sk; - KYBER_CPA_PUBLIC_KEY pk; - uint8_t pk_hash[32]; - uint8_t z[32]; -} KYBER_PRIVATE_KEY; - -typedef KYBER_CPA_CIPHERTEXT KYBER_CIPHERTEXT; - - +int kyber_cpa_ciphertext_to_bytes(const KYBER_CPA_CIPHERTEXT *ciphertext, uint8_t **out, size_t *outlen); +int kyber_cpa_ciphertext_from_bytes(KYBER_CPA_CIPHERTEXT *ciphertext, const uint8_t **in, size_t *inlen); void kyber_h_hash(const uint8_t *in, size_t inlen, uint8_t out[32]); void kyber_g_hash(const uint8_t *in, size_t inlen, uint8_t out[64]); @@ -165,18 +153,56 @@ int kyber_poly_encode1(const kyber_poly_t a, uint8_t out[32]); int kyber_cpa_keygen(KYBER_CPA_PUBLIC_KEY *pk, KYBER_CPA_PRIVATE_KEY *sk); int kyber_cpa_ciphertext_print(FILE *fp, int fmt, int ind, const char *label, const KYBER_CPA_CIPHERTEXT *c); -int kyber_ciphertext_print(FILE *fp, int fmt, int ind, const char *label, const KYBER_CPA_CIPHERTEXT *c); +int kyber_cpa_ciphertext_print(FILE *fp, int fmt, int ind, const char *label, const KYBER_CPA_CIPHERTEXT *c); int kyber_cpa_public_key_print(FILE *fp, int fmt, int ind, const char *label, const KYBER_CPA_PUBLIC_KEY *pk); int kyber_cpa_private_key_print(FILE *fp, int fmt, int ind, const char *label, const KYBER_CPA_PRIVATE_KEY *sk); int kyber_cpa_encrypt(const KYBER_CPA_PUBLIC_KEY *pk, const uint8_t in[32], const uint8_t rand[32], KYBER_CPA_CIPHERTEXT *out); int kyber_cpa_decrypt(const KYBER_CPA_PRIVATE_KEY *sk, const KYBER_CPA_CIPHERTEXT *in, uint8_t out[32]); + + +typedef KYBER_CPA_PUBLIC_KEY KYBER_PUBLIC_KEY; + + +typedef struct { + KYBER_CPA_PUBLIC_KEY pk; + KYBER_CPA_PRIVATE_KEY sk; + uint8_t pk_hash[32]; + uint8_t z[32]; +} KYBER_PRIVATE_KEY; + + +#define KYBER_PUBLIC_KEY_SIZE sizeof(KYBER_PUBLIC_KEY) +#define KYBER_PRIVATE_KEY_SIZE sizeof(KYBER_PRIVATE_KEY) + + + +typedef KYBER_CPA_CIPHERTEXT KYBER_CIPHERTEXT; + +int kyber_ciphertext_print(FILE *fp, int fmt, int ind, const char *label, const KYBER_CIPHERTEXT *c); + +int kyber_ciphertext_to_bytes(const KYBER_CIPHERTEXT *ciphertext, uint8_t **out, size_t *outlen); +int kyber_ciphertext_from_bytes(KYBER_CIPHERTEXT *ciphertext, const uint8_t **in, size_t *inlen); + +void kyber_key_cleanup(KYBER_PRIVATE_KEY *key); + +int kyber_key_generate(KYBER_PRIVATE_KEY *key); + +// generate a single key int kyber_keygen(KYBER_PUBLIC_KEY *pk, KYBER_PRIVATE_KEY *sk); + + int kyber_private_key_print(FILE *fp, int fmt, int ind, const char *label, const KYBER_PRIVATE_KEY *sk); -int kyber_public_key_print(FILE *fp, int fmt, int ind, const char *label, const KYBER_PUBLIC_KEY *pk); + +int kyber_public_key_print(FILE *fp, int fmt, int ind, const char *label, const KYBER_PRIVATE_KEY *pk); int kyber_encap(const KYBER_PUBLIC_KEY *pk, KYBER_CIPHERTEXT *c, uint8_t K[32]); int kyber_decap(const KYBER_PRIVATE_KEY *sk, const KYBER_CIPHERTEXT *c, uint8_t K[32]); +int kyber_public_key_to_bytes(const KYBER_PRIVATE_KEY *key, uint8_t **out, size_t *outlen); +int kyber_public_key_from_bytes(KYBER_PRIVATE_KEY *key, const uint8_t **in, size_t *inlen); +int kyber_private_key_to_bytes(const KYBER_PRIVATE_KEY *key, uint8_t **out, size_t *outlen); +int kyber_private_key_from_bytes(KYBER_PRIVATE_KEY *key, const uint8_t **in, size_t *inlen); + #ifdef __cplusplus } diff --git a/src/kyber.c b/src/kyber.c index 540a78f9..6dc063ca 100644 --- a/src/kyber.c +++ b/src/kyber.c @@ -17,42 +17,9 @@ #include #include #include +#include -#define KYBER_Q 3329 -#define KYBER_ZETA 17 -#define KYBER_N 256 -#define KYBER_ETA2 2 -#define KYBER_POLY_NBYTES (256 * 12 / 8) - -#define KYBER512_K 2 -#define KYBER768_K 3 -#define KYBER1024_K 4 - -#define KYBER512_ETA1 3 -#define KYBER768_ETA1 2 -#define KYBER1024_ETA1 2 - -#define KYBER512_DU 10 -#define KYBER768_DU 10 -#define KYBER1024_DU 11 - -#define KYBER512_DV 4 -#define KYBER769_DV 4 -#define KYBER1024_DV 5 - -#define KYBER_K KYBER512_K -#define KYBER_ETA1 KYBER512_ETA1 -#define KYBER_DU KYBER512_DU -#define KYBER_DV KYBER512_DV - - -#define KYBER_C1_SIZE ((256 * KYBER_DU)/8) -#define KYBER_C2_SIZE ((256 * KYBER_DV)/8) - - -#define KYBER_TEST - /* CRYSTALS-Kyber Algorithm Specifications and Supporing Documentation (version 3.02) @@ -70,35 +37,6 @@ CRYSTALS-Kyber Algorithm Specifications and Supporing Documentation (version 3.0 -typedef int16_t kyber_poly_t[256]; - -typedef struct { - uint8_t t[KYBER_K][384]; - uint8_t rho[32]; -} KYBER_CPA_PUBLIC_KEY; - -typedef struct { - uint8_t s[KYBER_K][384]; -} KYBER_CPA_PRIVATE_KEY; - -typedef struct { - uint8_t c1[KYBER_K][KYBER_C1_SIZE]; - uint8_t c2[KYBER_C2_SIZE]; -} KYBER_CPA_CIPHERTEXT; - - -typedef KYBER_CPA_PUBLIC_KEY KYBER_PUBLIC_KEY; - -typedef struct { - KYBER_CPA_PRIVATE_KEY sk; - KYBER_CPA_PUBLIC_KEY pk; - uint8_t pk_hash[32]; - uint8_t z[32]; -} KYBER_PRIVATE_KEY; - -typedef KYBER_CPA_CIPHERTEXT KYBER_CIPHERTEXT; - - void kyber_h_hash(const uint8_t *in, size_t inlen, uint8_t out[32]) { @@ -151,9 +89,6 @@ static int kyber_kdf(const uint8_t in[64], uint8_t out[32]) return 1; } -#define KYBER_FMT_POLY 1 -#define KYBER_FMT_HEX 2 - int kyber_poly_print(FILE *fp, int fmt, int ind, const char *label, const kyber_poly_t a) { int i; @@ -663,10 +598,100 @@ int kyber_poly_encode1(const kyber_poly_t a, uint8_t out[32]) return 1; } +/* + 78 typedef struct { + 79 uint8_t t[KYBER_K][384]; + 80 uint8_t rho[32]; + 81 } KYBER_CPA_PUBLIC_KEY; + 82 + 83 typedef struct { + 84 // should add public key + 85 uint8_t s[KYBER_K][384]; + 86 } KYBER_CPA_PRIVATE_KEY; +*/ +int kyber_cpa_public_key_to_bytes(const KYBER_CPA_PUBLIC_KEY *key, uint8_t **out, size_t *outlen) +{ + if (!key || !outlen) { + error_print(); + return -1; + } + if (out && *out) { + memcpy(*out, key->t, sizeof(key->t)); + *out += sizeof(key->t); + memcpy(*out, key->rho, sizeof(key->rho)); + *out += sizeof(key->rho); + } + *outlen += sizeof(key->t); + *outlen += sizeof(key->rho); + return 1; +} +int kyber_cpa_public_key_from_bytes(KYBER_CPA_PUBLIC_KEY *key, const uint8_t **in, size_t *inlen) +{ + if (!key || !in || !(*in) || !inlen) { + error_print(); + return -1; + } + if (*inlen < sizeof(key->t) + sizeof(key->rho)) { + error_print(); + return -1; + } + memset(key, 0, sizeof(*key)); + memcpy(key->t, *in, sizeof(key->t)); + *in += sizeof(key->t); + *inlen -= sizeof(key->t); + memcpy(key->rho, *in, sizeof(key->rho)); + *in += sizeof(key->rho); + *inlen -= sizeof(key->rho); + return 1; +} +int kyber_cpa_private_key_to_bytes(const KYBER_CPA_PRIVATE_KEY *key, uint8_t **out, size_t *outlen) +{ + if (!key || !outlen) { + error_print(); + return -1; + } + if (kyber_cpa_public_key_to_bytes(&key->public_key, out, outlen) != 1) { + error_print(); + return -1; + } + if (out && *out) { + memcpy(*out, key->s, sizeof(key->s)); + } + *outlen += sizeof(key->s); + return 1; +} +int kyber_cpa_private_key_from_bytes(KYBER_CPA_PRIVATE_KEY *key, const uint8_t **in, size_t *inlen) +{ + if (!key || !in || !(*in) || !inlen) { + error_print(); + return -1; + } + /* + if (*inlen < sizeof(key->s)) { + error_print(); + return -1; + } + */ + memset(key, 0, sizeof(*key)); + if (kyber_cpa_public_key_from_bytes(&key->public_key, in, inlen) != 1) { + error_print(); + return -1; + } + memcpy(key->s, *in, sizeof(key->s)); + *in += sizeof(key->s); + *inlen -= sizeof(key->s); + return 1; +} + +int kyber_cpa_key_generate(KYBER_CPA_PRIVATE_KEY *key) +{ + kyber_cpa_keygen(&key->public_key, key); + return 1; +} int kyber_cpa_keygen(KYBER_CPA_PUBLIC_KEY *pk, KYBER_CPA_PRIVATE_KEY *sk) { @@ -680,6 +705,7 @@ int kyber_cpa_keygen(KYBER_CPA_PUBLIC_KEY *pk, KYBER_CPA_PRIVATE_KEY *sk) uint8_t N = 0; int i,j; + // 应该支持这个函数是由确定的值导出的 if (rand_bytes(d, 32) != 1) { error_print(); return -1; @@ -778,7 +804,7 @@ int kyber_cpa_ciphertext_print(FILE *fp, int fmt, int ind, const char *label, co return 1; } -int kyber_ciphertext_print(FILE *fp, int fmt, int ind, const char *label, const KYBER_CPA_CIPHERTEXT *c) +int kyber_ciphertext_print(FILE *fp, int fmt, int ind, const char *label, const KYBER_CIPHERTEXT *c) { return kyber_cpa_ciphertext_print(fp, fmt, ind, label, c); } @@ -804,6 +830,9 @@ int kyber_cpa_private_key_print(FILE *fp, int fmt, int ind, const char *label, c int i; format_print(fp, fmt, ind, "%s\n", label); ind += 4; + + kyber_cpa_public_key_print(fp, fmt, ind, "public_key", &sk->public_key); + for (i = 0; i < KYBER_K; i++) { format_print(fp, fmt, ind, "ntt(s[%d])", i); format_bytes(fp, fmt, 0, "", sk->s[i], 384); @@ -974,6 +1003,96 @@ int kyber_cpa_decrypt(const KYBER_CPA_PRIVATE_KEY *sk, const KYBER_CPA_CIPHERTEX return 1; } + +int kyber_key_generate(KYBER_PRIVATE_KEY *sk) +{ + KYBER_PUBLIC_KEY pk; + if (kyber_keygen(&pk, sk) != 1) { + error_print(); + return -1; + } + return 1; +} + +void kyber_key_cleanup(KYBER_PRIVATE_KEY *key) +{ + gmssl_secure_clear(key, sizeof(*key)); +} + + +int kyber_public_key_to_bytes(const KYBER_PRIVATE_KEY *key, uint8_t **out, size_t *outlen) +{ + return kyber_cpa_public_key_to_bytes(&key->pk, out, outlen); +} + +int kyber_public_key_from_bytes(KYBER_PRIVATE_KEY *key, const uint8_t **in, size_t *inlen) +{ + memset(key, 0, sizeof(*key)); + return kyber_cpa_public_key_from_bytes(&key->pk, in, inlen); +} + +/* +165 typedef struct { +166 KYBER_CPA_PUBLIC_KEY pk; +167 KYBER_CPA_PRIVATE_KEY sk; +168 uint8_t pk_hash[32]; +169 uint8_t z[32]; +170 } KYBER_PRIVATE_KEY; +*/ + +int kyber_private_key_to_bytes(const KYBER_PRIVATE_KEY *key, uint8_t **out, size_t *outlen) +{ + if (!key || !outlen) { + error_print(); + return -1; + } + if (kyber_cpa_public_key_to_bytes(&key->pk, out, outlen) != 1) { + error_print(); + return -1; + } + if (kyber_cpa_private_key_to_bytes(&key->sk, out, outlen) != 1) { + error_print(); + return -1; + } + if (out && *out) { + memcpy(*out, key->pk_hash, sizeof(key->pk_hash)); + *out += sizeof(key->pk_hash); + memcpy(*out, key->z, sizeof(key->z)); + *out += sizeof(key->z); + } + *outlen += sizeof(key->pk_hash); + *outlen += sizeof(key->z); + return 1; +} + +int kyber_private_key_from_bytes(KYBER_PRIVATE_KEY *key, const uint8_t **in, size_t *inlen) +{ + if (!key || !in || !(*in) || !inlen) { + error_print(); + return -1; + } + if (*inlen < sizeof(*key)) { + error_print(); + return -1; + } + if (kyber_cpa_public_key_from_bytes(&key->pk, in, inlen) != 1) { + error_print(); + return -1; + } + if (kyber_cpa_private_key_from_bytes(&key->sk, in, inlen) != 1) { + error_print(); + return -1; + } + memcpy(key->pk_hash, *in, sizeof(key->pk_hash)); + *in += sizeof(key->pk_hash); + *inlen -= sizeof(key->pk_hash); + memcpy(key->z, *in, sizeof(key->z)); + *in += sizeof(key->z); + *inlen -= sizeof(key->z); + + return 1; +} + int kyber_keygen(KYBER_PUBLIC_KEY *pk, KYBER_PRIVATE_KEY *sk) { if (kyber_cpa_keygen(pk, &sk->sk) != 1) { @@ -1006,11 +1125,9 @@ int kyber_private_key_print(FILE *fp, int fmt, int ind, const char *label, const } - - -int kyber_public_key_print(FILE *fp, int fmt, int ind, const char *label, const KYBER_PUBLIC_KEY *pk) +int kyber_public_key_print(FILE *fp, int fmt, int ind, const char *label, const KYBER_PRIVATE_KEY *key) { - return kyber_cpa_public_key_print(fp, fmt, ind, label, pk); + return kyber_cpa_public_key_print(fp, fmt, ind, label, &key->pk); } @@ -1103,3 +1220,50 @@ int kyber_decap(const KYBER_PRIVATE_KEY *sk, const KYBER_CIPHERTEXT *c, uint8_t gmssl_secure_clear(K_r, sizeof(K_r)); return 1; } + +int kyber_cpa_ciphertext_to_bytes(const KYBER_CPA_CIPHERTEXT *ciphertext, uint8_t **out, size_t *outlen) +{ + if (!ciphertext || !outlen) { + error_print(); + return -1; + } + if (out && *out) { + memcpy(*out, ciphertext->c1, sizeof(ciphertext->c1)); + *out += sizeof(ciphertext->c1); + memcpy(*out, ciphertext->c2, sizeof(ciphertext->c2)); + *out += sizeof(ciphertext->c2); + } + *outlen += sizeof(ciphertext->c1); + *outlen += sizeof(ciphertext->c2); + return 1; +} + +int kyber_cpa_ciphertext_from_bytes(KYBER_CPA_CIPHERTEXT *ciphertext, const uint8_t **in, size_t *inlen) +{ + if (!ciphertext || !in || !(*in) || !inlen) { + error_print(); + return -1; + } + if (*inlen < sizeof(ciphertext->c1) + sizeof(ciphertext->c2)) { + error_print(); + return -1; + } + memcpy(ciphertext->c1, *in, sizeof(ciphertext->c1)); + *in += sizeof(ciphertext->c1); + *inlen -= sizeof(ciphertext->c1); + memcpy(ciphertext->c2, *in, sizeof(ciphertext->c2)); + *in += sizeof(ciphertext->c2); + *inlen -= sizeof(ciphertext->c2); + return 1; +} + +int kyber_ciphertext_to_bytes(const KYBER_CIPHERTEXT *ciphertext, uint8_t **out, size_t *outlen) +{ + return kyber_cpa_ciphertext_to_bytes(ciphertext, out, outlen); +} + +int kyber_ciphertext_from_bytes(KYBER_CIPHERTEXT *ciphertext, const uint8_t **in, size_t *inlen) +{ + return kyber_cpa_ciphertext_from_bytes(ciphertext, in, inlen); +} + diff --git a/tests/kybertest.c b/tests/kybertest.c index 06bcf7f4..049dccb1 100644 --- a/tests/kybertest.c +++ b/tests/kybertest.c @@ -483,10 +483,9 @@ static int test_kyber_kem(void) return -1; } - kyber_public_key_print(stderr, 0, 0, "pk", &pk); + kyber_public_key_print(stderr, 0, 0, "pk", &sk); kyber_private_key_print(stderr, 0, 0, "sk", &sk); - if (kyber_encap(&pk, &c, K) != 1) { error_print(); return -1; @@ -500,7 +499,6 @@ static int test_kyber_kem(void) } format_bytes(stderr, 0, 0, "DEC_K", K_, 32); - if (memcmp(K_, K, 32) != 0) { error_print(); return -1; @@ -510,6 +508,134 @@ static int test_kyber_kem(void) return 1; } +static int test_kyber_cpa_key_to_bytes(void) +{ + KYBER_CPA_PUBLIC_KEY pk; + KYBER_CPA_PRIVATE_KEY sk; + uint8_t buf[30000]; + uint8_t *p = buf; + const uint8_t *cp = buf; + size_t len = 0; + + if (kyber_cpa_keygen(&pk, &sk) != 1) { + error_print(); + return -1; + } + if (kyber_cpa_public_key_to_bytes(&pk, &p, &len) != 1) { + error_print(); + return -1; + } + if (kyber_cpa_private_key_to_bytes(&sk, &p, &len) != 1) { + error_print(); + return -1; + } + if (kyber_cpa_public_key_from_bytes(&pk, &cp, &len) != 1) { + error_print(); + return -1; + } + if (kyber_cpa_private_key_from_bytes(&sk, &cp, &len) != 1) { + error_print(); + return -1; + } + if (len) { + error_print(); + return -1; + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + + +static int test_kyber_key_to_bytes(void) +{ + KYBER_PRIVATE_KEY key; + uint8_t buf[sizeof(KYBER_PRIVATE_KEY) + sizeof(KYBER_PRIVATE_KEY)]; + uint8_t *p = buf; + const uint8_t *cp = buf; + size_t len = 0; + + if (kyber_key_generate(&key) != 1) { + error_print(); + return -1; + } + if (kyber_public_key_to_bytes(&key, &p, &len) != 1) { + error_print(); + return -1; + } + if (kyber_private_key_to_bytes(&key, &p, &len) != 1) { + error_print(); + return -1; + } + if (kyber_public_key_from_bytes(&key, &cp, &len) != 1) { + error_print(); + return -1; + } + if (kyber_private_key_from_bytes(&key, &cp, &len) != 1) { + error_print(); + return -1; + } + if (len) { + error_print(); + return -1; + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + + +static int test_kyber_cpa_ciphertext_to_bytes(void) +{ + KYBER_CPA_PUBLIC_KEY pk; + KYBER_CPA_PRIVATE_KEY sk; + KYBER_CPA_CIPHERTEXT c; + uint8_t m[32]; + uint8_t r[32]; + uint8_t m_[32]; + + + uint8_t buf[sizeof(KYBER_CPA_CIPHERTEXT)]; + uint8_t *p = buf; + const uint8_t *cp = buf; + size_t len = 0; + + + if (rand_bytes(m, 32) != 1) { + error_print(); + return -1; + } + if (rand_bytes(r, 32) != 1) { + error_print(); + return -1; + } + + if (kyber_cpa_keygen(&pk, &sk) != 1) { + error_print(); + return -1; + } + if (kyber_cpa_encrypt(&pk, m, r, &c) != 1) { + error_print(); + return -1; + } + + if (kyber_cpa_ciphertext_to_bytes(&c, &p, &len) != 1) { + error_print(); + return -1; + } + if (kyber_cpa_ciphertext_from_bytes(&c, &cp, &len) != 1) { + error_print(); + return -1; + } + if (len) { + error_print(); + return -1; + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + int main(void) { init_zeta(); @@ -527,6 +653,9 @@ int main(void) if (test_kyber_poly_ntt_mul() != 1) goto err; if (test_kyber_cpa() != 1) goto err; if (test_kyber_kem() != 1) goto err; + if (test_kyber_cpa_key_to_bytes() != 1) goto err; + if (test_kyber_key_to_bytes() != 1) goto err; + if (test_kyber_cpa_ciphertext_to_bytes() != 1) goto err; printf("%s all tests passed\n", __FILE__); return 0; diff --git a/tools/gmssl.c b/tools/gmssl.c index 4d091602..1701c03f 100644 --- a/tools/gmssl.c +++ b/tools/gmssl.c @@ -77,6 +77,11 @@ extern int xmsskeygen_main(int argc, char **argv); extern int xmsssign_main(int argc, char **argv); extern int xmssverify_main(int argc, char **argv); #endif +#ifdef ENABLE_KYBER +extern int kyberkeygen_main(int argc, char **argv); +extern int kyberencap_main(int argc, char **argv); +extern int kyberdecap_main(int argc, char **argv); +#endif #ifdef ENABLE_SDF extern int sdfinfo_main(int argc, char **argv); extern int sdfdigest_main(int argc, char **argv); @@ -154,6 +159,11 @@ static const char *options = " xmsssign Generate XMSS-SM3 signature\n" " xmssverify Verify XMSS-SM3 signature\n" #endif +#ifdef ENABLE_KYBER + " kyberkeygen Generate Kyber keypair\n" + " kyberencap Kyber KEM encap\n" + " kyberdecap Kyber KEM decap\n" +#endif #ifdef ENABLE_SDF " sdfinfo Print SDF device info\n" " sdfdigest Generate SM3 hash with SDF device\n" @@ -330,6 +340,14 @@ int main(int argc, char **argv) } else if (!strcmp(*argv, "xmssverify")) { return xmssverify_main(argc, argv); #endif +#ifdef ENABLE_KYBER + } else if (!strcmp(*argv, "kyberkeygen")) { + return kyberkeygen_main(argc, argv); + } else if (!strcmp(*argv, "kyberencap")) { + return kyberencap_main(argc, argv); + } else if (!strcmp(*argv, "kyberdecap")) { + return kyberdecap_main(argc, argv); +#endif #ifdef ENABLE_SDF } else if (!strcmp(*argv, "sdfinfo")) { return sdfinfo_main(argc, argv); diff --git a/tools/kyberdecap.c b/tools/kyberdecap.c new file mode 100644 index 00000000..ece22d8f --- /dev/null +++ b/tools/kyberdecap.c @@ -0,0 +1,171 @@ +/* + * Copyright 2014-2025 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ + + +#include +#include +#include +#include +#include +#include +#include + + +static const char *usage = "-key file [-in file] [-out file] [-verbose]\n"; + +static const char *options = +"Options\n" +" -key file Input private key file\n" +" -in file Input ciphertext (encapsulated secret)\n" +" -out file Output decapsulated secret\n" +" -verbose Print public key and ciphertext\n" +"\n"; + +int kyberdecap_main(int argc, char **argv) +{ + int ret = 1; + char *prog = argv[0]; + char *keyfile = NULL; + char *infile = NULL; + char *outfile = NULL; + int verbose = 0; + FILE *keyfp = NULL; + FILE *infp = stdin; + FILE *outfp = stdout; + uint8_t keybuf[KYBER_PRIVATE_KEY_SIZE]; + size_t keylen = KYBER_PRIVATE_KEY_SIZE; + const uint8_t *cp = keybuf; + uint8_t *p = keybuf; + KYBER_PRIVATE_KEY key; + + uint8_t inbuf[sizeof(KYBER_CIPHERTEXT)]; + uint8_t outbuf[32]; + + KYBER_CIPHERTEXT ciphertext; + + memset(&key, 0, sizeof(key)); + + argc--; + argv++; + + if (argc < 1) { + fprintf(stderr, "usage: gmssl %s %s\n", prog, usage); + return 1; + } + + while (argc > 0) { + if (!strcmp(*argv, "-help")) { + printf("usage: %s %s\n", prog, usage); + printf("%s\n", options); + ret = 0; + goto end; + } else if (!strcmp(*argv, "-key")) { + if (--argc < 1) goto bad; + keyfile = *(++argv); + if (!(keyfp = fopen(keyfile, "rb+"))) { + fprintf(stderr, "%s: open '%s' failure: %s\n", prog, keyfile, strerror(errno)); + goto end; + } + } else if (!strcmp(*argv, "-in")) { + if (--argc < 1) goto bad; + infile = *(++argv); + if (!(infp = fopen(infile, "rb"))) { + fprintf(stderr, "%s: open '%s' failure: %s\n", prog, infile, strerror(errno)); + goto end; + } + } else if (!strcmp(*argv, "-out")) { + if (--argc < 1) goto bad; + outfile = *(++argv); + if (!(outfp = fopen(outfile, "wb"))) { + fprintf(stderr, "%s: open '%s' failure: %s\n", prog, outfile, strerror(errno)); + goto end; + } + } else if (!strcmp(*argv, "-verbose")) { + verbose = 1; + } else { + fprintf(stderr, "%s: illegal option '%s'\n", prog, *argv); + goto end; +bad: + fprintf(stderr, "%s: `%s` option value missing\n", prog, *argv); + goto end; + } + + argc--; + argv++; + } + + if (!keyfile) { + fprintf(stderr, "%s: `-key` option required\n", prog); + goto end; + } + + if (fread(keybuf, 1, keylen, keyfp) != keylen) { + fprintf(stderr, "%s: read private key failure\n", prog); + goto end; + } + if (kyber_private_key_from_bytes(&key, &cp, &keylen) != 1) { + error_print(); + goto end; + } + if (keylen) { + error_print(); + return -1; + } + + if (verbose) { + kyber_private_key_print(stderr, 0, 0, "kyber_private_key", &key); + } + + + size_t inlen = sizeof(inbuf); + + if (fread(inbuf, 1, inlen, infp) != inlen) { + fprintf(stderr, "%s: read ciphertext failure\n", prog); + goto end; + } + cp = inbuf; + if (kyber_ciphertext_from_bytes(&ciphertext, &cp, &inlen) != 1) { + error_print(); + goto end; + } + if (inlen) { + error_print(); + return -1; + } + + + if (verbose) { + kyber_ciphertext_print(stderr, 0, 0, "kyber_ciphertext" ,&ciphertext); + } + + + + if (kyber_decap(&key, &ciphertext, outbuf) != 1) { + error_print(); + return -1; + } + + + if (verbose) { + format_bytes(stderr, 0, 0, "key", outbuf, 32); + + + } + + + ret = 0; + +end: + //kyber_key_cleanup(&key); + gmssl_secure_clear(keybuf, sizeof(keybuf)); + if (keyfp) fclose(keyfp); + if (infp && infp != stdin) fclose(infp); + if (outfp && outfp != stdout) fclose(outfp); + return ret; +} diff --git a/tools/kyberencap.c b/tools/kyberencap.c new file mode 100644 index 00000000..e1906074 --- /dev/null +++ b/tools/kyberencap.c @@ -0,0 +1,165 @@ +/* + * Copyright 2014-2025 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ + + +#include +#include +#include +#include +#include +#include +#include + + +static const char *usage = "-pubkey file [-out file] -outkey file [-verbose]\n"; + + +// decap 中的out一定是secret,而in 一定是ciphertext +// encap 中的out 是decap的in,因此encap中的out是ciphertext,而输出的secret是特殊的 + +static const char *options = +"Options\n" +" -pubkey file Input public key file\n" +" -out file Output ciphertext (decapsulated secret)\n" +" -outkey file Output secret\n" +" -verbose Print public key and ciphertext\n" +"\n"; + +int kyberencap_main(int argc, char **argv) +{ + int ret = 1; + char *prog = argv[0]; + char *pubkeyfile = NULL; + char *outfile = NULL; + char *outkeyfile = NULL; + int verbose = 0; + FILE *pubkeyfp = NULL; + FILE *outfp = stdout; + FILE *outkeyfp = NULL; + uint8_t pubkeybuf[KYBER_PUBLIC_KEY_SIZE]; + size_t pubkeylen = KYBER_PUBLIC_KEY_SIZE; + const uint8_t *cp = pubkeybuf; + uint8_t outbuf[sizeof(KYBER_CIPHERTEXT)]; + size_t outlen; + KYBER_PRIVATE_KEY key; + KYBER_CIPHERTEXT ciphertext; + + uint8_t outkey[32]; + + + argc--; + argv++; + + if (argc < 1) { + fprintf(stderr, "usage: gmssl %s %s\n", prog, usage); + return 1; + } + + while (argc > 0) { + if (!strcmp(*argv, "-help")) { + printf("usage: %s %s\n", prog, usage); + printf("%s\n", options); + ret = 0; + goto end; + } else if (!strcmp(*argv, "-pubkey")) { + if (--argc < 1) goto bad; + pubkeyfile = *(++argv); + if (!(pubkeyfp = fopen(pubkeyfile, "rb"))) { + fprintf(stderr, "%s: open '%s' failure: %s\n", prog, pubkeyfile, strerror(errno)); + goto end; + } + } else if (!strcmp(*argv, "-out")) { + if (--argc < 1) goto bad; + outfile = *(++argv); + if (!(outfp = fopen(outfile, "wb"))) { + fprintf(stderr, "%s: open '%s' failure: %s\n", prog, outfile, strerror(errno)); + goto end; + } + } else if (!strcmp(*argv, "-outkey")) { + if (--argc < 1) goto bad; + outkeyfile = *(++argv); + if (!(outkeyfp = fopen(outkeyfile, "wb"))) { + fprintf(stderr, "%s: open '%s' failure: %s\n", prog, outkeyfile, strerror(errno)); + goto end; + } + } else if (!strcmp(*argv, "-verbose")) { + verbose = 1; + } else { + fprintf(stderr, "%s: illegal option '%s'\n", prog, *argv); + goto end; +bad: + fprintf(stderr, "%s: `%s` option value missing\n", prog, *argv); + goto end; + } + + argc--; + argv++; + } + + if (!pubkeyfile) { + fprintf(stderr, "%s: `-key` option required\n", prog); + goto end; + } + if (!outkeyfile) { + fprintf(stderr, "%s: `-outkey` option required\n", prog); + goto end; + } + + if (fread(pubkeybuf, 1, pubkeylen, pubkeyfp) != pubkeylen) { + fprintf(stderr, "%s: read public key failure\n", prog); + goto end; + } + if (kyber_public_key_from_bytes(&key, &cp, &pubkeylen) != 1) { + error_print(); + goto end; + } + if (verbose) { + kyber_public_key_print(stderr, 0, 0, "kyber_public_key", &key); + } + + + if (kyber_encap(&key.pk, &ciphertext, outkey) != 1) { + error_print(); + return -1; + } + + if (verbose) { + + kyber_ciphertext_print(stderr, 0, 0, "kyber_ciphertext", &ciphertext); + + + format_bytes(stderr, 0, 0, "key", outkey, 32); + + } + + + uint8_t *p = outbuf; + outlen = 0; + if (kyber_ciphertext_to_bytes(&ciphertext, &p, &outlen) != 1) { + error_print(); + goto end; + } + if (fwrite(outbuf, 1, outlen, outfp) != outlen) { + error_print(); + goto end; + } + + if (fwrite(outkey, 1, 32, outkeyfp) != 32) { + error_print(); + goto end; + } + + ret = 0; + +end: + if (pubkeyfp) fclose(pubkeyfp); + if (outfp && outfp != stdin) fclose(outfp); + if (outkeyfp) fclose(outkeyfp); + return ret; +} diff --git a/tools/kyberkeygen.c b/tools/kyberkeygen.c new file mode 100644 index 00000000..d41cac2b --- /dev/null +++ b/tools/kyberkeygen.c @@ -0,0 +1,129 @@ +/* + * Copyright 2014-2025 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ + + +#include +#include +#include +#include +#include +#include +#include + + +static const char *usage = "-out file [-pubout file] [-verbose]\n"; + +static const char *options = +"Options\n" +" -out file Output private key\n" +" -pubout file Output public key\n" +" -verbose Print public key\n" +"\n"; + +int kyberkeygen_main(int argc, char **argv) +{ + int ret = 1; + char *prog = argv[0]; + char *outfile = NULL; + char *puboutfile = NULL; + int verbose = 0; + FILE *outfp = NULL; + FILE *puboutfp = stdout; + KYBER_PRIVATE_KEY key; + uint8_t out[sizeof(KYBER_PRIVATE_KEY)]; + uint8_t pubout[sizeof(KYBER_PUBLIC_KEY)]; + uint8_t *pout = out; + uint8_t *ppubout = pubout; + size_t outlen = 0, puboutlen = 0; + + memset(&key, 0, sizeof(key)); + + argc--; + argv++; + + if (argc < 1) { + fprintf(stderr, "usage: gmssl %s %s\n", prog, usage); + return 1; + } + + while (argc > 0) { + if (!strcmp(*argv, "-help")) { + printf("usage: gmssl %s %s\n", prog, usage); + printf("%s\n", options); + ret = 0; + goto end; + } else if (!strcmp(*argv, "-out")) { + if (--argc < 1) goto bad; + outfile = *(++argv); + if (!(outfp = fopen(outfile, "wb"))) { + fprintf(stderr, "%s: open '%s' failure : %s\n", prog, outfile, strerror(errno)); + goto end; + } + } else if (!strcmp(*argv, "-pubout")) { + if (--argc < 1) goto bad; + puboutfile = *(++argv); + if (!(puboutfp = fopen(puboutfile, "wb"))) { + fprintf(stderr, "%s: open '%s' failure : %s\n", prog, outfile, strerror(errno)); + goto end; + } + } else if (!strcmp(*argv, "-verbose")) { + verbose = 1; + } else { + fprintf(stderr, "%s: illegal option '%s'\n", prog, *argv); + goto end; +bad: + fprintf(stderr, "%s: `%s` option value missing\n", prog, *argv); + goto end; + } + + argc--; + argv++; + } + + if (!outfp) { + fprintf(stderr, "%s: `-out` option required\n", prog); + goto end; + } + + if (kyber_key_generate(&key) != 1) { + error_print(); + return -1; + } + if (verbose) { + kyber_public_key_print(stderr, 0, 0, "kyber_public_key", &key); + + kyber_private_key_print(stderr, 0, 0, "kyber_private_key", &key); + } + + if (kyber_private_key_to_bytes(&key, &pout, &outlen) != 1) { + error_print(); + goto end; + } + if (fwrite(out, 1, outlen, outfp) != outlen) { + error_print(); + goto end; + } + + if (kyber_public_key_to_bytes(&key, &ppubout, &puboutlen) != 1) { + error_print(); + goto end; + } + if (fwrite(pubout, 1, puboutlen, puboutfp) != puboutlen) { + error_print(); + goto end; + } + + ret = 0; +end: + kyber_key_cleanup(&key); + gmssl_secure_clear(out, outlen); + if (outfile && outfp) fclose(outfp); + if (puboutfile && puboutfp) fclose(puboutfp); + return ret; +}