[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