https://github.com/smuellerDD/leancrypto/commit/eb0ba53f220bc4fcc435c16da60e0892933af656
https://github.com/smuellerDD/leancrypto/commit/ec82fd19ba6e995bedb4987c2334c6f760eec3aa

From eb0ba53f220bc4fcc435c16da60e0892933af656 Mon Sep 17 00:00:00 2001
From: Stephan Mueller <smueller@chronox.de>
Date: Thu, 27 Nov 2025 23:12:03 +0100
Subject: [PATCH] Curve25519/448: Compile API code as pure C

Considering that the API functions are invoked without checking for
accelerations, they MUST be compiled without any accelerated options.

This prevents a SIGILL when the respective option is not available
on the target platform

Reported-by: Alexander Sosedkin
Signed-off-by: Stephan Mueller <smueller@chronox.de>
---
 curve25519/src/armv7/curve25519_armv7.c      | 4 ++--
 curve25519/src/armv7/meson.build             | 1 -
 curve25519/src/armv8/curve25519_armv8.c      | 2 +-
 curve25519/src/armv8/meson.build             | 1 -
 curve25519/src/avx/curve25519_avx.c          | 4 ++--
 curve25519/src/avx/meson.build               | 1 -
 curve25519/src/meson.build                   | 9 +++++++++
 curve448/src/avx2/curve448_scalarmult_avx2.c | 4 ++--
 curve448/src/avx2/meson.build                | 1 -
 curve448/src/meson.build                     | 3 +++
 10 files changed, 19 insertions(+), 11 deletions(-)

diff --git a/curve25519/src/armv7/curve25519_armv7.c b/curve25519/src/armv7/curve25519_armv7.c
index 5d03bfec..c988f6fc 100644
--- a/curve25519/src/armv7/curve25519_armv7.c
+++ b/curve25519/src/armv7/curve25519_armv7.c
@@ -19,8 +19,8 @@
 
 #include "cpufeatures.h"
 #include "curve25519_armv7.h"
-#include "x25519_scalarmult.h"
-#include "x25519_scalarmult_c.h"
+#include "../x25519_scalarmult.h"
+#include "../x25519_scalarmult_c.h"
 
 int crypto_scalarmult_curve25519(unsigned char *q, const unsigned char *n,
 				 const unsigned char *p)
diff --git a/curve25519/src/armv7/meson.build b/curve25519/src/armv7/meson.build
index 5768d836..d06c9212 100644
--- a/curve25519/src/armv7/meson.build
+++ b/curve25519/src/armv7/meson.build
@@ -1,7 +1,6 @@
 # for i in $(ls *.c | sort); do echo "'$i',"; done
 
 curve25519_armv7 = files([
-	'curve25519_armv7.c',
 	'x25519-cortex-m4-gcc.S',
 ])
 
diff --git a/curve25519/src/armv8/curve25519_armv8.c b/curve25519/src/armv8/curve25519_armv8.c
index 892ca053..a74bbcdd 100644
--- a/curve25519/src/armv8/curve25519_armv8.c
+++ b/curve25519/src/armv8/curve25519_armv8.c
@@ -21,7 +21,7 @@
 #include "cpufeatures.h"
 #include "curve25519_armv8.h"
 #include "lc_memset_secure.h"
-#include "x25519_scalarmult.h"
+#include "../x25519_scalarmult.h"
 
 int crypto_scalarmult_curve25519(unsigned char *q, const unsigned char *n,
 				 const unsigned char *p)
diff --git a/curve25519/src/armv8/meson.build b/curve25519/src/armv8/meson.build
index bc3610e4..508d44e5 100644
--- a/curve25519/src/armv8/meson.build
+++ b/curve25519/src/armv8/meson.build
@@ -1,7 +1,6 @@
 # for i in $(ls *.c | sort); do echo "'$i',"; done
 
 curve25519_armv8 = files([
-	'curve25519_armv8.c',
 	'X25519-AArch64.S',
 ])
 
diff --git a/curve25519/src/avx/curve25519_avx.c b/curve25519/src/avx/curve25519_avx.c
index ef605d54..9430d6d4 100644
--- a/curve25519/src/avx/curve25519_avx.c
+++ b/curve25519/src/avx/curve25519_avx.c
@@ -40,8 +40,8 @@
 #include "fe51.h"
 #include "ladder.h"
 #include "lc_memset_secure.h"
-#include "x25519_scalarmult.h"
-#include "x25519_scalarmult_c.h"
+#include "../x25519_scalarmult.h"
+#include "../x25519_scalarmult_c.h"
 
 #define x1 var[0]
 #define x2 var[1]
diff --git a/curve25519/src/avx/meson.build b/curve25519/src/avx/meson.build
index ecf7706c..dde3e1ce 100644
--- a/curve25519/src/avx/meson.build
+++ b/curve25519/src/avx/meson.build
@@ -1,7 +1,6 @@
 # for i in $(ls *.c | sort); do echo "'$i',"; done
 
 curve25519_avx = files([
-	'curve25519_avx.c',
 	'curve25519_avx_asm.S',
 	'fe51_invert.c',
 	'fe_frombytes_avx.c',
diff --git a/curve25519/src/meson.build b/curve25519/src/meson.build
index c5930bb6..8fa85dee 100644
--- a/curve25519/src/meson.build
+++ b/curve25519/src/meson.build
@@ -12,10 +12,19 @@ if get_option('kyber_x25519').enabled()
 
 	if (x86_64_asm)
 		subdir('avx')
+		src += files([
+			'avx/curve25519_avx.c',
+		])
 	elif (arm64_asm)
 		subdir('armv8')
+		src += files([
+			'armv8/curve25519_armv8.c',
+		])
 	elif (arm32_neon_asm)
 		subdir('armv7')
+		src += files([
+			'armv7/curve25519_armv7.c',
+		])
 	else
 		src += files([
 			'x25519_scalarmult.c',
diff --git a/curve448/src/avx2/curve448_scalarmult_avx2.c b/curve448/src/avx2/curve448_scalarmult_avx2.c
index 1c94662e..2d180b37 100644
--- a/curve448/src/avx2/curve448_scalarmult_avx2.c
+++ b/curve448/src/avx2/curve448_scalarmult_avx2.c
@@ -65,8 +65,8 @@
 #include "lc_memset_secure.h"
 #include "lc_x448.h"
 #include "small_stack_support.h"
-#include "x448_scalarmult.h"
-#include "x448_scalarmult_c.h"
+#include "../x448_scalarmult.h"
+#include "../x448_scalarmult_c.h"
 
 static const uint8_t curve448_base_point[LC_X448_PUBLICKEYBYTES] = { 5 };
 
diff --git a/curve448/src/avx2/meson.build b/curve448/src/avx2/meson.build
index 1fb2dffc..9fa2f827 100644
--- a/curve448/src/avx2/meson.build
+++ b/curve448/src/avx2/meson.build
@@ -1,7 +1,6 @@
 # for i in $(ls *.c | sort); do echo "'$i',"; done
 
 curve448_avx2 = files([
-	'curve448_scalarmult_avx2.c',
 	'gf_p4482241_inv.c',
 	'curve448_scalarmult_avx2_asm.S',
 	'gf_p4482241_pack.c',
diff --git a/curve448/src/meson.build b/curve448/src/meson.build
index cc49b878..88c792b0 100644
--- a/curve448/src/meson.build
+++ b/curve448/src/meson.build
@@ -22,6 +22,9 @@ if get_option('kyber_x448').enabled()
 
 	if (x86_64_asm)
 		subdir('avx2')
+		src += files([
+			'avx2/curve448_scalarmult_avx2.c',
+		])
 	else
 		src += files([
 			'x448_scalarmult.c',

From ec82fd19ba6e995bedb4987c2334c6f760eec3aa Mon Sep 17 00:00:00 2001
From: Stephan Mueller <smueller@chronox.de>
Date: Thu, 27 Nov 2025 22:49:58 +0100
Subject: [PATCH] ML-KEM/DSA/HQC: Compile API code as pure C

Considering that the API functions are invoked without checking for
accelerations, they MUST be compiled without any accelerated options.

This prevents a SIGILL when the respective option is not available
on the target platform

Reported-by: Alexander Sosedkin
Signed-off-by: Stephan Mueller <smueller@chronox.de>
---
 hqc/api/hqc_type.h              |  3 ++
 hqc/src/avx2/hqc_kem_api_avx2.c |  1 -
 hqc/src/avx2/meson.build        |  5 ++-
 hqc/src/hqc_internal.h          |  3 --
 hqc/src/meson.build             |  3 ++
 ml-dsa/src/armv7/meson.build    |  1 -
 ml-dsa/src/armv8/meson.build    |  1 -
 ml-dsa/src/avx2/meson.build     |  1 -
 ml-dsa/src/meson.build          | 60 ++++++++++++++++++++++++++++-----
 ml-dsa/src/riscv64/meson.build  |  1 -
 ml-kem/src/armv8/meson.build    |  1 -
 ml-kem/src/avx2/meson.build     |  1 -
 ml-kem/src/meson.build          | 26 ++++++++++----
 ml-kem/src/riscv64/meson.build  | 52 ----------------------------
 14 files changed, 82 insertions(+), 77 deletions(-)

diff --git a/hqc/api/hqc_type.h b/hqc/api/hqc_type.h
index 8a0daf1f..dad81927 100644
--- a/hqc/api/hqc_type.h
+++ b/hqc/api/hqc_type.h
@@ -152,6 +152,9 @@ extern "C" {
 #define gf_mul_vect_avx2 HQC_F(gf_mul_vect_avx2)
 #define gf_mod_avx2 HQC_F(gf_mod_avx2)
 
+int lc_hqc_enc_internal(struct lc_hqc_ct *ct, struct lc_hqc_ss *ss,
+			const struct lc_hqc_pk *pk, struct lc_rng_ctx *rng_ctx);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/hqc/src/avx2/hqc_kem_api_avx2.c b/hqc/src/avx2/hqc_kem_api_avx2.c
index b2edfe58..4e6e5959 100644
--- a/hqc/src/avx2/hqc_kem_api_avx2.c
+++ b/hqc/src/avx2/hqc_kem_api_avx2.c
@@ -19,7 +19,6 @@
 
 #include "compare.h"
 #include "cpufeatures.h"
-#include "hqc_internal_avx2.h"
 #include "hqc_kem_avx2.h"
 #include "../hqc_selftest.h"
 #include "../hqc_kem_c.h"
diff --git a/hqc/src/avx2/meson.build b/hqc/src/avx2/meson.build
index d8835fbf..24bd2703 100644
--- a/hqc/src/avx2/meson.build
+++ b/hqc/src/avx2/meson.build
@@ -1,12 +1,15 @@
 # for i in $(ls *.c | sort); do echo "'$i',"; done
 
+hqc_src_c = files([
+	'hqc_kem_api_avx2.c',
+])
+
 hqc_src_avx2 = files([
 	'code_avx2.c',
 	'fft_avx2.c',
 	'gf_avx2.c',
 	'gf2x_avx2.c',
 	'hqc_avx2.c',
-	'hqc_kem_api_avx2.c',
 	'hqc_kem_avx2.c',
 	'parsing_avx2.c',
 	'reed_muller_avx2.c',
diff --git a/hqc/src/hqc_internal.h b/hqc/src/hqc_internal.h
index 25ded1ff..3a884d93 100644
--- a/hqc/src/hqc_internal.h
+++ b/hqc/src/hqc_internal.h
@@ -85,9 +85,6 @@ struct hqc_pke_decrypt_ws {
 	} wsu;
 };
 
-int lc_hqc_enc_internal(struct lc_hqc_ct *ct, struct lc_hqc_ss *ss,
-			const struct lc_hqc_pk *pk, struct lc_rng_ctx *rng_ctx);
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/hqc/src/meson.build b/hqc/src/meson.build
index 2b14869f..44ac9dd1 100644
--- a/hqc/src/meson.build
+++ b/hqc/src/meson.build
@@ -25,6 +25,9 @@ hqc_src = files([
 if (hqc_enabled)
 	if (x86_64_asm)
 		subdir('avx2')
+		hqc_src += files([
+			'avx2/hqc_kem_api_avx2.c',
+		])
 	else
 		hqc_src += files([
 			'hqc_kem_api_c.c'
diff --git a/ml-dsa/src/armv7/meson.build b/ml-dsa/src/armv7/meson.build
index 9c92eb21..078dabab 100644
--- a/ml-dsa/src/armv7/meson.build
+++ b/ml-dsa/src/armv7/meson.build
@@ -13,7 +13,6 @@ dilithium_armv7 = files([
 	'dilithium_pointwise_smull_armv7.S',
 	'dilithium_poly.c',
 	'dilithium_poly_armv7.S',
-	'dilithium_signature_api_armv7.c',
 	'dilithium_signature_armv7.c'
 ])
 
diff --git a/ml-dsa/src/armv8/meson.build b/ml-dsa/src/armv8/meson.build
index 71eb2ae4..803a4fee 100644
--- a/ml-dsa/src/armv8/meson.build
+++ b/ml-dsa/src/armv8/meson.build
@@ -14,7 +14,6 @@ dilithium_armv8 = files([
 	'dilithium_ntt_armv8.S',
 	'dilithium_poly.c',
 	'dilithium_poly_armv8.S',
-	'dilithium_signature_api_armv8.c',
 	'dilithium_signature_armv8.c'
 ])
 
diff --git a/ml-dsa/src/avx2/meson.build b/ml-dsa/src/avx2/meson.build
index 8e16644f..5d19ee3e 100644
--- a/ml-dsa/src/avx2/meson.build
+++ b/ml-dsa/src/avx2/meson.build
@@ -16,7 +16,6 @@ dilithium_avx2 = files([
 	'dilithium_polyvec_avx2.c',
 	'dilithium_rejsample_avx2.c',
 	'dilithium_rounding_avx2.c',
-	'dilithium_signature_api_avx2.c',
 	'dilithium_signature_avx2.c',
 	'dilithium_shuffle_avx2.S',
 ])
diff --git a/ml-dsa/src/meson.build b/ml-dsa/src/meson.build
index 361657a3..2c7a3130 100644
--- a/ml-dsa/src/meson.build
+++ b/ml-dsa/src/meson.build
@@ -28,7 +28,6 @@ if get_option('dilithium_ed448').enabled()
 	dilithium_c += files ([ 'dilithium_ed448_signature.c' ])
 endif
 
-dilithium_api_c = 0
 if (dilithium_enabled)
 	if (x86_64_asm)
 		subdir('avx2')
@@ -39,17 +38,34 @@ if (dilithium_enabled)
 		subdir('armv7')
 	elif (riscv64_asm)
 		subdir('riscv64')
-	else
-		dilithium_api_c = 1
-		dilithium_c += files([
-			'dilithium_signature_api_c.c'
-		])
 	endif
 endif
 
 if get_option('dilithium_87').enabled()
 	dilithium_87_files = dilithium_c
 
+	if (x86_64_asm)
+		dilithium_87_files += files([
+			'avx2/dilithium_signature_api_avx2.c'
+		])
+	elif (arm64_asm)
+		dilithium_87_files += files([
+			'armv8/dilithium_signature_api_armv8.c'
+		])
+	elif (arm32_neon_asm)
+		dilithium_87_files += files([
+			'armv7/dilithium_signature_api_armv7.c'
+		])
+	elif (riscv64_asm)
+		dilithium_87_files += files([
+			'riscv64/dilithium_signature_api_riscv64.c'
+		])
+	else
+		dilithium_87_files += files([
+			'dilithium_signature_api_c.c'
+		])
+	endif
+
 	leancrypto_dilithium_87_c_lib = static_library(
 		'leancrypto_dilithium_87_c_lib',
 		[ dilithium_87_files ],
@@ -64,6 +80,28 @@ endif
 if get_option('dilithium_65').enabled()
 	dilithium_65_files = dilithium_c
 
+	if (x86_64_asm)
+		dilithium_65_files += files([
+			'avx2/dilithium_signature_api_avx2.c'
+		])
+	elif (arm64_asm)
+		dilithium_65_files += files([
+			'armv8/dilithium_signature_api_armv8.c'
+		])
+	elif (arm32_neon_asm)
+		dilithium_65_files += files([
+			'armv7/dilithium_signature_api_armv7.c'
+		])
+	elif (riscv64_asm)
+		dilithium_65_files += files([
+			'riscv64/dilithium_signature_api_riscv64.c'
+		])
+	else
+		dilithium_65_files += files([
+			'dilithium_signature_api_c.c'
+		])
+	endif
+
 	leancrypto_dilithium_65_c_lib = static_library(
 		'leancrypto_dilithium_65_c_lib',
 		[ dilithium_65_files ],
@@ -79,8 +117,14 @@ endif
 if get_option('dilithium_44').enabled()
 	dilithium_44_files = dilithium_c
 
-	if (not riscv64_asm and (dilithium_api_c == 0))
-		dilithium_44_files += files([ 'dilithium_signature_api_c.c' ])
+	if (riscv64_asm)
+		dilithium_44_files += files([
+			'riscv64/dilithium_signature_api_riscv64.c'
+		])
+	else
+		dilithium_44_files += files([
+			'dilithium_signature_api_c.c'
+		])
 	endif
 
 	leancrypto_dilithium_44_c_lib = static_library(
diff --git a/ml-dsa/src/riscv64/meson.build b/ml-dsa/src/riscv64/meson.build
index 1a5ac214..e168e4bf 100644
--- a/ml-dsa/src/riscv64/meson.build
+++ b/ml-dsa/src/riscv64/meson.build
@@ -6,7 +6,6 @@ src += files([
 
 # Files which are compiled for each Dilithium implementation separately
 dilithium_riscv64_asm = files([
-	'dilithium_signature_api_riscv64.c',
 	'dilithium_signature_riscv64.c',
 	'ntt_8l_dualissue_plant_rv64im.S'
 ])
diff --git a/ml-kem/src/armv8/meson.build b/ml-kem/src/armv8/meson.build
index cb88feb4..b8caab3c 100644
--- a/ml-kem/src/armv8/meson.build
+++ b/ml-kem/src/armv8/meson.build
@@ -14,7 +14,6 @@ kyber_armv8 = files([
 	'kyber_cbd_armv8.S',
 	'kyber_indcpa_armv8.c',
 	'kyber_inv_ntt_armv8.S',
-	'kyber_kem_api_armv8.c',
 	'kyber_kem_armv8.c',
 	'kyber_ntt_armv8_asm.S',
 	'kyber_poly_armv8_asm.S',
diff --git a/ml-kem/src/avx2/meson.build b/ml-kem/src/avx2/meson.build
index 4aa6f5a6..7bb82cf1 100644
--- a/ml-kem/src/avx2/meson.build
+++ b/ml-kem/src/avx2/meson.build
@@ -12,7 +12,6 @@ kyber_avx2 = files([
 	'kyber_fq_avx2.S',
 	'kyber_indcpa_avx2.c',
 	'kyber_invntt_avx2.S',
-	'kyber_kem_api_avx2.c',
 	'kyber_kem_avx2.c',
 	'kyber_ntt_avx2.S',
 	'kyber_poly_avx2.c',
diff --git a/ml-kem/src/meson.build b/ml-kem/src/meson.build
index 43ed1c90..f8c2f96f 100644
--- a/ml-kem/src/meson.build
+++ b/ml-kem/src/meson.build
@@ -63,18 +63,32 @@ if (x86_64_asm)
 	subdir('avx2')
 elif (arm64_asm)
 	subdir('armv8')
+	kyber_c += files ([
+		'armv8/kyber_kem_api_armv8.c',
+	])
 elif (arm32_neon_asm)
 	subdir('armv7')
+	kyber_c += files([
+		'kyber_kem_api_c.c',
+	])
 elif (riscv64_asm)
 	subdir('riscv64')
+	kyber_c += files([
+		'riscv64/kyber_kem_api_riscv.c',
+	])
+else
+	kyber_c += files([
+		'kyber_kem_api_c.c',
+	])
 endif
 
 if get_option('kyber_1024').enabled()
 	kyber_1024_files = kyber_c
 
-	if (not x86_64_asm and not arm64_asm and not riscv64_asm)
-		kyber_1024_files += files([ 'kyber_kem_api_c.c' ])
+	if (x86_64_asm)
+		kyber_1024_files += files ([ 'avx2/kyber_kem_api_avx2.c' ])
 	endif
+
 	leancrypto_kyber_1024_c_lib = static_library(
 		'leancrypto_kyber_1024_c_lib',
 		[ kyber_1024_files ],
@@ -89,8 +103,8 @@ endif
 if get_option('kyber_768').enabled()
 	kyber_768_files = kyber_c
 
-	if (not x86_64_asm and not arm64_asm and not riscv64_asm)
-		kyber_768_files += files([ 'kyber_kem_api_c.c' ])
+	if (x86_64_asm)
+		kyber_768_files += files ([ 'avx2/kyber_kem_api_avx2.c' ])
 	endif
 
 	leancrypto_kyber_768_c_lib = static_library(
@@ -108,8 +122,8 @@ endif
 if get_option('kyber_512').enabled()
 	kyber_512_files = kyber_c
 
-	if (not riscv64_asm)
-		kyber_512_files += files([ 'kyber_kem_api_c.c' ])
+	if (x86_64_asm)
+		kyber_512_files += files ([ 'kyber_kem_api_c.c' ])
 	endif
 
 	leancrypto_kyber_512_c_lib = static_library(
diff --git a/ml-kem/src/riscv64/meson.build b/ml-kem/src/riscv64/meson.build
index 9ce75439..c498989a 100644
--- a/ml-kem/src/riscv64/meson.build
+++ b/ml-kem/src/riscv64/meson.build
@@ -7,10 +7,6 @@ kyber_riscv_rvv_common = files([
 	'riscv_rvv_selector_test.S'
 ])
 
-kyber_riscv_riscv_api = files([
-	'kyber_kem_api_riscv.c',
-])
-
 kyber_riscv_rvv_vlen128 = files([
 	'kyber_indcpa_rvv_vlen128.c',
 	'kyber_kem_rvv_vlen128.c',
@@ -70,54 +66,6 @@ if (get_option('kyber_1024').enabled() or
 	leancrypto_support_libs += leancrypto_kyber_riscv_rvv_lib
 endif
 
-# Kyber RISCV API
-if get_option('kyber_1024').enabled()
-	kyber_1024_files = kyber_riscv_riscv_api
-
-	leancrypto_kyber_1024_riscv_lib = static_library(
-		'leancrypto_kyber_1024_riscv_lib',
-		[ kyber_1024_files ],
-		include_directories: [
-			'../',
-			include_dirs,
-			include_internal_dirs
-		],
-	)
-	leancrypto_support_libs += leancrypto_kyber_1024_riscv_lib
-endif
-
-if get_option('kyber_768').enabled()
-	kyber_768_files = kyber_riscv_riscv_api
-
-	leancrypto_kyber_768_riscv_lib = static_library(
-		'leancrypto_kyber_768_riscv_lib',
-		[ kyber_768_files ],
-		include_directories: [
-			'../',
-			include_dirs,
-			include_internal_dirs
-		],
-		c_args : [ '-DLC_KYBER_TYPE_768']
-	)
-	leancrypto_support_libs += leancrypto_kyber_768_riscv_lib
-endif
-
-if get_option('kyber_512').enabled()
-	kyber_512_files = kyber_riscv_riscv_api
-
-	leancrypto_kyber_512_riscv_lib = static_library(
-		'leancrypto_kyber_512_riscv_lib',
-		[ kyber_512_files ],
-		include_directories: [
-			'../',
-			include_dirs,
-			include_internal_dirs
-		],
-		c_args : [ '-DLC_KYBER_TYPE_512' ]
-	)
-	leancrypto_support_libs += leancrypto_kyber_512_riscv_lib
-endif
-
 # Kyber RVV vector length 128
 if get_option('riscv_rvv_vlen128').enabled()
 	if get_option('kyber_1024').enabled()
