Skip to content

Commit 5221bd1

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. Fixes #602 Signed-off-by: Hanno Becker <beckphan@amazon.co.uk>
1 parent b4209ba commit 5221bd1

File tree

5 files changed

+44
-33
lines changed

5 files changed

+44
-33
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/ntt.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,15 @@ __contract__(
2727
ensures(return_value > -MLDSA_Q && return_value < MLDSA_Q)
2828
)
2929
{
30+
/* Bounds: We argue in mld_montgomery_reduce() that the reult
31+
* of Montgomery reduction is < MLDSA_Q if the input is smaller
32+
* than 2^31 * MLDSA_Q in absolute value. Indeed, we have:
33+
*
34+
* |a * b| = |a| * |b|
35+
* < 2^31 * MLDSA_Q_HALF
36+
* < 2^31 * MLDSA_Q
37+
*/
3038
return mld_montgomery_reduce((int64_t)a * (int64_t)b);
31-
/* TODO: reason about bounds */
3239
}
3340

3441
/*************************************************
@@ -50,8 +57,9 @@ __contract__(
5057
{
5158
/* check-magic: 41978 == pow(2,64-8,MLDSA_Q) */
5259
const int32_t f = 41978;
60+
/* Bounds: MLD_INTT_BOUND is MLDSA_Q, so the bounds reasoning is just
61+
* a special case of that in mld_fqmul(). */
5362
return mld_montgomery_reduce((int64_t)a * f);
54-
/* TODO: reason about bounds */
5563
}
5664

5765
#include "zetas.inc"

mldsa/src/reduce.h

Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -21,41 +21,30 @@
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+
* <= |a| / 2^32 + MLDSA_Q / 2
4635
*
47-
* Arguments: - int64_t: finite field element a
48-
*
49-
* Returns r.
36+
* In particular, if |a| < 2^31 * MLDSA_Q, the absolute value
37+
* of the return value is < MLDSA_Q.
5038
**************************************************/
5139
static MLD_INLINE int32_t mld_montgomery_reduce(int64_t a)
5240
__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))
41+
/* We don't attempt to express an input-dependent output bound
42+
* as the post-condition here, as all call-sites satisfy the
43+
* absolute input bound 2^31 * MLDSA_Q and higher-level
44+
* reasoning can be conducted using |return_value| < MLDSA_Q. */
45+
requires(a > -(((int64_t)1 << 31) * MLDSA_Q) &&
46+
a < (((int64_t)1 << 31) * MLDSA_Q))
47+
ensures(return_value > -MLDSA_Q && return_value < MLDSA_Q)
5948
)
6049
{
6150
/* check-magic: 58728449 == unsigned_mod(pow(MLDSA_Q, -1, 2^32), 2^32) */
@@ -70,14 +59,30 @@ __contract__(
7059

7160
int64_t r;
7261

73-
r = a - ((int64_t)t * MLDSA_Q);
62+
mld_assert(a < +(INT64_MAX - (((int64_t)1 << 31) * MLDSA_Q)) &&
63+
a > -(INT64_MAX - (((int64_t)1 << 31) * MLDSA_Q)));
64+
65+
r = a - (int64_t)t * MLDSA_Q;
7466

7567
/*
7668
* PORTABILITY: Right-shift on a signed integer is, strictly-speaking,
7769
* implementation-defined for negative left argument. Here,
7870
* we assume it's sign-preserving "arithmetic" shift right. (C99 6.5.7 (5))
7971
*/
8072
r = r >> 32;
73+
74+
/* Bounds:
75+
*
76+
* By construction of the Montgomery multiplication, by the time we
77+
* compute r >> 32, r is divisible by 2^32, and hence
78+
*
79+
* |r >> 32| = |r| / 2^32
80+
* <= |a| / 2^32 + MLDSA_Q / 2
81+
*
82+
* (In general, we would only have |x >> n| <= ceil(|x| / 2^n)).
83+
*
84+
* In particular, if |a| < 2^31 * MLDSA_Q, then |return_value| < MLDSA_Q.
85+
*/
8186
return (int32_t)r;
8287
}
8388

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)