Skip to content

Commit 45ba4b3

Browse files
committed
Lowram: Refactor verify into per-row loop, drop polyveck w1/t1/h
Restructure mld_sign_verify_internal so that w1, t1 and h live as single mld_poly scratch buffers instead of full mld_polyveck vectors. Each row of A * z - c * t1 * 2^d, the use_hint correction and the polyw1 packing are now done one polynomial at a time. Convert mld_unpack_pk_t1 and mld_sig_unpack_hints to per-row APIs (mld_unpack_pk_t1 takes the row index, mld_sig_unpack_hints decodes and validates one row at a time, with the trailing-zero check folded into the i == K-1 iteration). Drop the now-unused mld_polyveck_{sub,shiftl,pointwise_poly_montgomery, use_hint} helpers and their CBMC harnesses, and narrow the guards on mld_polyveck_ntt and mld_polyveck_pack_w1 accordingly. Signed-off-by: Matthias J. Kannwischer <matthias@zerorisc.com>
1 parent c1725f3 commit 45ba4b3

25 files changed

Lines changed: 196 additions & 651 deletions

File tree

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
# Copyright (c) The mldsa-native project authors
22
# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
33
diff --git a/sw/device/lib/crypto/include/mldsa.h b/sw/device/lib/crypto/include/mldsa.h
4-
index be11f20..9112042 100644
54
--- a/sw/device/lib/crypto/include/mldsa.h
65
+++ b/sw/device/lib/crypto/include/mldsa.h
76
@@ -41,17 +41,17 @@ enum {
@@ -13,21 +12,21 @@ index be11f20..9112042 100644
1312
- kOtcryptoMldsa44WorkBufferVerifyWords = 22464 / sizeof(uint32_t),
1413
+ kOtcryptoMldsa44WorkBufferKeypairWords = 13632 / sizeof(uint32_t),
1514
+ kOtcryptoMldsa44WorkBufferSignWords = 13120 / sizeof(uint32_t),
16-
+ kOtcryptoMldsa44WorkBufferVerifyWords = 13184 / sizeof(uint32_t),
15+
+ kOtcryptoMldsa44WorkBufferVerifyWords = 9120 / sizeof(uint32_t),
1716

1817
- kOtcryptoMldsa65WorkBufferKeypairWords = 46304 / sizeof(uint32_t),
1918
- kOtcryptoMldsa65WorkBufferSignWords = 44768 / sizeof(uint32_t),
2019
- kOtcryptoMldsa65WorkBufferVerifyWords = 30720 / sizeof(uint32_t),
2120
+ kOtcryptoMldsa65WorkBufferKeypairWords = 19776 / sizeof(uint32_t),
2221
+ kOtcryptoMldsa65WorkBufferSignWords = 17248 / sizeof(uint32_t),
23-
+ kOtcryptoMldsa65WorkBufferVerifyWords = 18368 / sizeof(uint32_t),
22+
+ kOtcryptoMldsa65WorkBufferVerifyWords = 10208 / sizeof(uint32_t),
2423

2524
- kOtcryptoMldsa87WorkBufferKeypairWords = 62688 / sizeof(uint32_t),
2625
- kOtcryptoMldsa87WorkBufferSignWords = 59104 / sizeof(uint32_t),
2726
- kOtcryptoMldsa87WorkBufferVerifyWords = 41216 / sizeof(uint32_t),
2827
+ kOtcryptoMldsa87WorkBufferKeypairWords = 25920 / sizeof(uint32_t),
2928
+ kOtcryptoMldsa87WorkBufferSignWords = 21344 / sizeof(uint32_t),
30-
+ kOtcryptoMldsa87WorkBufferVerifyWords = 24768 / sizeof(uint32_t),
29+
+ kOtcryptoMldsa87WorkBufferVerifyWords = 12512 / sizeof(uint32_t),
3130
};
3231

3332
/**

mldsa/mldsa_native.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -323,14 +323,10 @@
323323
#undef mld_polyveck_pack_eta
324324
#undef mld_polyveck_pack_t0
325325
#undef mld_polyveck_pack_w1
326-
#undef mld_polyveck_pointwise_poly_montgomery
327326
#undef mld_polyveck_power2round
328327
#undef mld_polyveck_reduce
329-
#undef mld_polyveck_shiftl
330-
#undef mld_polyveck_sub
331328
#undef mld_polyveck_unpack_eta
332329
#undef mld_polyveck_unpack_t0
333-
#undef mld_polyveck_use_hint
334330
#undef mld_polyvecl
335331
#undef mld_polyvecl_chknorm
336332
#undef mld_polyvecl_ntt

mldsa/mldsa_native.h

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -942,33 +942,33 @@ int MLD_API_NAMESPACE(pk_from_sk)(
942942
#define MLD_TOTAL_ALLOC_44_KEYPAIR_PCT 48480
943943
#define MLD_TOTAL_ALLOC_44_PK_FROM_SK 37056
944944
#define MLD_TOTAL_ALLOC_44_SIGN 44704
945-
#define MLD_TOTAL_ALLOC_44_VERIFY 25472
945+
#define MLD_TOTAL_ALLOC_44_VERIFY 24448
946946
#define MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT 49440
947947
#define MLD_TOTAL_ALLOC_65_KEYPAIR_PCT 74624
948948
#define MLD_TOTAL_ALLOC_65_PK_FROM_SK 60608
949949
#define MLD_TOTAL_ALLOC_65_SIGN 69312
950-
#define MLD_TOTAL_ALLOC_65_VERIFY 42944
950+
#define MLD_TOTAL_ALLOC_65_VERIFY 39872
951951
#define MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT 82208
952952
#define MLD_TOTAL_ALLOC_87_KEYPAIR_PCT 115488
953953
#define MLD_TOTAL_ALLOC_87_PK_FROM_SK 97472
954954
#define MLD_TOTAL_ALLOC_87_SIGN 108224
955-
#define MLD_TOTAL_ALLOC_87_VERIFY 73920
955+
#define MLD_TOTAL_ALLOC_87_VERIFY 68800
956956
#else /* MLD_API_LEGACY_CONFIG || !MLD_CONFIG_REDUCE_RAM */
957957
#define MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT 13632
958-
#define MLD_TOTAL_ALLOC_44_KEYPAIR_PCT 16960
958+
#define MLD_TOTAL_ALLOC_44_KEYPAIR_PCT 16896
959959
#define MLD_TOTAL_ALLOC_44_PK_FROM_SK 21728
960960
#define MLD_TOTAL_ALLOC_44_SIGN 13120
961-
#define MLD_TOTAL_ALLOC_44_VERIFY 13184
961+
#define MLD_TOTAL_ALLOC_44_VERIFY 9120
962962
#define MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT 19776
963-
#define MLD_TOTAL_ALLOC_65_KEYPAIR_PCT 23680
963+
#define MLD_TOTAL_ALLOC_65_KEYPAIR_PCT 22560
964964
#define MLD_TOTAL_ALLOC_65_PK_FROM_SK 30944
965965
#define MLD_TOTAL_ALLOC_65_SIGN 17248
966-
#define MLD_TOTAL_ALLOC_65_VERIFY 18368
966+
#define MLD_TOTAL_ALLOC_65_VERIFY 10208
967967
#define MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT 25920
968-
#define MLD_TOTAL_ALLOC_87_KEYPAIR_PCT 32032
968+
#define MLD_TOTAL_ALLOC_87_KEYPAIR_PCT 28608
969969
#define MLD_TOTAL_ALLOC_87_PK_FROM_SK 41184
970970
#define MLD_TOTAL_ALLOC_87_SIGN 21344
971-
#define MLD_TOTAL_ALLOC_87_VERIFY 24768
971+
#define MLD_TOTAL_ALLOC_87_VERIFY 12512
972972
#endif /* !(MLD_API_LEGACY_CONFIG || !MLD_CONFIG_REDUCE_RAM) */
973973
/* check-magic: on */
974974

mldsa/mldsa_native_asm.S

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -328,14 +328,10 @@
328328
#undef mld_polyveck_pack_eta
329329
#undef mld_polyveck_pack_t0
330330
#undef mld_polyveck_pack_w1
331-
#undef mld_polyveck_pointwise_poly_montgomery
332331
#undef mld_polyveck_power2round
333332
#undef mld_polyveck_reduce
334-
#undef mld_polyveck_shiftl
335-
#undef mld_polyveck_sub
336333
#undef mld_polyveck_unpack_eta
337334
#undef mld_polyveck_unpack_t0
338-
#undef mld_polyveck_use_hint
339335
#undef mld_polyvecl
340336
#undef mld_polyvecl_chknorm
341337
#undef mld_polyvecl_ntt

mldsa/src/packing.c

Lines changed: 35 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,11 @@ void mld_pack_pk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES],
3838

3939
#if !defined(MLD_CONFIG_NO_VERIFY_API)
4040
MLD_INTERNAL_API
41-
void mld_unpack_pk_t1(mld_polyveck *t1,
42-
const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES])
41+
void mld_unpack_pk_t1(mld_poly *t1,
42+
const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES],
43+
unsigned int i)
4344
{
44-
unsigned int i;
45-
46-
pk += MLDSA_SEEDBYTES;
47-
48-
for (i = 0; i < MLDSA_K; ++i)
49-
{
50-
mld_polyt1_unpack(&t1->vec[i], pk + i * MLDSA_POLYT1_PACKEDBYTES);
51-
}
45+
mld_polyt1_unpack(t1, pk + MLDSA_SEEDBYTES + i * MLDSA_POLYT1_PACKEDBYTES);
5246
}
5347
#endif /* !MLD_CONFIG_NO_VERIFY_API */
5448

@@ -172,75 +166,52 @@ void mld_pack_sig_z(uint8_t sig[MLDSA_CRYPTO_BYTES], const mld_poly *zi,
172166

173167
#if !defined(MLD_CONFIG_NO_VERIFY_API)
174168
MLD_INTERNAL_API
175-
int mld_sig_unpack_hints(mld_polyveck *h, const uint8_t sig[MLDSA_CRYPTO_BYTES])
169+
int mld_sig_unpack_hints(mld_poly *h, const uint8_t sig[MLDSA_CRYPTO_BYTES],
170+
unsigned int i)
176171
{
177172
const uint8_t *packed_hints =
178173
sig + MLDSA_CTILDEBYTES + MLDSA_L * MLDSA_POLYZ_PACKEDBYTES;
179-
unsigned int i, j;
180-
unsigned int old_hint_count;
174+
const unsigned int old_hint_count =
175+
(i == 0) ? 0 : packed_hints[MLDSA_OMEGA + i - 1];
176+
const unsigned int new_hint_count = packed_hints[MLDSA_OMEGA + i];
177+
unsigned int j;
181178

182-
/* Set all coefficients of all polynomials to 0. */
183-
/* Only those that are actually non-zero hints will */
184-
/* be overwritten below. */
185-
mld_memset(h, 0, sizeof(mld_polyveck));
179+
if (new_hint_count < old_hint_count || new_hint_count > MLDSA_OMEGA)
180+
{
181+
return MLD_ERR_FAIL;
182+
}
186183

187-
old_hint_count = 0;
188-
for (i = 0; i < MLDSA_K; ++i)
184+
mld_memset(h, 0, sizeof(mld_poly));
185+
186+
for (j = old_hint_count; j < new_hint_count; ++j)
189187
__loop__(
190-
invariant(i <= MLDSA_K)
191-
/* Maintain the post-condition */
192-
invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2)))
193-
decreases(MLDSA_K - i)
188+
invariant(j >= old_hint_count && j <= new_hint_count &&
189+
new_hint_count <= MLDSA_OMEGA)
190+
invariant(array_bound(h->coeffs, 0, MLDSA_N, 0, 2))
191+
decreases(new_hint_count - j)
194192
)
195193
{
196-
/* Grab the hint count for the i'th polynomial */
197-
const unsigned int new_hint_count = packed_hints[MLDSA_OMEGA + i];
198-
199-
/* new_hint_count must increase or stay the same, but also remain */
200-
/* less than or equal to MLDSA_OMEGA */
201-
if (new_hint_count < old_hint_count || new_hint_count > MLDSA_OMEGA)
194+
if (j > old_hint_count && packed_hints[j] <= packed_hints[j - 1])
202195
{
203-
/* Error - new_hint_count is invalid */
204-
return 1;
196+
return MLD_ERR_FAIL;
205197
}
198+
/* Safety: packed_hints[j] is uint8_t (<= 255) and MLDSA_N == 256. */
199+
h->coeffs[packed_hints[j]] = 1;
200+
}
206201

207-
/* If new_hint_count == old_hint_count, then this polynomial has */
208-
/* zero hints, so this loop executes zero times and we move */
209-
/* straight on to the next polynomial. */
210-
for (j = old_hint_count; j < new_hint_count; ++j)
202+
/* On the last row, also verify that the trailing index slots are zero. */
203+
if (i == MLDSA_K - 1)
204+
{
205+
for (j = new_hint_count; j < MLDSA_OMEGA; ++j)
211206
__loop__(
212-
invariant(i <= MLDSA_K)
213-
/* Maintain the post-condition */
214-
invariant(j <= new_hint_count && new_hint_count <= MLDSA_OMEGA)
215-
invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2)))
216-
decreases(new_hint_count - j)
217-
)
207+
invariant(j <= MLDSA_OMEGA)
208+
decreases(MLDSA_OMEGA - j)
209+
)
218210
{
219-
const uint8_t this_hint_index = packed_hints[j];
220-
221-
/* Coefficients must be ordered for strong unforgeability */
222-
if (j > old_hint_count && this_hint_index <= packed_hints[j - 1])
211+
if (packed_hints[j] != 0)
223212
{
224-
return 1;
213+
return MLD_ERR_FAIL;
225214
}
226-
h->vec[i].coeffs[this_hint_index] = 1;
227-
}
228-
229-
old_hint_count = new_hint_count;
230-
}
231-
232-
/* Extra indices must be zero for strong unforgeability */
233-
for (j = old_hint_count; j < MLDSA_OMEGA; ++j)
234-
__loop__(
235-
invariant(j <= MLDSA_OMEGA)
236-
/* Maintain the post-condition */
237-
invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2)))
238-
decreases(MLDSA_OMEGA - j)
239-
)
240-
{
241-
if (packed_hints[j] != 0)
242-
{
243-
return 1;
244215
}
245216
}
246217

mldsa/src/packing.h

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -163,20 +163,23 @@ __contract__(
163163
/*************************************************
164164
* Name: mld_unpack_pk_t1
165165
*
166-
* Description: Unpack the t1 component of a public key pk = (rho, t1).
166+
* Description: Unpack a single polynomial of the t1 component of a public
167+
* key pk = (rho, t1).
167168
*
168-
* Arguments: - mld_polyveck *t1: pointer to output vector t1
169+
* Arguments: - mld_poly *t1: pointer to output polynomial t1[i]
169170
* - uint8_t pk[]: byte array containing bit-packed pk
171+
* - unsigned int i: row index, must be < MLDSA_K
170172
**************************************************/
171173
MLD_INTERNAL_API
172-
void mld_unpack_pk_t1(mld_polyveck *t1,
173-
const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES])
174+
void mld_unpack_pk_t1(mld_poly *t1,
175+
const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES],
176+
unsigned int i)
174177
__contract__(
175178
requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES))
176-
requires(memory_no_alias(t1, sizeof(mld_polyveck)))
177-
assigns(memory_slice(t1, sizeof(mld_polyveck)))
178-
ensures(forall(k0, 0, MLDSA_K,
179-
array_bound(t1->vec[k0].coeffs, 0, MLDSA_N, 0, 1 << 10)))
179+
requires(memory_no_alias(t1, sizeof(mld_poly)))
180+
requires(i < MLDSA_K)
181+
assigns(memory_slice(t1, sizeof(mld_poly)))
182+
ensures(array_bound(t1->coeffs, 0, MLDSA_N, 0, 1 << 10))
180183
);
181184
#endif /* !MLD_CONFIG_NO_VERIFY_API */
182185

@@ -240,25 +243,38 @@ __contract__(
240243
/*************************************************
241244
* Name: mld_sig_unpack_hints
242245
*
243-
* Description: Unpack hint vector h from a signature buffer.
246+
* Description: Decode and validate a single row of the hint vector h
247+
* from a signature buffer. The hint encoding is shared
248+
* across all rows (a count array followed by a single
249+
* index list), so this function performs the validation
250+
* relevant to row i:
251+
* - the i'th hint count is non-decreasing and bounded
252+
* by MLDSA_OMEGA;
253+
* - the indices for row i are strictly ascending;
254+
* - on i == MLDSA_K - 1, the trailing index slots are
255+
* zero.
256+
* Callers must invoke this for every
257+
* i in {0, 1, ..., MLDSA_K - 1}; if any call returns
258+
* MLD_ERR_FAIL the encoding is malformed and the signature
259+
* must be rejected.
244260
*
245-
* Arguments: - mld_polyveck *h: pointer to output hint vector
261+
* Arguments: - mld_poly *h: pointer to output polynomial h[i]
246262
* - const uint8_t sig[]: signature buffer
247-
* (MLDSA_CRYPTO_BYTES); the hint bytes are read from
248-
* the trailing MLDSA_POLYVECH_PACKEDBYTES.
263+
* - unsigned int i: row index, must be < MLDSA_K
249264
*
250-
* Returns 1 in case of malformed hints; otherwise 0.
265+
* Returns MLD_ERR_FAIL in case of malformed hints; otherwise 0.
251266
**************************************************/
252267
MLD_INTERNAL_API
253268
MLD_MUST_CHECK_RETURN_VALUE
254-
int mld_sig_unpack_hints(mld_polyveck *h, const uint8_t sig[MLDSA_CRYPTO_BYTES])
269+
int mld_sig_unpack_hints(mld_poly *h, const uint8_t sig[MLDSA_CRYPTO_BYTES],
270+
unsigned int i)
255271
__contract__(
256272
requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES))
257-
requires(memory_no_alias(h, sizeof(mld_polyveck)))
258-
assigns(memory_slice(h, sizeof(mld_polyveck)))
259-
ensures(forall(k1, 0, MLDSA_K,
260-
array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2)))
261-
ensures(return_value >= 0 && return_value <= 1)
273+
requires(memory_no_alias(h, sizeof(mld_poly)))
274+
requires(i < MLDSA_K)
275+
assigns(memory_slice(h, sizeof(mld_poly)))
276+
ensures(return_value == 0 || return_value == MLD_ERR_FAIL)
277+
ensures(return_value == 0 ==> array_bound(h->coeffs, 0, MLDSA_N, 0, 2))
262278
);
263279
#endif /* !MLD_CONFIG_NO_VERIFY_API */
264280

0 commit comments

Comments
 (0)