Skip to content

Commit ba6e679

Browse files
committed
Remove unused spec for mld_montgomery_reduce, add bounds reasoning
Context: We previously had two specifications for mld_montgomery_reduce: - A 'weak' one where the output upper bound matches the input upper bound of mld_reduce32(). - A 'strong' one where the output interval is (-Q,Q), exclusively. Both contracts were combined into one in a somewhat ad-hoc way (the 'weak' version being encoded as pre- and post-conditions as usual, the 'strong' version being stated as an implication in the post-condition). The combined contract was used in the CBMC proofs of - mld_poly_pointwise_montgomery - mld_polyvecl_pointwise_acc_montgomery There are two more functions which rely on mld_montgomery_reduce, namely - mld_fqmul - mld_fqscale Observations: - The 'weak' contract of mld_montgomery_reduce is not needed: In the context of mld_poly_pointwise_montgomery and mld_polyvecl_pointwise_acc_montgomery, the strong version applies. - The 'strong' version also applies in the context of mld_fqmul and mld_fqscale. Accordingly, this commit removes the 'weak' version and re-formulates the 'strong' version in traditional pre/post condition form. The commit also removes the macro wrapper around the input bound, which I find difficult to read. It's easier to understand if the bound is explicit. The 'strong' version only applies to `mld_fqscale` because of the recent modification of the iNTT output bound from 3/4*Q to Q. Otherwise, an even stronger spec would have been needed. At present, one can even remove mld_fqscale and just call mld_fqmul directly, but this commit does not do this. The commit also takes the opportunity to add some pen-and-paper bounds reasoning for mld_montgomery_reduce. It is explained why under the _inclusive_ input bound 2^31 * MLDSA_Q one gets an _inclusive_ output bound by MLDSA_Q. However, a pen-and-paper argument that the same holds for _exclusive_ input/output bounds -- which is what the 'strong' CBMC spec states -- is still missing. Signed-off-by: Hanno Becker <beckphan@amazon.co.uk>
1 parent 8e74a84 commit ba6e679

File tree

4 files changed

+43
-31
lines changed

4 files changed

+43
-31
lines changed

mldsa/mldsa_native.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -374,8 +374,6 @@
374374
/* mldsa/src/reduce.h */
375375
#undef MLD_REDUCE_H
376376
#undef MONT
377-
#undef MONTGOMERY_REDUCE_DOMAIN_MAX
378-
#undef MONTGOMERY_REDUCE_STRONG_DOMAIN_MAX
379377
#undef REDUCE32_DOMAIN_MAX
380378
#undef REDUCE32_RANGE_MAX
381379
/* mldsa/src/symmetric.h */

mldsa/src/reduce.h

Lines changed: 41 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -21,41 +21,33 @@
2121
/* check-magic: 6283009 == (REDUCE32_DOMAIN_MAX - 255 * MLDSA_Q + 1) */
2222
#define REDUCE32_RANGE_MAX 6283009
2323

24-
/* Absolute bound for domain of mld_montgomery_reduce() */
25-
#define MONTGOMERY_REDUCE_DOMAIN_MAX ((int64_t)INT32_MIN * INT32_MIN)
26-
27-
/* Absolute bound for tight domain of mld_montgomery_reduce() */
28-
#define MONTGOMERY_REDUCE_STRONG_DOMAIN_MAX ((int64_t)INT32_MIN * -MLDSA_Q)
29-
3024
/*************************************************
3125
* Name: mld_montgomery_reduce
3226
*
33-
* Description:
34-
* For finite field element a with
35-
* -MONTGOMERY_REDUCE_DOMAIN_MAX <= a <= MONTGOMERY_REDUCE_DOMAIN_MAX,
36-
* compute r == a*2^{-32} (mod MLDSA_Q) such that
37-
* INT32_MIN <= r < REDUCE32_DOMAIN_MAX
27+
* Description: Generic Montgomery reduction; given a 64-bit integer a, computes
28+
* 32-bit integer congruent to a * R^-1 mod q, where R=2^32
3829
*
39-
* The upper-bound on the result ensures that a result from this
40-
* function can be used as an input to mld_reduce32() declared below.
30+
* Arguments: - int64_t a: input integer to be reduced, of absolute value
31+
* smaller or equal to INT64_MAX - 2^31 * MLDSA_Q.
4132
*
42-
* Additionally, as a special case, if the input a is in range
43-
* -MONTGOMERY_REDUCE_STRONG_DOMAIN_MAX < a <
44-
* MONTGOMERY_REDUCE_STRONG_DOMAIN_MAX
45-
* then the result satisfies -MLDSA_Q < r < MLDSA_Q.
33+
* Returns: Integer congruent to a * R^-1 modulo q, with absolute value
34+
* <= ceil(|a| / 2^32 + MLDSA_Q / 2)
4635
*
47-
* Arguments: - int64_t: finite field element a
36+
* In particular, if |a| <= 2^31 * MLDSA_Q, the absolute value
37+
* of the return value is <= MLDSA_Q.
4838
*
49-
* Returns r.
39+
* For |a| < 2^31 * MLDSA_Q, the return value is even < MLDSA_Q
40+
* in absolute value. This is what the CBMC specification encodes.
5041
**************************************************/
5142
static MLD_INLINE int32_t mld_montgomery_reduce(int64_t a)
5243
__contract__(
53-
requires(a >= -MONTGOMERY_REDUCE_DOMAIN_MAX && a <= MONTGOMERY_REDUCE_DOMAIN_MAX)
54-
ensures(return_value >= INT32_MIN && return_value < REDUCE32_DOMAIN_MAX)
55-
56-
/* Special case - for stronger input bounds, we can ensure stronger bounds on the output */
57-
ensures((a >= -MONTGOMERY_REDUCE_STRONG_DOMAIN_MAX && a < MONTGOMERY_REDUCE_STRONG_DOMAIN_MAX) ==>
58-
(return_value > -MLDSA_Q && return_value < MLDSA_Q))
44+
/* We don't attempt to express an input-dependent output bound
45+
* as the post-condition here, as all call-sites satisfy the
46+
* absolute input bound 2^31 * MLDSA_Q and higher-level
47+
* reasoning can be conducted using |return_value| < MLDSA_Q. */
48+
requires(a > ((int64_t)INT32_MIN * MLDSA_Q) &&
49+
a < -((int64_t)INT32_MIN * MLDSA_Q))
50+
ensures(return_value > -MLDSA_Q && return_value < MLDSA_Q)
5951
)
6052
{
6153
/* check-magic: 58728449 == unsigned_mod(pow(MLDSA_Q, -1, 2^32), 2^32) */
@@ -68,16 +60,38 @@ __contract__(
6860
/* Lift to signed canonical representative mod 2^32. */
6961
const int32_t t = mld_cast_uint32_to_int32(a_inverted);
7062

71-
int64_t r;
63+
int64_t r, tp;
64+
65+
mld_assert(a < +(INT64_MAX - (((int64_t)1 << 31) * MLDSA_Q)) &&
66+
a > -(INT64_MAX - (((int64_t)1 << 31) * MLDSA_Q)));
7267

73-
r = a - ((int64_t)t * MLDSA_Q);
68+
tp = (int64_t)t * MLDSA_Q;
69+
r = a - tp;
7470

7571
/*
7672
* PORTABILITY: Right-shift on a signed integer is, strictly-speaking,
7773
* implementation-defined for negative left argument. Here,
7874
* we assume it's sign-preserving "arithmetic" shift right. (C99 6.5.7 (5))
7975
*/
8076
r = r >> 32;
77+
/* Bounds: |r >> 32| <= ceil(|r| / 2^32)
78+
* <= ceil(|a| / 2^32 + MLDSA_Q / 2)
79+
*
80+
* (Note that |a >> n| = ceil(|a| / 2^n) for negative a).
81+
* This is the bound stated in the documentation.
82+
*
83+
* Note that for a = 2^31 * MLDSA_Q, we get return_value = MLDSA_Q, so the
84+
* bound is strict under the assumption |a| <= 2^31 * MLDSA_Q.
85+
*
86+
* However, if we assume a _strict_ input inequality |a| < 2^31 * MLDSA_Q,
87+
* the output inequality is _also_ strict:
88+
*
89+
* |return_value| < MLDSA_Q
90+
*
91+
* This is what is captured by the CBMC spec.
92+
*
93+
* TODO: Find a pen-and-paper argument.
94+
*/
8195
return (int32_t)r;
8296
}
8397

proofs/cbmc/fqmul/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
2020
PROJECT_SOURCES += $(SRCDIR)/mldsa/src/ntt.c
2121

2222
CHECK_FUNCTION_CONTRACTS=mld_fqmul
23-
USE_FUNCTION_CONTRACTS=
23+
USE_FUNCTION_CONTRACTS=mld_montgomery_reduce
2424
APPLY_LOOP_CONTRACTS=on
2525
USE_DYNAMIC_FRAMES=1
2626

proofs/cbmc/fqscale/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
2020
PROJECT_SOURCES += $(SRCDIR)/mldsa/src/ntt.c
2121

2222
CHECK_FUNCTION_CONTRACTS=mld_fqscale
23-
USE_FUNCTION_CONTRACTS=
23+
USE_FUNCTION_CONTRACTS=mld_montgomery_reduce
2424
APPLY_LOOP_CONTRACTS=on
2525
USE_DYNAMIC_FRAMES=1
2626

0 commit comments

Comments
 (0)