@@ -24781,6 +24781,135 @@ int test_mldsa_pkcs8_export_import_wolfSSL_form(void)
2478124781 return EXPECT_RESULT();
2478224782}
2478324783
24784+ /* Exercise w1 encoding with adversarial inputs to catch undefined behavior.
24785+ *
24786+ * The word32-optimized paths in dilithium_encode_w1_88_c and
24787+ * dilithium_encode_w1_32_c left-shift sword32 values by up to 30 bits.
24788+ * Large or invalid w1 values trigger signed integer overflow (UB in C).
24789+ * Under -fsanitize=undefined this test will trap on the offending shifts.
24790+ *
24791+ * We also test that encoding the same input twice yields identical output
24792+ * (determinism check - UB can cause nondeterministic results).
24793+ */
24794+ int test_wc_dilithium_encode_w1_large_values(void)
24795+ {
24796+ EXPECT_DECLS;
24797+ #if defined(HAVE_DILITHIUM) && defined(WOLFSSL_WC_DILITHIUM) && \
24798+ (!defined(WOLFSSL_DILITHIUM_NO_SIGN) || \
24799+ !defined(WOLFSSL_DILITHIUM_NO_VERIFY))
24800+
24801+ sword32 w1[DILITHIUM_N];
24802+ unsigned int j, k;
24803+
24804+ /* Adversarial w1 values:
24805+ * - valid boundary values (0, 1, max-for-bit-width)
24806+ * - oversize values that exceed the expected bit width
24807+ * - negative values (should never appear but might if prior step is buggy)
24808+ * - extreme values near INT32 limits
24809+ * - alternating patterns that stress cross-element packing
24810+ */
24811+ const sword32 patterns[] = {
24812+ 0, /* trivial zero */
24813+ 1, /* minimal nonzero */
24814+ 0x7F, /* 7 bits set - wider than both 4-bit and 6-bit */
24815+ 0xFF, /* full byte */
24816+ 0xFFFF, /* 16 bits */
24817+ 0x7FFFFFFF, /* INT32_MAX */
24818+ -1, /* all bits set (negative) */
24819+ -128, /* negative */
24820+ (sword32)0x80000000 /* INT32_MIN */
24821+ };
24822+ const int n_patterns = (int)(sizeof(patterns) / sizeof(patterns[0]));
24823+
24824+ /* ---- 6-bit encoding (dilithium_encode_w1_88 path) ---- */
24825+ #ifndef WOLFSSL_NO_ML_DSA_44
24826+ {
24827+ ALIGN32 byte enc_a[DILITHIUM_N * DILITHIUM_Q_HI_88_ENC_BITS / 8];
24828+ ALIGN32 byte enc_b[DILITHIUM_N * DILITHIUM_Q_HI_88_ENC_BITS / 8];
24829+
24830+ /* Uniform fill with each pattern */
24831+ for (k = 0; k < (unsigned int)n_patterns; k++) {
24832+ for (j = 0; j < DILITHIUM_N; j++) {
24833+ w1[j] = patterns[k];
24834+ }
24835+
24836+ XMEMSET(enc_a, 0, sizeof(enc_a));
24837+ XMEMSET(enc_b, 0, sizeof(enc_b));
24838+ wc_dilithium_encode_w1_88(w1, enc_a);
24839+ wc_dilithium_encode_w1_88(w1, enc_b);
24840+
24841+ /* Determinism: same input must produce same output */
24842+ ExpectIntEQ(XMEMCMP(enc_a, enc_b, sizeof(enc_a)), 0);
24843+ }
24844+
24845+ /* Alternating pattern: adjacent elements get different values */
24846+ for (j = 0; j < DILITHIUM_N; j++) {
24847+ w1[j] = (j & 1) ? 43 : 0;
24848+ }
24849+ XMEMSET(enc_a, 0, sizeof(enc_a));
24850+ XMEMSET(enc_b, 0, sizeof(enc_b));
24851+ wc_dilithium_encode_w1_88(w1, enc_a);
24852+ wc_dilithium_encode_w1_88(w1, enc_b);
24853+ ExpectIntEQ(XMEMCMP(enc_a, enc_b, sizeof(enc_a)), 0);
24854+
24855+ /* Ascending pattern: each element differs */
24856+ for (j = 0; j < DILITHIUM_N; j++) {
24857+ w1[j] = (sword32)(j % 44); /* 0..43 cycling */
24858+ }
24859+ XMEMSET(enc_a, 0, sizeof(enc_a));
24860+ XMEMSET(enc_b, 0, sizeof(enc_b));
24861+ wc_dilithium_encode_w1_88(w1, enc_a);
24862+ wc_dilithium_encode_w1_88(w1, enc_b);
24863+ ExpectIntEQ(XMEMCMP(enc_a, enc_b, sizeof(enc_a)), 0);
24864+ }
24865+ #endif /* !WOLFSSL_NO_ML_DSA_44 */
24866+
24867+ /* ---- 4-bit encoding (dilithium_encode_w1_32 path) ---- */
24868+ #if !defined(WOLFSSL_NO_ML_DSA_65) || !defined(WOLFSSL_NO_ML_DSA_87)
24869+ {
24870+ ALIGN32 byte enc_a[DILITHIUM_N * DILITHIUM_Q_HI_32_ENC_BITS / 8];
24871+ ALIGN32 byte enc_b[DILITHIUM_N * DILITHIUM_Q_HI_32_ENC_BITS / 8];
24872+
24873+ /* Uniform fill with each pattern */
24874+ for (k = 0; k < (unsigned int)n_patterns; k++) {
24875+ for (j = 0; j < DILITHIUM_N; j++) {
24876+ w1[j] = patterns[k];
24877+ }
24878+
24879+ XMEMSET(enc_a, 0, sizeof(enc_a));
24880+ XMEMSET(enc_b, 0, sizeof(enc_b));
24881+ wc_dilithium_encode_w1_32(w1, enc_a);
24882+ wc_dilithium_encode_w1_32(w1, enc_b);
24883+
24884+ ExpectIntEQ(XMEMCMP(enc_a, enc_b, sizeof(enc_a)), 0);
24885+ }
24886+
24887+ /* Alternating pattern */
24888+ for (j = 0; j < DILITHIUM_N; j++) {
24889+ w1[j] = (j & 1) ? 15 : 0;
24890+ }
24891+ XMEMSET(enc_a, 0, sizeof(enc_a));
24892+ XMEMSET(enc_b, 0, sizeof(enc_b));
24893+ wc_dilithium_encode_w1_32(w1, enc_a);
24894+ wc_dilithium_encode_w1_32(w1, enc_b);
24895+ ExpectIntEQ(XMEMCMP(enc_a, enc_b, sizeof(enc_a)), 0);
24896+
24897+ /* Ascending pattern */
24898+ for (j = 0; j < DILITHIUM_N; j++) {
24899+ w1[j] = (sword32)(j % 16); /* 0..15 cycling */
24900+ }
24901+ XMEMSET(enc_a, 0, sizeof(enc_a));
24902+ XMEMSET(enc_b, 0, sizeof(enc_b));
24903+ wc_dilithium_encode_w1_32(w1, enc_a);
24904+ wc_dilithium_encode_w1_32(w1, enc_b);
24905+ ExpectIntEQ(XMEMCMP(enc_a, enc_b, sizeof(enc_a)), 0);
24906+ }
24907+ #endif /* !WOLFSSL_NO_ML_DSA_65 || !WOLFSSL_NO_ML_DSA_87 */
24908+
24909+ #endif /* HAVE_DILITHIUM && WOLFSSL_WC_DILITHIUM && sign/verify */
24910+ return EXPECT_RESULT();
24911+ }
24912+
2478424913int test_mldsa_pkcs12(void)
2478524914{
2478624915 EXPECT_DECLS;
0 commit comments