Skip to content

Commit 92bd5f1

Browse files
committed
verify: Switch to constant-time memcmp
In the very end of verify one has to compare the input challenge to the re-computed challenge. If they are equal (and some previous checks on h and z passed), the signature is valid. Currently, our constant-time tests do not declassify the message and we, hence, need to declassify in this final step. Before thi commit, the declassification would happen on the recomputed challenge just before the memcmp. Now that a constant-time memcmp was added in #714, we might as well use that; that plus a constant-time selections allows us to not use any declassifications in verification, i.e., we do not leak the verification result through timing. Signed-off-by: Matthias J. Kannwischer <matthias@kannwischer.eu>
1 parent 1915e47 commit 92bd5f1

File tree

2 files changed

+14
-22
lines changed

2 files changed

+14
-22
lines changed

mldsa/src/sign.c

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -782,7 +782,6 @@ int crypto_sign_verify_internal(const uint8_t *sig, size_t siglen,
782782
const uint8_t pk[CRYPTO_PUBLICKEYBYTES],
783783
int externalmu)
784784
{
785-
unsigned int i;
786785
int res;
787786
MLD_ALIGN uint8_t buf[MLDSA_K * MLDSA_POLYW1_PACKEDBYTES];
788787
MLD_ALIGN uint8_t rho[MLDSA_SEEDBYTES];
@@ -853,28 +852,18 @@ int crypto_sign_verify_internal(const uint8_t *sig, size_t siglen,
853852
mld_H(c2, MLDSA_CTILDEBYTES, mu, MLDSA_CRHBYTES, buf,
854853
MLDSA_K * MLDSA_POLYW1_PACKEDBYTES, NULL, 0);
855854

856-
/* Constant time: All data in verification is usually considered public.
857-
* However, in our constant-time tests we do not declassify the message and
858-
* context string.
859-
* The following conditional is the only place in verification whose run-time
860-
* depends on the message. As all that can be leakaged here is the output of
861-
* a hash call (that should behave like a random oracle), it is safe to
862-
* declassify here even with a secret message.
863-
*/
864-
MLD_CT_TESTING_DECLASSIFY(c2, sizeof(c2));
865-
for (i = 0; i < MLDSA_CTILDEBYTES; ++i)
866-
__loop__(
867-
invariant(i <= MLDSA_CTILDEBYTES)
868-
)
869-
{
870-
if (c[i] != c2[i])
871-
{
872-
res = -1;
873-
goto cleanup;
874-
}
875-
}
876855

877-
res = 0;
856+
857+
/* Constant time: Leaking the result of the signature verification is fine in
858+
* the vast majority of the cases. However, performing all
859+
* of verification in constant-time only has negligible
860+
* performance overhead. This way we do not have to declassify
861+
* the message.
862+
*/
863+
/* Return 0 if c == c2, -1 otherwise */
864+
res = mld_ct_sel_int32(
865+
-1, 0,
866+
mld_ct_cmask_neg_i32(-(int32_t)mld_ct_memcmp(c, c2, MLDSA_CTILDEBYTES)));
878867

879868
cleanup:
880869
/* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */

proofs/cbmc/crypto_sign_verify_internal/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ USE_FUNCTION_CONTRACTS+=$(MLD_NAMESPACE)polyveck_caddq
3939
USE_FUNCTION_CONTRACTS+=$(MLD_NAMESPACE)polyveck_use_hint
4040
USE_FUNCTION_CONTRACTS+=$(MLD_NAMESPACE)polyveck_pack_w1
4141
USE_FUNCTION_CONTRACTS+=mld_zeroize
42+
USE_FUNCTION_CONTRACTS+=mld_ct_memcmp
43+
USE_FUNCTION_CONTRACTS+=mld_ct_cmask_neg_i32
44+
USE_FUNCTION_CONTRACTS+=mld_ct_sel_int32
4245

4346
APPLY_LOOP_CONTRACTS=on
4447
USE_DYNAMIC_FRAMES=1

0 commit comments

Comments
 (0)