diff --git a/mldsa/src/sign.c b/mldsa/src/sign.c index 02dd6e192..d939a1382 100644 --- a/mldsa/src/sign.c +++ b/mldsa/src/sign.c @@ -616,10 +616,6 @@ __contract__( } /* All is well - write signature */ - /* Constant time: At this point it is clear that the signature is valid - it - * can, hence, be considered public. */ - MLD_CT_TESTING_DECLASSIFY(h, sizeof(*h)); - MLD_CT_TESTING_DECLASSIFY(z, sizeof(*z)); mld_pack_sig(sig, challenge_bytes, z, h, n); ret = 0; /* success */ @@ -874,6 +870,7 @@ int crypto_sign_verify_internal(const uint8_t *sig, size_t siglen, const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], int externalmu) { + uint32_t z_invalid; unsigned int i; int ret; MLD_ALLOC(buf, uint8_t, (MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)); @@ -908,12 +905,24 @@ int crypto_sign_verify_internal(const uint8_t *sig, size_t siglen, /* mld_unpack_sig and mld_polyvecl_chknorm signal failure through a * single non-zero error code that's not yet aligned with MLD_ERR_XXX. * Map it to MLD_ERR_FAIL explicitly. */ + + /* Constant-time: The signature is commonly considered public. However, we + * mark it as secret to make explicit which parts of the code take time + * depending on the signature. + * + * mld_unpack_sig uses conditional branches to unpack the hint vector h. + * The h-component of the signature, hence, needs to be declassified. + */ if (mld_unpack_sig(c, z, h, sig)) { ret = MLD_ERR_FAIL; goto cleanup; } - if (mld_polyvecl_chknorm(z, MLDSA_GAMMA1 - MLDSA_BETA)) + + z_invalid = mld_polyvecl_chknorm(z, MLDSA_GAMMA1 - MLDSA_BETA); + /* Constant-time: We only leak if z is invalid or not. */ + MLD_CT_TESTING_DECLASSIFY(&z_invalid, sizeof(uint32_t)); + if (z_invalid) { ret = MLD_ERR_FAIL; goto cleanup; @@ -937,6 +946,8 @@ int crypto_sign_verify_internal(const uint8_t *sig, size_t siglen, } /* Matrix-vector multiplication; compute Az - c2^dt1 */ + /* Constant-time: poly_challenge uses conditional branches depending on c. */ + MLD_CT_TESTING_DECLASSIFY(c, MLDSA_CTILDEBYTES); mld_poly_challenge(cp, c); mld_polyvec_matrix_expand(mat, rho); @@ -955,6 +966,9 @@ int crypto_sign_verify_internal(const uint8_t *sig, size_t siglen, /* Reconstruct w1 */ mld_polyveck_caddq(w1); + + /* Constant-time: use_hint uses conditional branches depending on w1. */ + MLD_CT_TESTING_DECLASSIFY(w1, sizeof(mld_polyveck)); mld_polyveck_use_hint(tmp, w1, h); mld_polyveck_pack_w1(buf, tmp); /* Call random oracle and verify challenge */ diff --git a/test/test_mldsa.c b/test/test_mldsa.c index 5916e45dd..5eacce08e 100644 --- a/test/test_mldsa.c +++ b/test/test_mldsa.c @@ -29,6 +29,11 @@ } while (0) +#define MLD_CT_TESTING_DECLASSIFY_H(s) \ + MLD_CT_TESTING_DECLASSIFY( \ + (s) + MLDSA_CTILDEBYTES + MLDSA_L * MLDSA_POLYZ_PACKEDBYTES, \ + MLDSA_POLYVECH_PACKEDBYTES); + static int test_sign_core(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], uint8_t sm[MLEN + MLDSA_CRYPTO_BYTES], @@ -49,10 +54,17 @@ static int test_sign_core(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], CHECK(crypto_sign(sm, &smlen, m, MLEN, ctx, CTXLEN, sk) == 0); + /* Mark signature as secret to force explcit declassification in verification + */ + MLD_CT_TESTING_SECRET(sm, MLEN + MLDSA_CRYPTO_BYTES); + /* Constant-time: The unpacking of the h-component of the signature requires + * conditional branches.*/ + MLD_CT_TESTING_DECLASSIFY_H(sm); + rc = crypto_sign_open(m2, &mlen, sm, smlen, ctx, CTXLEN, pk); /* Constant time: Declassify outputs to check them. */ - MLD_CT_TESTING_DECLASSIFY(rc, sizeof(int)); + MLD_CT_TESTING_DECLASSIFY(&rc, sizeof(int)); MLD_CT_TESTING_DECLASSIFY(m, MLEN); MLD_CT_TESTING_DECLASSIFY(m2, (MLEN + MLDSA_CRYPTO_BYTES)); @@ -120,6 +132,12 @@ static int test_sign_extmu(void) MLD_CT_TESTING_SECRET(mu, sizeof(mu)); CHECK(crypto_sign_signature_extmu(sig, &siglen, mu, sk) == 0); + /* Mark signature as secret to force explcit declassification in verification + */ + MLD_CT_TESTING_SECRET(sig, sizeof(sig)); + /* Constant-time: The unpacking of the h-component of the signature requires + * conditional branches.*/ + MLD_CT_TESTING_DECLASSIFY_H(sig); CHECK(crypto_sign_verify_extmu(sig, siglen, mu, pk) == 0); return 0; @@ -147,6 +165,12 @@ static int test_sign_pre_hash(void) CHECK(crypto_sign_signature_pre_hash_shake256(sig, &siglen, m, MLEN, ctx, CTXLEN, rnd, sk) == 0); + /* Mark signature as secret to force explcit declassification in verification + */ + MLD_CT_TESTING_SECRET(sig, sizeof(sig)); + /* Constant-time: The unpacking of the h-component of the signature requires + * conditional branches.*/ + MLD_CT_TESTING_DECLASSIFY_H(sig); CHECK(crypto_sign_verify_pre_hash_shake256(sig, siglen, m, MLEN, ctx, CTXLEN, pk) == 0); @@ -234,6 +258,13 @@ static int test_wrong_pk(void) CHECK(crypto_sign(sm, &smlen, m, MLEN, ctx, CTXLEN, sk) == 0); + /* Mark signature as secret to force explcit declassification in verification + */ + MLD_CT_TESTING_SECRET(sm, sizeof(sm)); + /* Constant-time: The unpacking of the h-component of the signature requires + * conditional branches.*/ + MLD_CT_TESTING_DECLASSIFY_H(sm); + /* flip bit in public key */ randombytes((uint8_t *)&idx, sizeof(size_t)); idx %= MLDSA_CRYPTO_PUBLICKEYBYTES; @@ -285,6 +316,13 @@ static int test_wrong_sig(void) CHECK(crypto_sign(sm, &smlen, m, MLEN, ctx, CTXLEN, sk) == 0); + /* Mark signature as secret to force explcit declassification in verification + */ + MLD_CT_TESTING_SECRET(sm, sizeof(sm)); + /* Constant-time: The unpacking of the h-component of the signature requires + * conditional branches.*/ + MLD_CT_TESTING_DECLASSIFY_H(sm); + /* flip bit in signed message */ randombytes((uint8_t *)&idx, sizeof(size_t)); idx %= MLEN + MLDSA_CRYPTO_BYTES; @@ -294,7 +332,7 @@ static int test_wrong_sig(void) rc = crypto_sign_open(m2, &mlen, sm, smlen, ctx, CTXLEN, pk); /* Constant time: Declassify outputs to check them. */ - MLD_CT_TESTING_DECLASSIFY(rc, sizeof(int)); + MLD_CT_TESTING_DECLASSIFY(&rc, sizeof(int)); MLD_CT_TESTING_DECLASSIFY(m2, sizeof(m2)); if (!rc) @@ -337,6 +375,13 @@ static int test_wrong_ctx(void) CHECK(crypto_sign(sm, &smlen, m, MLEN, ctx, CTXLEN, sk) == 0); + /* Mark signature as secret to force explcit declassification in verification + */ + MLD_CT_TESTING_SECRET(sm, sizeof(sm)); + /* Constant-time: The unpacking of the h-component of the signature requires + * conditional branches.*/ + MLD_CT_TESTING_DECLASSIFY_H(sm); + /* flip bit in ctx */ randombytes((uint8_t *)&idx, sizeof(size_t)); idx %= CTXLEN; @@ -346,7 +391,7 @@ static int test_wrong_ctx(void) rc = crypto_sign_open(m2, &mlen, sm, smlen, ctx, CTXLEN, pk); /* Constant time: Declassify outputs to check them. */ - MLD_CT_TESTING_DECLASSIFY(rc, sizeof(int)); + MLD_CT_TESTING_DECLASSIFY(&rc, sizeof(int)); MLD_CT_TESTING_DECLASSIFY(m2, sizeof(m2)); if (!rc)