@@ -658,6 +658,48 @@ void mld_polyt0_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT0_PACKEDBYTES])
658658 (1 << (MLDSA_D - 1 )) + 1 );
659659}
660660
661+ MLD_STATIC_TESTABLE uint32_t mld_poly_chknorm_c (const mld_poly * a , int32_t B )
662+ __contract__ (
663+ requires (memory_no_alias (a , sizeof (mld_poly )))
664+ requires (0 <= B && B <= MLDSA_Q - REDUCE32_RANGE_MAX )
665+ requires (array_bound (a - > coeffs , 0 , MLDSA_N , - REDUCE32_RANGE_MAX , REDUCE32_RANGE_MAX ))
666+ ensures (return_value == 0 || return_value == 0xFFFFFFFF )
667+ ensures ((return_value == 0 ) == array_abs_bound (a - > coeffs , 0 , MLDSA_N , B ))
668+ )
669+ {
670+ unsigned int i ;
671+ uint32_t t = 0 ;
672+ mld_assert_bound (a -> coeffs , MLDSA_N , - REDUCE32_RANGE_MAX , REDUCE32_RANGE_MAX );
673+ for (i = 0 ; i < MLDSA_N ; ++ i )
674+ __loop__ (
675+ invariant (i <= MLDSA_N )
676+ invariant (t == 0 || t == 0xFFFFFFFF )
677+ invariant ((t == 0 ) == array_abs_bound (a -> coeffs , 0 , i , B ))
678+ )
679+ {
680+ /*
681+ * Since we know that -REDUCE32_RANGE_MAX <= a < REDUCE32_RANGE_MAX,
682+ * and B <= MLDSA_Q - REDUCE32_RANGE_MAX, to check if
683+ * -B < (a mod± MLDSA_Q) < B, it suffices to check if -B < a < B.
684+ *
685+ * We prove this to be true using the following CBMC assertions.
686+ * a ==> b expressed as !a || b to also allow run-time assertion.
687+ */
688+ mld_assert (a -> coeffs [i ] < B || a -> coeffs [i ] - MLDSA_Q <= - B );
689+ mld_assert (a -> coeffs [i ] > - B || a -> coeffs [i ] + MLDSA_Q >= B );
690+
691+ /* Reference: Leaks which coefficient violates the bound via a conditional.
692+ * We are more conservative to reduce the number of declassifications in
693+ * constant-time testing.
694+ */
695+
696+ /* if (abs(a[i]) >= B) */
697+ t |= mld_ct_cmask_neg_i32 (B - 1 - mld_ct_abs_i32 (a -> coeffs [i ]));
698+ }
699+
700+ return t ;
701+ }
702+
661703/* Reference: explicitly checks the bound B to be <= (MLDSA_Q - 1) / 8).
662704 * This is unnecessary as it's always a compile-time constant.
663705 * We instead model it as a precondition.
@@ -671,8 +713,6 @@ void mld_polyt0_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT0_PACKEDBYTES])
671713MLD_INTERNAL_API
672714uint32_t mld_poly_chknorm (const mld_poly * a , int32_t B )
673715{
674- unsigned int i ;
675- uint32_t t = 0 ;
676716 mld_assert_bound (a -> coeffs , MLDSA_N , - REDUCE32_RANGE_MAX , REDUCE32_RANGE_MAX );
677717#if defined(MLD_USE_NATIVE_POLY_CHKNORM )
678718 {
@@ -702,34 +742,7 @@ uint32_t mld_poly_chknorm(const mld_poly *a, int32_t B)
702742 }
703743 }
704744#endif /* MLD_USE_NATIVE_POLY_CHKNORM */
705- for (i = 0 ; i < MLDSA_N ; ++ i )
706- __loop__ (
707- invariant (i <= MLDSA_N )
708- invariant (t == 0 || t == 0xFFFFFFFF )
709- invariant ((t == 0 ) == array_abs_bound (a -> coeffs , 0 , i , B ))
710- )
711- {
712- /*
713- * Since we know that -REDUCE32_RANGE_MAX <= a < REDUCE32_RANGE_MAX,
714- * and B <= MLDSA_Q - REDUCE32_RANGE_MAX, to check if
715- * -B < (a mod± MLDSA_Q) < B, it suffices to check if -B < a < B.
716- *
717- * We prove this to be true using the following CBMC assertions.
718- * a ==> b expressed as !a || b to also allow run-time assertion.
719- */
720- mld_assert (a -> coeffs [i ] < B || a -> coeffs [i ] - MLDSA_Q <= - B );
721- mld_assert (a -> coeffs [i ] > - B || a -> coeffs [i ] + MLDSA_Q >= B );
722-
723- /* Reference: Leaks which coefficient violates the bound via a conditional.
724- * We are more conservative to reduce the number of declassifications in
725- * constant-time testing.
726- */
727-
728- /* if (abs(a[i]) >= B) */
729- t |= mld_ct_cmask_neg_i32 (B - 1 - mld_ct_abs_i32 (a -> coeffs [i ]));
730- }
731-
732- return t ;
745+ return mld_poly_chknorm_c (a , B );
733746}
734747
735748#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */
0 commit comments