Skip to content

Commit 447afbe

Browse files
committed
Introduce helper functions for signed<-> unsigned conversions
This commit introduces helper functions mld_cast_uint32_to_int32, mld_cast_int32_to_uint32, and mld_cast_int64_to_uint32 for int64_t->uint32_t, and int32_t <-> uint32_t. This cleans up prior code and also removes the need for some pragmas stopping CBMC from flagging value-changing integer conversions. This commit is based on pq-code-package/mlkem-native@e5adf3a (but for 32-bit integers. Signed-off-by: Matthias J. Kannwischer <[email protected]>
1 parent 4da63d6 commit 447afbe

File tree

2 files changed

+60
-66
lines changed

2 files changed

+60
-66
lines changed

mldsa/ct.h

Lines changed: 60 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -111,18 +111,67 @@ __contract__(ensures(return_value == b))
111111
}
112112
#endif /* MLD_USE_ASM_VALUE_BARRIER */
113113

114-
115-
/*
116-
* The mld_ct_sel_int32 function below makes deliberate use of unsigned
117-
* to signed integer conversion, which is implementation-defined
118-
* behaviour. Here, we assume that uint16_t -> int16_t is inverse
119-
* to int16_t -> uint16_t.
120-
*/
121114
#ifdef CBMC
122115
#pragma CPROVER check push
123116
#pragma CPROVER check disable "conversion"
124117
#endif
125118

119+
/*************************************************
120+
* Name: mld_cast_uint32_to_int32
121+
*
122+
* Description: Cast uint32 value to int32
123+
*
124+
* Returns: For uint32_t x, the unique y in int32_t
125+
* so that x == y mod 2^32.
126+
*
127+
* Concretely:
128+
* - x < 2^31: returns x
129+
* - x >= 2^31: returns x - 2^31
130+
*
131+
**************************************************/
132+
static MLD_ALWAYS_INLINE int32_t mld_cast_uint32_to_int32(uint32_t x)
133+
{
134+
/*
135+
* PORTABILITY: This relies on uint32_t -> int32_t
136+
* being implemented as the inverse of int32_t -> uint32_t,
137+
* which is implementation-defined (C99 6.3.1.3 (3))
138+
* CBMC (correctly) fails to prove this conversion is OK,
139+
* so we have to suppress that check here
140+
*/
141+
return (int32_t)x;
142+
}
143+
144+
#ifdef CBMC
145+
#pragma CPROVER check pop
146+
#endif
147+
148+
149+
/*************************************************
150+
* Name: mld_cast_int64_to_uint32
151+
*
152+
* Description: Cast int64 value to uint32 as per C standard.
153+
*
154+
* Returns: For int64_t x, the unique y in uint32_t
155+
* so that x == y mod 2^32.
156+
**************************************************/
157+
static MLD_ALWAYS_INLINE uint32_t mld_cast_int64_to_uint32(int64_t x)
158+
{
159+
return (uint32_t)(x & (int64_t)UINT32_MAX);
160+
}
161+
162+
/*************************************************
163+
* Name: mld_cast_int32_to_uint32
164+
*
165+
* Description: Cast int32 value to uint32 as per C standard.
166+
*
167+
* Returns: For int32_t x, the unique y in uint32_t
168+
* so that x == y mod 2^32.
169+
**************************************************/
170+
static MLD_ALWAYS_INLINE uint32_t mld_cast_int32_to_uint32(int32_t x)
171+
{
172+
return mld_cast_int64_to_uint32((int64_t)x);
173+
}
174+
126175
/*************************************************
127176
* Name: mld_ct_sel_int32
128177
*
@@ -137,35 +186,17 @@ __contract__(ensures(return_value == b))
137186
*
138187
**************************************************/
139188
static MLD_INLINE int32_t mld_ct_sel_int32(int32_t a, int32_t b, uint32_t cond)
140-
/* TODO: proof */
141189
__contract__(
142190
requires(cond == 0x0 || cond == 0xFFFFFFFF)
143191
ensures(return_value == (cond ? a : b))
144192
)
145193
{
146-
uint32_t au = a, bu = b;
194+
uint32_t au = mld_cast_int32_to_uint32(a);
195+
uint32_t bu = mld_cast_int32_to_uint32(b);
147196
uint32_t res = bu ^ (mld_value_barrier_u32(cond) & (au ^ bu));
148-
return (int32_t)res;
197+
return mld_cast_uint32_to_int32(res);
149198
}
150199

151-
/* Put unsigned-to-signed warnings in CBMC back into scope */
152-
#ifdef CBMC
153-
#pragma CPROVER check pop
154-
#endif
155-
156-
157-
158-
/*
159-
* The mld_ct_cmask_neg_i32 function below makes deliberate use of
160-
* signed to unsigned integer conversion, which is fully defined
161-
* behaviour in C. It is thus safe to disable this warning.
162-
*/
163-
#ifdef CBMC
164-
#pragma CPROVER check push
165-
#pragma CPROVER check disable "conversion"
166-
#endif
167-
168-
169200
/*************************************************
170201
* Name: mld_ct_cmask_neg_i32
171202
*
@@ -174,22 +205,16 @@ __contract__(
174205
* Arguments: int32_t x: Value to be converted into a mask
175206
*
176207
**************************************************/
177-
/* TODO: proof */
178208
static MLD_INLINE uint32_t mld_ct_cmask_neg_i32(int32_t x)
179209
__contract__(
180210
ensures(return_value == ((x < 0) ? 0xFFFFFFFF : 0))
181211
)
182212
{
183213
int64_t tmp = mld_value_barrier_i64((int64_t)x);
184214
tmp >>= 31;
185-
return (uint32_t)tmp;
215+
return mld_cast_int64_to_uint32(tmp);
186216
}
187217

188-
/* Put signed-to-unsigned warnings in CBMC back into scope */
189-
#ifdef CBMC
190-
#pragma CPROVER check pop
191-
#endif
192-
193218
/*************************************************
194219
* Name: mld_ct_abs_i32
195220
*
@@ -198,7 +223,6 @@ __contract__(
198223
* Arguments: int32_t x: Input value
199224
*
200225
**************************************************/
201-
/* TODO: proof */
202226
static MLD_INLINE int32_t mld_ct_abs_i32(int32_t x)
203227
__contract__(
204228
requires(x >= -INT32_MAX)

mldsa/reduce.h

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -27,36 +27,6 @@
2727
/* Absolute bound for tight domain of mld_montgomery_reduce() */
2828
#define MONTGOMERY_REDUCE_STRONG_DOMAIN_MAX ((int64_t)INT32_MIN * -MLDSA_Q)
2929

30-
31-
32-
/*************************************************
33-
* Name: mld_cast_uint32_to_int32
34-
*
35-
* Description: Cast uint32 value to int32
36-
*
37-
* Returns:
38-
* input x in 0 .. 2^31-1: returns value unchanged
39-
* input x in 2^31 .. 2^32-1: returns (x - 2^32)
40-
**************************************************/
41-
#ifdef CBMC
42-
#pragma CPROVER check push
43-
#pragma CPROVER check disable "conversion"
44-
#endif
45-
static MLD_INLINE int32_t mld_cast_uint32_to_int32(uint32_t x)
46-
{
47-
/*
48-
* PORTABILITY: This relies on uint32_t -> int32_t
49-
* being implemented as the inverse of int32_t -> uint32_t,
50-
* which is implementation-defined (C99 6.3.1.3 (3))
51-
* CBMC (correctly) fails to prove this conversion is OK,
52-
* so we have to suppress that check here
53-
*/
54-
return (int32_t)x;
55-
}
56-
#ifdef CBMC
57-
#pragma CPROVER check pop
58-
#endif
59-
6030
/*************************************************
6131
* Name: mld_montgomery_reduce
6232
*

0 commit comments

Comments
 (0)