@@ -457,12 +457,13 @@ __contract__(
457457MLD_MUST_CHECK_RETURN_VALUE
458458static int mld_compute_pack_z (uint8_t sig [MLDSA_CRYPTO_BYTES ],
459459 const mld_poly * cp , const mld_polyvecl * s1 ,
460- const mld_polyvecl * y )
460+ const mld_polyvecl * y , mld_poly * z )
461461__contract__ (
462462 requires (memory_no_alias (sig , MLDSA_CRYPTO_BYTES ))
463463 requires (memory_no_alias (cp , sizeof (mld_poly )))
464464 requires (memory_no_alias (s1 , sizeof (mld_polyvecl )))
465465 requires (memory_no_alias (y , sizeof (mld_polyvecl )))
466+ requires (memory_no_alias (z , sizeof (mld_poly )))
466467 requires (array_abs_bound (cp - > coeffs , 0 , MLDSA_N , MLD_NTT_BOUND ))
467468 requires (forall (k0 , 0 , MLDSA_L ,
468469 array_bound (y - > vec [k0 ].coeffs , 0 , MLDSA_N , - (MLDSA_GAMMA1 - 1 ), MLDSA_GAMMA1 + 1 )))
@@ -474,17 +475,10 @@ __contract__(
474475{
475476 unsigned int i ;
476477 uint32_t z_invalid ;
477- int ret ;
478- MLD_ALLOC (z , mld_poly , 1 );
479- if (z == NULL )
480- {
481- ret = MLD_ERR_OUT_OF_MEMORY ;
482- goto cleanup ;
483- }
484478 for (i = 0 ; i < MLDSA_L ; i ++ )
485479 __loop__ (
486480 assigns (i , memory_slice (z , sizeof (mld_poly )), memory_slice (sig , MLDSA_CRYPTO_BYTES ))
487- invariant (i <= MLDSA_L )
481+ invariant (i <= MLDSA_L )
488482 )
489483 {
490484 mld_poly_pointwise_montgomery (z , cp , & s1 -> vec [i ]);
@@ -494,38 +488,37 @@ __contract__(
494488
495489 z_invalid = mld_poly_chknorm (z , MLDSA_GAMMA1 - MLDSA_BETA );
496490 /* Constant time: It is fine (and prohibitively expensive to avoid)
497- * leaking the result of the norm check. In case of rejection it
498- * would even be okay to leak which coefficient led to rejection
499- * as the candidate signature will be discarded anyway.
491+ * to leak the result of the norm check and which polynomial in z caused a
492+ * rejection. It would even be okay to leak which coefficient led to
493+ * rejection as the candidate signature will be discarded anyway.
500494 * See Section 5.5 of @[Round3_Spec]. */
501495 MLD_CT_TESTING_DECLASSIFY (& z_invalid , sizeof (uint32_t ));
502496 if (z_invalid )
503497 {
504- ret = MLD_ERR_FAIL ; /* reject */
505- goto cleanup ;
498+ return MLD_ERR_FAIL ; /* reject */
506499 }
507- /* If z is valid, then its coefficients are bounded by */
508- / * MLDSA_GAMMA1 - MLDSA_BETA. This will be needed below */
509- / * to prove the pre-condition of pack_sig_z() */
500+ /* If z is valid, then its coefficients are bounded by
501+ * MLDSA_GAMMA1 - MLDSA_BETA. This will be needed below
502+ * to prove the pre-condition of pack_sig_z() */
510503 mld_assert_abs_bound (z , MLDSA_N , (MLDSA_GAMMA1 - MLDSA_BETA ));
504+
505+ /* After the norm check, the distribution of each coefficient of z is
506+ * independent of the secret key and it can, hence, be considered
507+ * public. It is, hence, okay to immediately pack it into the user-provided
508+ * signature buffer. */
511509 mld_pack_sig_z (sig , z , i );
512510 }
513- ret = 0 ;
514-
515- cleanup :
516- MLD_FREE (z , mld_poly , 1 );
517- return ret ;
511+ return 0 ;
518512}
519513
520- /* Reference: The reference implementation does not explicitly */
521- /* check the maximum nonce value, but instead loops indefinitely */
522- /* (even when the nonce would overflow). Internally, */
523- /* sampling of y uses (nonceL), (nonceL+1), ... (nonce*L+L-1). */
524- /* Hence, there are no overflows if nonce < (UINT16_MAX - L)/L. */
525- /* Explicitly checking for this explicitly allows us to prove */
526- /* type-safety. Note that FIPS204 explicitly allows an upper- */
527- /* bound this loop of 814 (< (UINT16_MAX - L)/L) - see */
528- /* @[FIPS204, Appendix C]. */
514+ /* Reference: The reference implementation does not explicitly check the
515+ * maximum nonce value, but instead loops indefinitely (even when the nonce
516+ * would overflow). Internally, sampling of y uses
517+ * (nonceL), (nonceL+1), ... (nonce*L+L-1).
518+ * Hence, there are no overflows if nonce < (UINT16_MAX - L)/L.
519+ * Explicitly checking for this explicitly allows us to prove type-safety.
520+ * Note that FIPS204 explicitly allows an upper-bound this loop of
521+ * 814 (< (UINT16_MAX - L)/L) - see @[FIPS204, Appendix C]. */
529522#define MLD_NONCE_UB ((UINT16_MAX - MLDSA_L) / MLDSA_L)
530523
531524/*************************************************
@@ -608,9 +601,10 @@ __contract__(
608601 MLD_ALLOC (w1tmp , w1tmp_u , 1 );
609602 MLD_ALLOC (w0 , mld_polyveck , 1 );
610603 MLD_ALLOC (cp , mld_poly , 1 );
604+ MLD_ALLOC (t , mld_poly , 1 );
611605
612606 if (challenge_bytes == NULL || yh == NULL || z == NULL || w1tmp == NULL ||
613- w0 == NULL || cp == NULL )
607+ w0 == NULL || cp == NULL || t == NULL )
614608 {
615609 ret = MLD_ERR_OUT_OF_MEMORY ;
616610 goto cleanup ;
@@ -646,13 +640,12 @@ __contract__(
646640 mld_poly_ntt (cp );
647641
648642 /* Compute z, reject if it reveals secret */
649- ret = mld_compute_pack_z (sig , cp , s1 , y );
643+ ret = mld_compute_pack_z (sig , cp , s1 , y , t );
650644 if (ret )
651645 {
652646 goto cleanup ;
653647 }
654648
655-
656649 /* Check that subtracting cs2 does not change high bits of w and low bits
657650 * do not reveal secret information */
658651 mld_polyveck_pointwise_poly_montgomery (h , cp , s2 );
@@ -703,14 +696,15 @@ __contract__(
703696 }
704697
705698 /* All is well - write signature */
706- mld_pack_sig (sig , challenge_bytes , h , n );
699+ mld_pack_sig_c_h (sig , challenge_bytes , h , n );
707700 /* Constant time: At this point it is clear that the signature is valid - it
708701 * can, hence, be considered public. */
709702 MLD_CT_TESTING_DECLASSIFY (sig , MLDSA_CRYPTO_BYTES );
710703 ret = 0 ; /* success */
711704
712705cleanup :
713706 /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */
707+ MLD_FREE (t , mld_poly , 1 );
714708 MLD_FREE (cp , mld_poly , 1 );
715709 MLD_FREE (w0 , mld_polyveck , 1 );
716710 MLD_FREE (w1tmp , w1tmp_u , 1 );
0 commit comments