[PATCH] Add stack burning for PQC algorithms
Jussi Kivilinna
jussi.kivilinna at iki.fi
Sat Sep 27 11:52:24 CEST 2025
* cipher/dilithium.h (DILITHIUM_KEYPAIR_STACK_BURN)
(DILITHIUM_SIGN_STACK_BURN, DILITHIUM_VERIFY_STACK_BURN): New.
* cipher/kem.c (_gcry_kem_genkey, _gcry_kem_encap)
(_gcry_kem_decap): Burn stack after calls to sntrup761, kyber and
mceliece6688128f algos.
* cipher/kyber.h (KYBER_KEYPAIR_STACK_BURN, KYBER_ENCAP_STACK_BURN)
(KYBER_DECAP_STACK_BURN): New.
* cipher/mceliece6688128f.h (MCELIECE6688128F_KEYPAIR_STACK_BURN)
(MCELIECE6688128F_ENC_STACK_BURN, MCELIECE6688128F_DEC_STACK_BURN): New.
* cipher/pubkey-dilithium.c (mldsa_generate, mldsa_sign)
(mldsa_verify): Burn stack after calls to dilithium algo.
* cipher/sntrup761.h (SNTRUP761_KEYPAIR_STACK_BURN)
(SNTRUP761_ENC_STACK_BURN, SNTRUP761_DEC_STACK_BURN): New.
--
Stack usage measured on GCC-14 build on x86-64/linux with
additional +33% margin added and rounded up to closest 1 KiB.
Signed-off-by: Jussi Kivilinna <jussi.kivilinna at iki.fi>
---
cipher/dilithium.h | 4 ++++
cipher/kem.c | 11 +++++++++++
cipher/kyber.h | 13 +++++++++++++
cipher/mceliece6688128f.h | 4 ++++
cipher/pubkey-dilithium.c | 3 +++
cipher/sntrup761.h | 4 ++++
6 files changed, 39 insertions(+)
diff --git a/cipher/dilithium.h b/cipher/dilithium.h
index 03a095c7..88a48094 100644
--- a/cipher/dilithium.h
+++ b/cipher/dilithium.h
@@ -60,6 +60,10 @@
#define dilithium_decap _gcry_mldsa_decap
/**** End of the glue code ****/
+#define DILITHIUM_KEYPAIR_STACK_BURN (128 * 1024)
+#define DILITHIUM_SIGN_STACK_BURN (161 * 1024)
+#define DILITHIUM_VERIFY_STACK_BURN (122 * 1024)
+
int dilithium_keypair (int algo, uint8_t *pk, uint8_t *sk,
const uint8_t seed[SEEDBYTES]);
int dilithium_sign (int algo, uint8_t *sig, size_t siglen,
diff --git a/cipher/kem.c b/cipher/kem.c
index 072249e2..2a432a0a 100644
--- a/cipher/kem.c
+++ b/cipher/kem.c
@@ -96,10 +96,12 @@ _gcry_kem_genkey (int algo,
|| pubkey_len != GCRY_KEM_SNTRUP761_PUBKEY_LEN)
return GPG_ERR_INV_ARG;
sntrup761_keypair (pubkey, seckey, NULL, sntrup761_random);
+ _gcry_burn_stack (SNTRUP761_KEYPAIR_STACK_BURN);
return 0;
case GCRY_KEM_CM6688128F:
mceliece6688128f_keypair (pubkey, seckey);
+ _gcry_burn_stack (MCELIECE6688128F_KEYPAIR_STACK_BURN);
return 0;
#if USE_KYBER
@@ -109,6 +111,7 @@ _gcry_kem_genkey (int algo,
|| (optional && optional_len != GCRY_KEM_MLKEM_RANDOM_LEN*2))
return GPG_ERR_INV_ARG;
kyber_keypair (algo, pubkey, seckey, optional);
+ _gcry_burn_stack (KYBER_KEYPAIR_STACK_BURN (algo));
return 0;
case GCRY_KEM_MLKEM768:
@@ -117,6 +120,7 @@ _gcry_kem_genkey (int algo,
|| (optional && optional_len != GCRY_KEM_MLKEM_RANDOM_LEN*2))
return GPG_ERR_INV_ARG;
kyber_keypair (algo, pubkey, seckey, optional);
+ _gcry_burn_stack (KYBER_KEYPAIR_STACK_BURN (algo));
return 0;
case GCRY_KEM_MLKEM1024:
@@ -125,6 +129,7 @@ _gcry_kem_genkey (int algo,
|| (optional && optional_len != GCRY_KEM_MLKEM_RANDOM_LEN*2))
return GPG_ERR_INV_ARG;
kyber_keypair (algo, pubkey, seckey, optional);
+ _gcry_burn_stack (KYBER_KEYPAIR_STACK_BURN (algo));
return 0;
#endif
@@ -166,12 +171,14 @@ _gcry_kem_encap (int algo,
|| shared_len != GCRY_KEM_SNTRUP761_SHARED_LEN)
return GPG_ERR_INV_VALUE;
sntrup761_enc (ciphertext, shared, pubkey, NULL, sntrup761_random);
+ _gcry_burn_stack (SNTRUP761_ENC_STACK_BURN);
return 0;
case GCRY_KEM_CM6688128F:
if (optional != NULL)
return GPG_ERR_INV_VALUE;
mceliece6688128f_enc (ciphertext, shared, pubkey);
+ _gcry_burn_stack (MCELIECE6688128F_ENC_STACK_BURN);
return 0;
#if USE_KYBER
@@ -181,6 +188,7 @@ _gcry_kem_encap (int algo,
if (optional && optional_len != GCRY_KEM_MLKEM_RANDOM_LEN)
return GPG_ERR_INV_VALUE;
kyber_encap (algo, ciphertext, shared, pubkey, optional);
+ _gcry_burn_stack (KYBER_ENCAP_STACK_BURN (algo));
return 0;
#endif
@@ -228,12 +236,14 @@ _gcry_kem_decap (int algo,
|| shared_len != GCRY_KEM_SNTRUP761_SHARED_LEN)
return GPG_ERR_INV_VALUE;
sntrup761_dec (shared, ciphertext, seckey);
+ _gcry_burn_stack (SNTRUP761_DEC_STACK_BURN);
return 0;
case GCRY_KEM_CM6688128F:
if (optional != NULL)
return GPG_ERR_INV_VALUE;
mceliece6688128f_dec (shared, ciphertext, seckey);
+ _gcry_burn_stack (MCELIECE6688128F_DEC_STACK_BURN);
return 0;
#if USE_KYBER
@@ -243,6 +253,7 @@ _gcry_kem_decap (int algo,
if (optional != NULL)
return GPG_ERR_INV_VALUE;
kyber_decap (algo, shared, ciphertext, seckey);
+ _gcry_burn_stack (KYBER_DECAP_STACK_BURN (algo));
return 0;
#endif
diff --git a/cipher/kyber.h b/cipher/kyber.h
index b1ba0eab..0ef2eb65 100644
--- a/cipher/kyber.h
+++ b/cipher/kyber.h
@@ -60,6 +60,19 @@
#define kyber_decap _gcry_mlkem_decap
/**** End of the glue code ****/
+#define KYBER_KEYPAIR_STACK_BURN(algo) \
+ ((algo) == GCRY_KEM_MLKEM512 ? (9 * 1024) : \
+ (algo) == GCRY_KEM_MLKEM768 ? (15 * 1024) : \
+ /* MLKEM1024*/ (21 * 1024))
+#define KYBER_ENCAP_STACK_BURN(algo) \
+ ((algo) == GCRY_KEM_MLKEM512 ? (13 * 1024) : \
+ (algo) == GCRY_KEM_MLKEM768 ? (19 * 1024) : \
+ /* MLKEM1024*/ (26 * 1024))
+#define KYBER_DECAP_STACK_BURN(algo) \
+ ((algo) == GCRY_KEM_MLKEM512 ? (18 * 1024) : \
+ (algo) == GCRY_KEM_MLKEM768 ? (25 * 1024) : \
+ /* MLKEM1024*/ (35 * 1024))
+
void kyber_keypair (int algo, uint8_t *pk, uint8_t *sk, const uint8_t *coins);
void kyber_encap (int algo, uint8_t *ct, uint8_t *ss, const uint8_t *pk,
const uint8_t *coins);
diff --git a/cipher/mceliece6688128f.h b/cipher/mceliece6688128f.h
index eb9f23a0..4b1b35c9 100644
--- a/cipher/mceliece6688128f.h
+++ b/cipher/mceliece6688128f.h
@@ -30,6 +30,10 @@
#include "g10lib.h" /* for GCC_ATTR_UNUSED */
#include "gcrypt-int.h"
+#define MCELIECE6688128F_KEYPAIR_STACK_BURN (360 * 1024)
+#define MCELIECE6688128F_ENC_STACK_BURN (9 * 1024)
+#define MCELIECE6688128F_DEC_STACK_BURN (80 * 1024)
+
#define mceliece6688128f_keypair _gcry_mceliece6688128f_keypair
#define mceliece6688128f_enc _gcry_mceliece6688128f_enc
#define mceliece6688128f_dec _gcry_mceliece6688128f_dec
diff --git a/cipher/pubkey-dilithium.c b/cipher/pubkey-dilithium.c
index 7f87a99f..03958bb0 100644
--- a/cipher/pubkey-dilithium.c
+++ b/cipher/pubkey-dilithium.c
@@ -171,6 +171,7 @@ mldsa_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey)
}
dilithium_keypair (info->algo, pk, sk, seed);
+ _gcry_burn_stack (DILITHIUM_KEYPAIR_STACK_BURN);
if (!rc)
rc = sexp_build (r_skey,
@@ -262,6 +263,7 @@ mldsa_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms)
else
r = dilithium_sign (info->algo, sig, info->sig_len, data, data_len,
ctx.label, ctx.labellen, sk, rnd);
+ _gcry_burn_stack (DILITHIUM_SIGN_STACK_BURN);
if (r < 0)
{
rc = GPG_ERR_INTERNAL;
@@ -353,6 +355,7 @@ mldsa_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms)
else
r = dilithium_verify (info->algo, sig, info->sig_len, data, data_len,
ctx.label, ctx.labellen, pk);
+ _gcry_burn_stack (DILITHIUM_VERIFY_STACK_BURN);
if (r < 0)
{
rc = GPG_ERR_BAD_SIGNATURE;
diff --git a/cipher/sntrup761.h b/cipher/sntrup761.h
index a9974bb0..88f7a902 100644
--- a/cipher/sntrup761.h
+++ b/cipher/sntrup761.h
@@ -46,6 +46,10 @@ crypto_hash_sha512 (unsigned char *out,
_gcry_md_hash_buffer (GCRY_MD_SHA512, out, in, inlen);
}
+#define SNTRUP761_KEYPAIR_STACK_BURN (26 * 1024)
+#define SNTRUP761_ENC_STACK_BURN (23 * 1024)
+#define SNTRUP761_DEC_STACK_BURN (34 * 1024)
+
#define sntrup761_keypair _gcry_sntrup761_keypair
#define sntrup761_enc _gcry_sntrup761_enc
#define sntrup761_dec _gcry_sntrup761_dec
--
2.48.1
More information about the Gcrypt-devel
mailing list