@@ -457,34 +457,29 @@ __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 )))
469470 requires (forall (k1 , 0 , MLDSA_L , array_abs_bound (s1 - > vec [k1 ].coeffs , 0 , MLDSA_N , MLD_NTT_BOUND )))
470471 assigns (memory_slice (sig , MLDSA_CRYPTO_BYTES ))
472+ assigns (memory_slice (z , sizeof (mld_poly )))
471473 ensures (return_value == 0 || return_value == MLD_ERR_FAIL ||
472474 return_value == MLD_ERR_OUT_OF_MEMORY )
473475)
474476{
475477 unsigned int i ;
476478 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- }
484479 for (i = 0 ; i < MLDSA_L ; i ++ )
485480 __loop__ (
486481 assigns (i , memory_slice (z , sizeof (mld_poly )), memory_slice (sig , MLDSA_CRYPTO_BYTES ))
487- invariant (i <= MLDSA_L )
482+ invariant (i <= MLDSA_L )
488483 )
489484 {
490485 mld_poly_pointwise_montgomery (z , cp , & s1 -> vec [i ]);
@@ -494,38 +489,37 @@ __contract__(
494489
495490 z_invalid = mld_poly_chknorm (z , MLDSA_GAMMA1 - MLDSA_BETA );
496491 /* 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.
492+ * to leak the result of the norm check and which polynomial in z caused a
493+ * rejection. It would even be okay to leak which coefficient led to
494+ * rejection as the candidate signature will be discarded anyway.
500495 * See Section 5.5 of @[Round3_Spec]. */
501496 MLD_CT_TESTING_DECLASSIFY (& z_invalid , sizeof (uint32_t ));
502497 if (z_invalid )
503498 {
504- ret = MLD_ERR_FAIL ; /* reject */
505- goto cleanup ;
499+ return MLD_ERR_FAIL ; /* reject */
506500 }
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() */
501+ /* If z is valid, then its coefficients are bounded by
502+ * MLDSA_GAMMA1 - MLDSA_BETA. This will be needed below
503+ * to prove the pre-condition of pack_sig_z() */
510504 mld_assert_abs_bound (z , MLDSA_N , (MLDSA_GAMMA1 - MLDSA_BETA ));
505+
506+ /* After the norm check, the distribution of each coefficient of z is
507+ * independent of the secret key and it can, hence, be considered
508+ * public. It is, hence, okay to immediately pack it into the user-provided
509+ * signature buffer. */
511510 mld_pack_sig_z (sig , z , i );
512511 }
513- ret = 0 ;
514-
515- cleanup :
516- MLD_FREE (z , mld_poly , 1 );
517- return ret ;
512+ return 0 ;
518513}
519514
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]. */
515+ /* Reference: The reference implementation does not explicitly check the
516+ * maximum nonce value, but instead loops indefinitely (even when the nonce
517+ * would overflow). Internally, sampling of y uses
518+ * (nonceL), (nonceL+1), ... (nonce*L+L-1).
519+ * Hence, there are no overflows if nonce < (UINT16_MAX - L)/L.
520+ * Explicitly checking for this explicitly allows us to prove type-safety.
521+ * Note that FIPS204 explicitly allows an upper-bound this loop of
522+ * 814 (< (UINT16_MAX - L)/L) - see @[FIPS204, Appendix C]. */
529523#define MLD_NONCE_UB ((UINT16_MAX - MLDSA_L) / MLDSA_L)
530524
531525/*************************************************
@@ -608,9 +602,10 @@ __contract__(
608602 MLD_ALLOC (w1tmp , w1tmp_u , 1 );
609603 MLD_ALLOC (w0 , mld_polyveck , 1 );
610604 MLD_ALLOC (cp , mld_poly , 1 );
605+ MLD_ALLOC (t , mld_poly , 1 );
611606
612607 if (challenge_bytes == NULL || yh == NULL || z == NULL || w1tmp == NULL ||
613- w0 == NULL || cp == NULL )
608+ w0 == NULL || cp == NULL || t == NULL )
614609 {
615610 ret = MLD_ERR_OUT_OF_MEMORY ;
616611 goto cleanup ;
@@ -646,13 +641,12 @@ __contract__(
646641 mld_poly_ntt (cp );
647642
648643 /* Compute z, reject if it reveals secret */
649- ret = mld_compute_pack_z (sig , cp , s1 , y );
644+ ret = mld_compute_pack_z (sig , cp , s1 , y , t );
650645 if (ret )
651646 {
652647 goto cleanup ;
653648 }
654649
655-
656650 /* Check that subtracting cs2 does not change high bits of w and low bits
657651 * do not reveal secret information */
658652 mld_polyveck_pointwise_poly_montgomery (h , cp , s2 );
@@ -703,14 +697,15 @@ __contract__(
703697 }
704698
705699 /* All is well - write signature */
706- mld_pack_sig (sig , challenge_bytes , h , n );
700+ mld_pack_sig_c_h (sig , challenge_bytes , h , n );
707701 /* Constant time: At this point it is clear that the signature is valid - it
708702 * can, hence, be considered public. */
709703 MLD_CT_TESTING_DECLASSIFY (sig , MLDSA_CRYPTO_BYTES );
710704 ret = 0 ; /* success */
711705
712706cleanup :
713707 /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */
708+ MLD_FREE (t , mld_poly , 1 );
714709 MLD_FREE (cp , mld_poly , 1 );
715710 MLD_FREE (w0 , mld_polyveck , 1 );
716711 MLD_FREE (w1tmp , w1tmp_u , 1 );
0 commit comments