Update Kyber-512 to ML-KEM-768

This commit is contained in:
Zhi Guan
2026-06-24 22:35:01 +08:00
parent 09c96fa2e0
commit d8ce43ffef
8 changed files with 742 additions and 63 deletions

View File

@@ -14,7 +14,9 @@
#include <gmssl/hex.h>
#include <gmssl/mem.h>
#include <gmssl/rand.h>
#include <gmssl/sm3.h>
#include <gmssl/hkdf.h>
#include <gmssl/sha3.h>
#include <gmssl/error.h>
#include <gmssl/endian.h>
#include <gmssl/kyber.h>
@@ -22,13 +24,29 @@
void kyber_h_hash(const uint8_t *in, size_t inlen, uint8_t out[32])
{
SM3_CTX ctx;
sm3_init(&ctx);
sm3_update(&ctx, in, inlen);
sm3_finish(&ctx, out);
sha3_256(in, inlen, out);
}
void kyber_g_hash(const uint8_t *in, size_t inlen, uint8_t out[64])
{
sha3_512(in, inlen, out);
}
/*
* Legacy SM3-based Kyber variants kept for compatibility/reference only.
* The ML-KEM path above uses FIPS 203 SHA3/SHAKE functions.
*/
void kyber_h_hash_sm3(const uint8_t *in, size_t inlen, uint8_t out[32])
{
SM3_CTX ctx;
sm3_init(&ctx);
sm3_update(&ctx, in, inlen);
sm3_finish(&ctx, out);
gmssl_secure_clear(&ctx, sizeof(ctx));
}
void kyber_g_hash_sm3(const uint8_t *in, size_t inlen, uint8_t out[64])
{
SM3_CTX ctx;
uint8_t ctr[4] = {0};
@@ -43,30 +61,53 @@ void kyber_g_hash(const uint8_t *in, size_t inlen, uint8_t out[64])
sm3_update(&ctx, in, inlen);
sm3_update(&ctx, ctr, 4);
sm3_finish(&ctx, out + 32);
gmssl_secure_clear(&ctx, sizeof(ctx));
gmssl_secure_clear(ctr, sizeof(ctr));
}
// https://www.cryptosys.net/pki/manpki/pki_prfxof.html
static int kyber_prf(const uint8_t seed[32], uint8_t N, size_t outlen, uint8_t *out)
{
uint8_t salt[1];
uint8_t key[32];
uint8_t in[33];
salt[0] = (uint8_t)N;
memcpy(in, seed, 32);
in[32] = N;
shake256(in, sizeof(in), out, outlen);
gmssl_secure_clear(in, sizeof(in));
return 1;
}
static int kyber_prf_sm3(const uint8_t seed[32], uint8_t N, size_t outlen, uint8_t *out)
{
uint8_t key[32];
if (sm3_hkdf_extract(NULL, 0, seed, 32, key) != 1) {
error_print();
return -1;
}
sm3_hkdf_expand(key, &N, 1, outlen, out);
if (sm3_hkdf_expand(key, &N, 1, outlen, out) != 1) {
gmssl_secure_clear(key, sizeof(key));
error_print();
return -1;
}
gmssl_secure_clear(key, sizeof(key));
return 1;
}
static int kyber_kdf(const uint8_t in[64], uint8_t out[32])
static int kyber_kdf_sm3(const uint8_t in[64], uint8_t out[32])
{
uint8_t key[32];
sm3_hkdf_extract(NULL, 0, in, 64, key);
sm3_hkdf_expand(key, NULL, 0, 32, out);
gmssl_secure_clear(key, 32);
if (sm3_hkdf_extract(NULL, 0, in, 64, key) != 1) {
error_print();
return -1;
}
if (sm3_hkdf_expand(key, NULL, 0, 32, out) != 1) {
gmssl_secure_clear(key, sizeof(key));
error_print();
return -1;
}
gmssl_secure_clear(key, sizeof(key));
return 1;
}
@@ -112,6 +153,51 @@ int kyber_poly_rand(kyber_poly_t r)
}
int kyber_poly_uniform_sample(kyber_poly_t r, const uint8_t rho[32], uint8_t j, uint8_t i)
{
SHAKE_CTX ctx;
uint8_t seed[32 + 2];
uint8_t rand[168];
size_t n;
int16_t *out = r;
int16_t *end = r + 256;
memcpy(seed, rho, 32);
seed[32] = j;
seed[33] = i;
shake128_init(&ctx);
shake_update(&ctx, seed, sizeof(seed));
shake_finish(&ctx);
for (;;) {
shake_squeeze(&ctx, rand, sizeof(rand));
for (n = 0; n < sizeof(rand); n += 3) {
int16_t a0 = rand[n] | ((int16_t)(rand[n + 1] & 0xf) << 8);
int16_t a1 = (rand[n + 1] >> 4) | ((int16_t)rand[n + 2] << 4);
if (a0 < KYBER_Q) {
*out++ = a0;
if (out >= end) {
goto end;
}
}
if (a1 < KYBER_Q) {
*out++ = a1;
if (out >= end) {
goto end;
}
}
}
}
end:
gmssl_secure_clear(&ctx, sizeof(ctx));
gmssl_secure_clear(seed, sizeof(seed));
gmssl_secure_clear(rand, sizeof(rand));
return 1;
}
int kyber_poly_uniform_sample_sm3(kyber_poly_t r, const uint8_t rho[32], uint8_t j, uint8_t i)
{
SM3_CTX ctx;
uint8_t seed[32 + 2 + 4];
@@ -154,6 +240,9 @@ int kyber_poly_uniform_sample(kyber_poly_t r, const uint8_t rho[32], uint8_t j,
}
end:
gmssl_secure_clear(&ctx, sizeof(ctx));
gmssl_secure_clear(seed, sizeof(seed));
gmssl_secure_clear(rand, sizeof(rand));
return 1;
}
@@ -198,6 +287,9 @@ int kyber_poly_cbd_sample(kyber_poly_t r, int eta, const uint8_t secret[32], uin
}
gmssl_secure_clear(bytes, sizeof(bytes));
} else {
error_print();
return -1;
}
for (i = 0; i < 256; i++) {
@@ -586,21 +678,23 @@ int kyber_cpa_key_generate_ex(KYBER_CPA_KEY *key, const uint8_t random[32])
kyber_poly_t e[KYBER_K];
kyber_poly_t t[KYBER_K];
uint8_t d[64];
uint8_t g_in[33];
uint8_t *rho = d;
uint8_t *sigma = d + 32;
uint8_t N = 0;
int i,j;
if (random) {
memcpy(d, random, 32);
memcpy(g_in, random, 32);
} else {
if (rand_bytes(d, 32) != 1) {
if (rand_bytes(g_in, 32) != 1) {
error_print();
return -1;
}
}
g_in[32] = KYBER_K;
kyber_g_hash(d, 32, d);
kyber_g_hash(g_in, sizeof(g_in), d);
// AHat[i][j] = Parse(XOR(rho, j, i))
for (i = 0; i < KYBER_K; i++) {
@@ -652,6 +746,7 @@ int kyber_cpa_key_generate_ex(KYBER_CPA_KEY *key, const uint8_t random[32])
memcpy(key->public_key.rho, rho, 32);
gmssl_secure_clear(d, sizeof(d));
gmssl_secure_clear(g_in, sizeof(g_in));
gmssl_secure_clear(s, sizeof(s));
gmssl_secure_clear(e, sizeof(e));
@@ -677,6 +772,9 @@ int kyber_cpa_public_key_to_bytes(const KYBER_CPA_KEY *key, uint8_t **out, size_
int kyber_cpa_public_key_from_bytes(KYBER_CPA_KEY *key, const uint8_t **in, size_t *inlen)
{
kyber_poly_t t;
int i;
if (!key || !in || !(*in) || !inlen) {
error_print();
return -1;
@@ -685,13 +783,19 @@ int kyber_cpa_public_key_from_bytes(KYBER_CPA_KEY *key, const uint8_t **in, size
error_print();
return -1;
}
memset(key, 0, sizeof(*key));
memcpy(key->public_key.t, *in, sizeof(key->public_key.t));
*in += sizeof(key->public_key.t);
*inlen -= sizeof(key->public_key.t);
memcpy(key->public_key.rho, *in, sizeof(key->public_key.rho));
*in += sizeof(key->public_key.rho);
*inlen -= sizeof(key->public_key.rho);
for (i = 0; i < KYBER_K; i++) {
if (kyber_poly_decode12(t, key->public_key.t[i]) != 1) {
error_print();
return -1;
}
}
return 1;
}
@@ -701,15 +805,15 @@ int kyber_cpa_private_key_to_bytes(const KYBER_CPA_KEY *key, uint8_t **out, size
error_print();
return -1;
}
if (kyber_cpa_public_key_to_bytes(key, out, outlen) != 1) {
error_print();
return -1;
}
if (out && *out) {
memcpy(*out, key->s, sizeof(key->s));
*out += sizeof(key->s);
}
*outlen += sizeof(key->s);
if (kyber_cpa_public_key_to_bytes(key, out, outlen) != 1) {
error_print();
return -1;
}
return 1;
}
@@ -720,10 +824,6 @@ int kyber_cpa_private_key_from_bytes(KYBER_CPA_KEY *key, const uint8_t **in, siz
return -1;
}
memset(key, 0, sizeof(*key));
if (kyber_cpa_public_key_from_bytes(key, in, inlen) != 1) {
error_print();
return -1;
}
if (*inlen < sizeof(key->s)) {
error_print();
return -1;
@@ -731,6 +831,10 @@ int kyber_cpa_private_key_from_bytes(KYBER_CPA_KEY *key, const uint8_t **in, siz
memcpy(key->s, *in, sizeof(key->s));
*in += sizeof(key->s);
*inlen -= sizeof(key->s);
if (kyber_cpa_public_key_from_bytes(key, in, inlen) != 1) {
error_print();
return -1;
}
return 1;
}
@@ -932,8 +1036,8 @@ int kyber_cpa_encrypt(const KYBER_CPA_KEY *key, const uint8_t in[32],
kyber_poly_encode10(u[i], out->c1[i]);
}
// c2 = Encode4(Compress(v, 4))
kyber_poly_compress(v, 4, v);
// c2 = Encode4(Compress(v, KYBER_DV))
kyber_poly_compress(v, KYBER_DV, v);
kyber_poly_encode4(v, out->c2);
gmssl_secure_clear(m, sizeof(m));
@@ -962,7 +1066,7 @@ int kyber_cpa_decrypt(const KYBER_CPA_KEY *key, const KYBER_CPA_CIPHERTEXT *in,
// v = Decompress(Decode_dv(c2), dv)
kyber_poly_decode4(v, in->c2);
kyber_poly_decompress(v, 4, v);
kyber_poly_decompress(v, KYBER_DV, v);
// s = Decode_12(sk)
@@ -997,20 +1101,46 @@ int kyber_cpa_decrypt(const KYBER_CPA_KEY *key, const KYBER_CPA_CIPHERTEXT *in,
int kyber_key_generate_ex(KYBER_KEY *key, const uint8_t random[32])
{
uint8_t seed[64];
if (!key) {
error_print();
return -1;
}
if (kyber_cpa_key_generate_ex(&key->cpa_key, random) != 1) {
if (random) {
memcpy(seed, random, 32);
} else if (rand_bytes(seed, 32) != 1) {
error_print();
return -1;
}
kyber_h_hash((uint8_t *)key, sizeof(KYBER_CPA_PUBLIC_KEY), key->pk_hash);
if (rand_bytes(key->z, 32) != 1) {
gmssl_secure_clear(&key->cpa_key, sizeof(KYBER_CPA_KEY));
if (rand_bytes(seed + 32, 32) != 1) {
gmssl_secure_clear(seed, sizeof(seed));
error_print();
return -1;
}
if (kyber_key_generate_from_seed(key, seed) != 1) {
gmssl_secure_clear(seed, sizeof(seed));
error_print();
return -1;
}
gmssl_secure_clear(seed, sizeof(seed));
return 1;
}
int kyber_key_generate_from_seed(KYBER_KEY *key, const uint8_t seed[64])
{
if (!key || !seed) {
error_print();
return -1;
}
memset(key, 0, sizeof(*key));
if (kyber_cpa_key_generate_ex(&key->cpa_key, seed) != 1) {
gmssl_secure_clear(key, sizeof(*key));
error_print();
return -1;
}
kyber_h_hash((const uint8_t *)&key->cpa_key.public_key, sizeof(KYBER_CPA_PUBLIC_KEY), key->pk_hash);
memcpy(key->z, seed + 32, 32);
return 1;
}
@@ -1064,6 +1194,8 @@ int kyber_private_key_to_bytes(const KYBER_KEY *key, uint8_t **out, size_t *outl
int kyber_private_key_from_bytes(KYBER_KEY *key, const uint8_t **in, size_t *inlen)
{
uint8_t pk_hash[32];
if (!key || !in || !(*in) || !inlen) {
error_print();
return -1;
@@ -1084,6 +1216,14 @@ int kyber_private_key_from_bytes(KYBER_KEY *key, const uint8_t **in, size_t *inl
memcpy(key->z, *in, sizeof(key->z));
*in += sizeof(key->z);
*inlen -= sizeof(key->z);
kyber_h_hash((const uint8_t *)&key->cpa_key.public_key, sizeof(KYBER_CPA_PUBLIC_KEY), pk_hash);
if (gmssl_secure_memcmp(key->pk_hash, pk_hash, sizeof(pk_hash)) != 0) {
gmssl_secure_clear(key, sizeof(*key));
gmssl_secure_clear(pk_hash, sizeof(pk_hash));
error_print();
return -1;
}
gmssl_secure_clear(pk_hash, sizeof(pk_hash));
return 1;
}
@@ -1101,60 +1241,86 @@ int kyber_private_key_print(FILE *fp, int fmt, int ind, const char *label, const
return 1;
}
int kyber_encap(const KYBER_KEY *key, KYBER_CIPHERTEXT *c, uint8_t K[32])
int kyber_encap_ex(const KYBER_KEY *key, const uint8_t m[32], KYBER_CIPHERTEXT *c, uint8_t K[32])
{
uint8_t m_h[64];
uint8_t K_r[64];
uint8_t *m = m_h;
uint8_t *h = m_h + 32;
uint8_t *K_ = K_r;
uint8_t *r = K_r + 32;
// m = rand(32)
if (rand_bytes(m, 32) != 1) {
if (!key || !m || !c || !K) {
error_print();
return -1;
}
// m = H(m)
kyber_h_hash(m, 32, m);
memcpy(m_h, m, 32);
// h = H(pk)
kyber_h_hash((const uint8_t *)key, sizeof(KYBER_PUBLIC_KEY), h);
kyber_h_hash((const uint8_t *)&key->cpa_key.public_key, sizeof(KYBER_PUBLIC_KEY), h);
// (K_, r) = G(m || H(pk))
kyber_g_hash(m_h, 64, K_r);
// c = Kyber.CPA.Enc(pk, m, r)
if (kyber_cpa_encrypt(&key->cpa_key, m, r, c) != 1) {
gmssl_secure_clear(m_h, sizeof(m_h));
gmssl_secure_clear(K_r, sizeof(K_r));
error_print();
return -1;
}
// H(c)
kyber_h_hash((uint8_t *)c, sizeof(KYBER_CIPHERTEXT), r);
// K = KDF(K_ || H(c))
kyber_kdf(K_r, K);
memcpy(K, K_, 32);
gmssl_secure_clear(m_h, sizeof(m_h));
gmssl_secure_clear(K_r, sizeof(K_r));
return 1;
}
int kyber_encap(const KYBER_KEY *key, KYBER_CIPHERTEXT *c, uint8_t K[32])
{
uint8_t m[32];
if (rand_bytes(m, sizeof(m)) != 1) {
error_print();
return -1;
}
if (kyber_encap_ex(key, m, c, K) != 1) {
gmssl_secure_clear(m, sizeof(m));
error_print();
return -1;
}
gmssl_secure_clear(m, sizeof(m));
return 1;
}
int kyber_decap(const KYBER_KEY *key, const KYBER_CIPHERTEXT *c, uint8_t K[32])
{
uint8_t m_h[64];
uint8_t K_r[64];
uint8_t Kbar[32];
uint8_t z_c[32 + sizeof(KYBER_CIPHERTEXT)];
uint8_t *m = m_h;
uint8_t *h = m_h + 32;
uint8_t *K_ = K_r;
uint8_t *r = K_r + 32;
KYBER_CIPHERTEXT c_;
uint8_t mask;
int diff;
int i;
if (!key || !c || !K) {
error_print();
return -1;
}
// m' = Dec(sk, c)
if (kyber_cpa_decrypt(&key->cpa_key, c, m) != 1) {
gmssl_secure_clear(m_h, sizeof(m_h));
gmssl_secure_clear(K_r, sizeof(K_r));
gmssl_secure_clear(Kbar, sizeof(Kbar));
gmssl_secure_clear(z_c, sizeof(z_c));
gmssl_secure_clear(&c_, sizeof(c_));
error_print();
return -1;
}
@@ -1169,24 +1335,29 @@ int kyber_decap(const KYBER_KEY *key, const KYBER_CIPHERTEXT *c, uint8_t K[32])
if (kyber_cpa_encrypt(&key->cpa_key, m, r, &c_) != 1) {
gmssl_secure_clear(m_h, sizeof(m_h));
gmssl_secure_clear(K_r, sizeof(K_r));
gmssl_secure_clear(Kbar, sizeof(Kbar));
gmssl_secure_clear(z_c, sizeof(z_c));
gmssl_secure_clear(&c_, sizeof(c_));
error_print();
return -1;
}
// H(c)
kyber_h_hash((uint8_t *)c, sizeof(KYBER_CIPHERTEXT), r);
memcpy(z_c, key->z, 32);
memcpy(z_c + 32, c, sizeof(KYBER_CIPHERTEXT));
shake256(z_c, sizeof(z_c), Kbar, sizeof(Kbar));
if (memcmp(c, &c_, sizeof(KYBER_CIPHERTEXT)) == 0) {
// K = KDF(K_||H(c))
kyber_kdf(K_r, K);
} else {
error_print();
memcpy(K_r, key->z, 32); // TODO: const time
kyber_kdf(K_r, K);
memcpy(K, K_r, 32);
diff = gmssl_secure_memcmp(c, &c_, sizeof(KYBER_CIPHERTEXT));
mask = (uint8_t)(0 - (uint8_t)(diff == 0));
for (i = 0; i < 32; i++) {
K[i] = (K[i] & mask) | (Kbar[i] & ~mask);
}
gmssl_secure_clear(m_h, sizeof(m_h));
gmssl_secure_clear(K_r, sizeof(K_r));
gmssl_secure_clear(Kbar, sizeof(Kbar));
gmssl_secure_clear(z_c, sizeof(z_c));
gmssl_secure_clear(&c_, sizeof(c_));
return 1;
}

247
src/sha3.c Normal file
View File

@@ -0,0 +1,247 @@
/*
* 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 <string.h>
#include <gmssl/mem.h>
#include <gmssl/sha3.h>
static uint64_t load64_le(const uint8_t in[8])
{
return ((uint64_t)in[0])
| ((uint64_t)in[1] << 8)
| ((uint64_t)in[2] << 16)
| ((uint64_t)in[3] << 24)
| ((uint64_t)in[4] << 32)
| ((uint64_t)in[5] << 40)
| ((uint64_t)in[6] << 48)
| ((uint64_t)in[7] << 56);
}
static void store64_le(uint8_t out[8], uint64_t a)
{
out[0] = (uint8_t)a;
out[1] = (uint8_t)(a >> 8);
out[2] = (uint8_t)(a >> 16);
out[3] = (uint8_t)(a >> 24);
out[4] = (uint8_t)(a >> 32);
out[5] = (uint8_t)(a >> 40);
out[6] = (uint8_t)(a >> 48);
out[7] = (uint8_t)(a >> 56);
}
static uint64_t rol64(uint64_t a, int n)
{
return n ? ((a << n) | (a >> (64 - n))) : a;
}
static void keccak_f1600(uint64_t a[25])
{
static const uint64_t rc[24] = {
0x0000000000000001ULL, 0x0000000000008082ULL,
0x800000000000808aULL, 0x8000000080008000ULL,
0x000000000000808bULL, 0x0000000080000001ULL,
0x8000000080008081ULL, 0x8000000000008009ULL,
0x000000000000008aULL, 0x0000000000000088ULL,
0x0000000080008009ULL, 0x000000008000000aULL,
0x000000008000808bULL, 0x800000000000008bULL,
0x8000000000008089ULL, 0x8000000000008003ULL,
0x8000000000008002ULL, 0x8000000000000080ULL,
0x000000000000800aULL, 0x800000008000000aULL,
0x8000000080008081ULL, 0x8000000000008080ULL,
0x0000000080000001ULL, 0x8000000080008008ULL,
};
static const int rho[25] = {
0, 1, 62, 28, 27,
36, 44, 6, 55, 20,
3, 10, 43, 25, 39,
41, 45, 15, 21, 8,
18, 2, 61, 56, 14,
};
uint64_t b[25];
uint64_t c[5];
uint64_t d;
int round;
int x;
int y;
for (round = 0; round < 24; round++) {
for (x = 0; x < 5; x++) {
c[x] = a[x] ^ a[x + 5] ^ a[x + 10] ^ a[x + 15] ^ a[x + 20];
}
for (x = 0; x < 5; x++) {
d = c[(x + 4) % 5] ^ rol64(c[(x + 1) % 5], 1);
for (y = 0; y < 5; y++) {
a[x + 5 * y] ^= d;
}
}
for (x = 0; x < 5; x++) {
for (y = 0; y < 5; y++) {
b[y + 5 * ((2 * x + 3 * y) % 5)] =
rol64(a[x + 5 * y], rho[x + 5 * y]);
}
}
for (x = 0; x < 5; x++) {
for (y = 0; y < 5; y++) {
a[x + 5 * y] = b[x + 5 * y]
^ ((~b[((x + 1) % 5) + 5 * y])
& b[((x + 2) % 5) + 5 * y]);
}
}
a[0] ^= rc[round];
}
gmssl_secure_clear(b, sizeof(b));
gmssl_secure_clear(c, sizeof(c));
gmssl_secure_clear(&d, sizeof(d));
}
static void keccak_xor_block(uint64_t state[25], const uint8_t *block, size_t rate)
{
size_t i;
for (i = 0; i < rate / 8; i++) {
state[i] ^= load64_le(block + 8 * i);
}
}
static void keccak_store_block(uint8_t *block, const uint64_t state[25], size_t rate)
{
size_t i;
for (i = 0; i < rate / 8; i++) {
store64_le(block + 8 * i, state[i]);
}
}
static void keccak_init(SHAKE_CTX *ctx, size_t rate)
{
memset(ctx, 0, sizeof(*ctx));
ctx->rate = rate;
}
static void keccak_update(SHAKE_CTX *ctx, const uint8_t *in, size_t inlen)
{
size_t len;
while (inlen) {
len = ctx->rate - ctx->num;
if (len > inlen) {
len = inlen;
}
memcpy(ctx->block + ctx->num, in, len);
ctx->num += len;
in += len;
inlen -= len;
if (ctx->num == ctx->rate) {
keccak_xor_block(ctx->state, ctx->block, ctx->rate);
keccak_f1600(ctx->state);
gmssl_secure_clear(ctx->block, ctx->rate);
ctx->num = 0;
}
}
}
static void keccak_finish(SHAKE_CTX *ctx, uint8_t suffix)
{
memset(ctx->block + ctx->num, 0, ctx->rate - ctx->num);
ctx->block[ctx->num] ^= suffix;
ctx->block[ctx->rate - 1] ^= 0x80;
keccak_xor_block(ctx->state, ctx->block, ctx->rate);
keccak_f1600(ctx->state);
keccak_store_block(ctx->block, ctx->state, ctx->rate);
ctx->num = 0;
ctx->squeezing = 1;
}
static void keccak_squeeze(SHAKE_CTX *ctx, uint8_t *out, size_t outlen)
{
size_t len;
while (outlen) {
if (ctx->num == ctx->rate) {
keccak_f1600(ctx->state);
keccak_store_block(ctx->block, ctx->state, ctx->rate);
ctx->num = 0;
}
len = ctx->rate - ctx->num;
if (len > outlen) {
len = outlen;
}
memcpy(out, ctx->block + ctx->num, len);
ctx->num += len;
out += len;
outlen -= len;
}
}
static void keccak_digest(size_t rate, uint8_t suffix,
const uint8_t *in, size_t inlen, uint8_t *out, size_t outlen)
{
SHAKE_CTX ctx;
keccak_init(&ctx, rate);
keccak_update(&ctx, in, inlen);
keccak_finish(&ctx, suffix);
keccak_squeeze(&ctx, out, outlen);
gmssl_secure_clear(&ctx, sizeof(ctx));
}
void sha3_256(const uint8_t *in, size_t inlen, uint8_t out[SHA3_256_DIGEST_SIZE])
{
keccak_digest(136, 0x06, in, inlen, out, SHA3_256_DIGEST_SIZE);
}
void sha3_512(const uint8_t *in, size_t inlen, uint8_t out[SHA3_512_DIGEST_SIZE])
{
keccak_digest(72, 0x06, in, inlen, out, SHA3_512_DIGEST_SIZE);
}
void shake128_init(SHAKE_CTX *ctx)
{
keccak_init(ctx, 168);
}
void shake256_init(SHAKE_CTX *ctx)
{
keccak_init(ctx, 136);
}
void shake_update(SHAKE_CTX *ctx, const uint8_t *in, size_t inlen)
{
if (!ctx->squeezing) {
keccak_update(ctx, in, inlen);
}
}
void shake_finish(SHAKE_CTX *ctx)
{
if (!ctx->squeezing) {
keccak_finish(ctx, 0x1f);
}
}
void shake_squeeze(SHAKE_CTX *ctx, uint8_t *out, size_t outlen)
{
if (!ctx->squeezing) {
keccak_finish(ctx, 0x1f);
}
keccak_squeeze(ctx, out, outlen);
}
void shake128(const uint8_t *in, size_t inlen, uint8_t *out, size_t outlen)
{
keccak_digest(168, 0x1f, in, inlen, out, outlen);
}
void shake256(const uint8_t *in, size_t inlen, uint8_t *out, size_t outlen)
{
keccak_digest(136, 0x1f, in, inlen, out, outlen);
}