Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 48 additions & 29 deletions wolfcrypt/src/dilithium.c
Original file line number Diff line number Diff line change
Expand Up @@ -11456,39 +11456,58 @@ int wc_dilithium_check_key(dilithium_key* key)
/* Get s1, s2 and t0 from private key. */
dilithium_vec_decode_eta_bits(s1p, params->eta, s1, params->l);
dilithium_vec_decode_eta_bits(s2p, params->eta, s2, params->k);
dilithium_vec_decode_t0(t0p, params->k, t0);

/* Get t1 from public key. */
dilithium_vec_decode_t1(t1p, params->k, t1);
/* Validate s1 and s2 coefficients are within [-eta, eta]. */
{
sword32 eta = (sword32)params->eta;
word32 c;
for (c = 0; c < (word32)(params->l * DILITHIUM_N); c++) {
if (s1[c] < -eta || s1[c] > eta) {
ret = PUBLIC_KEY_E;
break;
}
}
for (c = 0; (ret == 0) && (c < (word32)(params->k * DILITHIUM_N)); c++) {
if (s2[c] < -eta || s2[c] > eta) {
ret = PUBLIC_KEY_E;
break;
}
}
Comment on lines +11463 to +11474
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This introduces data-dependent early exits (break) while processing secret-key material (s1/s2). If wc_dilithium_check_key() is used in contexts where timing differences are observable, consider making this check branchless by accumulating a violation flag across all coefficients and setting ret = PUBLIC_KEY_E after the loops complete (same behavior, less timing leakage).

Suggested change
for (c = 0; c < (word32)(params->l * DILITHIUM_N); c++) {
if (s1[c] < -eta || s1[c] > eta) {
ret = PUBLIC_KEY_E;
break;
}
}
for (c = 0; (ret == 0) && (c < (word32)(params->k * DILITHIUM_N)); c++) {
if (s2[c] < -eta || s2[c] > eta) {
ret = PUBLIC_KEY_E;
break;
}
}
word32 bad = 0;
for (c = 0; c < (word32)(params->l * DILITHIUM_N); c++) {
if (s1[c] < -eta || s1[c] > eta) {
bad = 1;
}
}
for (c = 0; c < (word32)(params->k * DILITHIUM_N); c++) {
if (s2[c] < -eta || s2[c] > eta) {
bad = 1;
}
}
if (bad != 0) {
ret = PUBLIC_KEY_E;
}

Copilot uses AI. Check for mistakes.
}
Comment on lines +11459 to +11475
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new coefficient validation is duplicated for s1 and s2 with slightly different loop bounds. Consider extracting this into a small internal helper (e.g., dilithium_vec_check_eta_bounds(const sword32* v, word32 coeffCount, sword32 eta)) to reduce duplication and make future changes (like constant-time accumulation or different bounds) less error-prone.

Copilot uses AI. Check for mistakes.
if (ret == 0) {
dilithium_vec_decode_t0(t0p, params->k, t0);

/* Calcaluate t = NTT-1(A o NTT(s1)) + s2 */
dilithium_vec_ntt_small_full(s1, params->l);
dilithium_matrix_mul(t, a, s1, params->k, params->l);
#ifdef WOLFSSL_DILITHIUM_SMALL
dilithium_vec_red(t, params->k);
#endif
dilithium_vec_invntt_full(t, params->k);
dilithium_vec_add(t, s2, params->k);
/* Subtract t0 from t. */
dilithium_vec_sub(t, t0, params->k);
/* Make t positive to match t1. */
dilithium_vec_make_pos(t, params->k);
/* Get t1 from public key. */
dilithium_vec_decode_t1(t1p, params->k, t1);

/* Check t - t0 and t1 are the same. */
for (i = 0; i < params->k; i++) {
for (j = 0; j < DILITHIUM_N; j++) {
x |= tt[j] ^ t1[j];
/* Calcaluate t = NTT-1(A o NTT(s1)) + s2 */
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in comment: 'Calcaluate' should be 'Calculate'.

Suggested change
/* Calcaluate t = NTT-1(A o NTT(s1)) + s2 */
/* Calculate t = NTT-1(A o NTT(s1)) + s2 */

Copilot uses AI. Check for mistakes.
dilithium_vec_ntt_small_full(s1, params->l);
dilithium_matrix_mul(t, a, s1, params->k, params->l);
#ifdef WOLFSSL_DILITHIUM_SMALL
dilithium_vec_red(t, params->k);
#endif
dilithium_vec_invntt_full(t, params->k);
dilithium_vec_add(t, s2, params->k);
/* Subtract t0 from t. */
dilithium_vec_sub(t, t0, params->k);
/* Make t positive to match t1. */
dilithium_vec_make_pos(t, params->k);

/* Check t - t0 and t1 are the same. */
for (i = 0; i < params->k; i++) {
for (j = 0; j < DILITHIUM_N; j++) {
x |= tt[j] ^ t1[j];
}
tt += DILITHIUM_N;
t1 += DILITHIUM_N;
}
/* Check the public seed is the same in private and public key. */
for (i = 0; i < DILITHIUM_PUB_SEED_SZ; i++) {
x |= key->p[i] ^ key->k[i];
}
tt += DILITHIUM_N;
t1 += DILITHIUM_N;
}
/* Check the public seed is the same in private and public key. */
for (i = 0; i < DILITHIUM_PUB_SEED_SZ; i++) {
x |= key->p[i] ^ key->k[i];
}

if ((ret == 0) && (x != 0)) {
ret = PUBLIC_KEY_E;
if (x != 0) {
ret = PUBLIC_KEY_E;
}
}
}

Expand Down
Loading