Skip to content
Open
Show file tree
Hide file tree
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
23 changes: 13 additions & 10 deletions crypto/fipsmodule/ml_dsa/ml_dsa_ref/poly.c
Original file line number Diff line number Diff line change
Expand Up @@ -228,29 +228,32 @@ void ml_dsa_poly_use_hint(ml_dsa_params *params,
* Arguments: - const poly *a: pointer to polynomial
* - int32_t B: norm bound
*
* Returns 0 if norm is strictly smaller than B <= (Q-1)/8 and 1 otherwise.
* Returns 0 if norm is strictly smaller than B <= (Q-1)/8 and 0xFFFFFFFF otherwise.
**************************************************/
int ml_dsa_poly_chknorm(const ml_dsa_poly *a, int32_t B) {
uint32_t ml_dsa_poly_chknorm(const ml_dsa_poly *a, int32_t B) {
unsigned int i;
int32_t t;
uint32_t r = 0;

if(B > (ML_DSA_Q-1)/8) {
return 1;
return 0xFFFFFFFF;
}

/* It is ok to leak which coefficient violates the bound since
the probability for each coefficient is independent of secret
data but we must not leak the sign of the centralized representative. */
/* Constant-time implementation as defense-in-depth. According to Section 5.5
of the Dilithium specification, it is safe to leak which coefficient violates
the bound, but we implement this in constant-time as additional hardening.
We accumulate violations using bitwise OR instead of early exit. See 5.5 in
https://pq-crystals.org/dilithium/data/dilithium-specification-round3-20210208.pdf
*/
for(i = 0; i < ML_DSA_N; ++i) {
/* Absolute value */
t = constant_time_select_int(constant_time_msb_w(a->coeffs[i]),
-a->coeffs[i], a->coeffs[i]);

if(t >= B) {
return 1;
}
/* Check if t >= B and accumulate result */
r |= constant_time_ge_w((uint32_t)t, (uint32_t)B);
}
return 0;
return r;
}

/*************************************************
Expand Down
2 changes: 1 addition & 1 deletion crypto/fipsmodule/ml_dsa/ml_dsa_ref/poly.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ void ml_dsa_poly_use_hint(ml_dsa_params *params,
const ml_dsa_poly *a,
const ml_dsa_poly *h);

int ml_dsa_poly_chknorm(const ml_dsa_poly *a, int32_t B);
uint32_t ml_dsa_poly_chknorm(const ml_dsa_poly *a, int32_t B);

void ml_dsa_poly_uniform(ml_dsa_poly *a,
const uint8_t seed[ML_DSA_SEEDBYTES],
Expand Down
28 changes: 16 additions & 12 deletions crypto/fipsmodule/ml_dsa/ml_dsa_ref/polyvec.c
Original file line number Diff line number Diff line change
Expand Up @@ -223,16 +223,16 @@ void ml_dsa_polyvecl_pointwise_acc_montgomery(ml_dsa_params *params,
* - int32_t B: norm bound
*
* Returns 0 if norm of all polynomials is strictly smaller than B <= (Q-1)/8
* and 1 otherwise.
* and 0xFFFFFFFF otherwise.
**************************************************/
int ml_dsa_polyvecl_chknorm(ml_dsa_params *params, const polyvecl *v, int32_t bound) {
uint32_t ml_dsa_polyvecl_chknorm(ml_dsa_params *params, const polyvecl *v, int32_t bound) {
unsigned int i;
uint32_t r = 0;

for(i = 0; i < params->l; ++i) {
if(ml_dsa_poly_chknorm(&v->vec[i], bound)) {
return 1;
}
r |= ml_dsa_poly_chknorm(&v->vec[i], bound);
}
return 0;
return r;
}

/**************************************************************/
Expand Down Expand Up @@ -418,16 +418,20 @@ void ml_dsa_polyveck_pointwise_poly_montgomery(ml_dsa_params *params,
* - int32_t B: norm bound
*
* Returns 0 if norm of all polynomials are strictly smaller than B <= (Q-1)/8
* and 1 otherwise.
* and 0xFFFFFFFF otherwise.
**************************************************/
int ml_dsa_polyveck_chknorm(ml_dsa_params *params, const polyveck *v, int32_t bound) {
uint32_t ml_dsa_polyveck_chknorm(ml_dsa_params *params, const polyveck *v, int32_t bound) {
unsigned int i;
uint32_t r = 0;

/* Reference: Leaks which polynomial violates the bound via a conditional.
* We are more conservative to reduce the number of declassifications in
* constant-time testing.
*/
for(i = 0; i < params->k; ++i) {
if(ml_dsa_poly_chknorm(&v->vec[i], bound)) {
return 1;
}
r |= ml_dsa_poly_chknorm(&v->vec[i], bound);
}
return 0;
return r;
}

/*************************************************
Expand Down
4 changes: 2 additions & 2 deletions crypto/fipsmodule/ml_dsa/ml_dsa_ref/polyvec.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ void ml_dsa_polyvecl_pointwise_acc_montgomery(ml_dsa_params *params,
const polyvecl *u,
const polyvecl *v);

int ml_dsa_polyvecl_chknorm(ml_dsa_params *params, const polyvecl *v, int32_t B);
uint32_t ml_dsa_polyvecl_chknorm(ml_dsa_params *params, const polyvecl *v, int32_t B);

typedef struct {
ml_dsa_poly vec[ML_DSA_K_MAX];
Expand Down Expand Up @@ -77,7 +77,7 @@ void ml_dsa_polyveck_pointwise_poly_montgomery(ml_dsa_params *params,
const ml_dsa_poly *a,
const polyveck *v);

int ml_dsa_polyveck_chknorm(ml_dsa_params *params, const polyveck *v, int32_t B);
uint32_t ml_dsa_polyveck_chknorm(ml_dsa_params *params, const polyveck *v, int32_t B);

void ml_dsa_polyveck_power2round(ml_dsa_params *params,
polyveck *v1,
Expand Down
15 changes: 12 additions & 3 deletions crypto/fipsmodule/ml_dsa/ml_dsa_ref/sign.c
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ int ml_dsa_sign_internal(ml_dsa_params *params,
uint8_t seedbuf[2*ML_DSA_SEEDBYTES + ML_DSA_TRBYTES + 2*ML_DSA_CRHBYTES];
uint8_t *rho, *tr, *key, *mu, *rhoprime;
uint16_t nonce = 0;
uint32_t z_invalid, w0_invalid, h_invalid;
polyvecl mat[ML_DSA_K_MAX], s1, y, z;
polyveck t0, s2, w1, w0, h;
ml_dsa_poly cp;
Expand Down Expand Up @@ -248,7 +249,8 @@ int ml_dsa_sign_internal(ml_dsa_params *params,
ml_dsa_polyvecl_invntt_tomont(params, &z);
ml_dsa_polyvecl_add(params, &z, &z, &y);
ml_dsa_polyvecl_reduce(params, &z);
if(ml_dsa_polyvecl_chknorm(params, &z, params->gamma1 - params->beta)) {
z_invalid = ml_dsa_polyvecl_chknorm(params, &z, params->gamma1 - params->beta);
if(z_invalid) {
goto rej;
}

Expand All @@ -258,15 +260,22 @@ int ml_dsa_sign_internal(ml_dsa_params *params,
ml_dsa_polyveck_invntt_tomont(params, &h);
ml_dsa_polyveck_sub(params, &w0, &w0, &h);
ml_dsa_polyveck_reduce(params, &w0);
if(ml_dsa_polyveck_chknorm(params, &w0, params->gamma2 - params->beta)) {
w0_invalid = ml_dsa_polyveck_chknorm(params, &w0, params->gamma2 - params->beta);
/* Leaking the fact that a signature was rejected at this stage is acceptable as
* the next attempt at a signature will be (indistinguishable from) independent of
* this one. See 5.5 in
* https://pq-crystals.org/dilithium/data/dilithium-specification-round3-20210208.pdf
*/
if(w0_invalid) {
goto rej;
}

/* FIPS 204: line 25 */
ml_dsa_polyveck_pointwise_poly_montgomery(params, &h, &cp, &t0);
ml_dsa_polyveck_invntt_tomont(params, &h);
ml_dsa_polyveck_reduce(params, &h);
if(ml_dsa_polyveck_chknorm(params, &h, params->gamma2)) {
h_invalid = ml_dsa_polyveck_chknorm(params, &h, params->gamma2);
if(h_invalid) {
goto rej;
}

Expand Down
Loading