Skip to content

Commit 086846b

Browse files
committed
sign: Compute h incrementally to reduce stack usage
Instead of allocating a full polyveck for h in attempt_signature_generation, compute cs2, ct0, and hints one polynomial at a time using scratch polys. This eliminates the polyveck h from the yh_u union, replacing mld_pack_sig_c_h with incremental packing via mld_pack_sig_c and mld_pack_sig_h_poly. This is a prerequisite for also eliminating y in a follow up. Signed-off-by: Matthias J. Kannwischer <matthias@zerorisc.com>
1 parent 69177fb commit 086846b

18 files changed

Lines changed: 189 additions & 418 deletions

File tree

integration/opentitan/reduce_alloc.patch

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@ index be11f20..26351ee 100644
1717
- kOtcryptoMldsa65WorkBufferKeypairWords = 46304 / sizeof(uint32_t),
1818
- kOtcryptoMldsa65WorkBufferSignWords = 44768 / sizeof(uint32_t),
1919
+ kOtcryptoMldsa65WorkBufferKeypairWords = 40224 / sizeof(uint32_t),
20-
+ kOtcryptoMldsa65WorkBufferSignWords = 27456 / sizeof(uint32_t),
20+
+ kOtcryptoMldsa65WorkBufferSignWords = 26432 / sizeof(uint32_t),
2121
kOtcryptoMldsa65WorkBufferVerifyWords = 30720 / sizeof(uint32_t),
2222

2323
- kOtcryptoMldsa87WorkBufferKeypairWords = 62688 / sizeof(uint32_t),
2424
- kOtcryptoMldsa87WorkBufferSignWords = 59104 / sizeof(uint32_t),
2525
+ kOtcryptoMldsa87WorkBufferKeypairWords = 54560 / sizeof(uint32_t),
26-
+ kOtcryptoMldsa87WorkBufferSignWords = 35648 / sizeof(uint32_t),
26+
+ kOtcryptoMldsa87WorkBufferSignWords = 34624 / sizeof(uint32_t),
2727
kOtcryptoMldsa87WorkBufferVerifyWords = 41216 / sizeof(uint32_t),
2828
};
2929

mldsa/mldsa_native.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,8 @@
257257
/* mldsa/src/packing.h */
258258
#undef MLD_PACKING_H
259259
#undef mld_pack_pk
260-
#undef mld_pack_sig_c_h
260+
#undef mld_pack_sig_c
261+
#undef mld_pack_sig_h_poly
261262
#undef mld_pack_sig_z
262263
#undef mld_pack_sk
263264
#undef mld_unpack_pk
@@ -319,7 +320,6 @@
319320
#undef mld_polyveck_chknorm
320321
#undef mld_polyveck_decompose
321322
#undef mld_polyveck_invntt_tomont
322-
#undef mld_polyveck_make_hint
323323
#undef mld_polyveck_ntt
324324
#undef mld_polyveck_pack_eta
325325
#undef mld_polyveck_pack_t0

mldsa/mldsa_native.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -913,19 +913,19 @@ int MLD_API_NAMESPACE(pk_from_sk)(
913913
/* check-magic: off */
914914
#if defined(MLD_API_LEGACY_CONFIG) || !defined(MLD_CONFIG_REDUCE_RAM)
915915
#define MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT 41216
916-
#define MLD_TOTAL_ALLOC_44_KEYPAIR_PCT 56640
916+
#define MLD_TOTAL_ALLOC_44_KEYPAIR_PCT 52544
917917
#define MLD_TOTAL_ALLOC_44_PK_FROM_SK 45248
918-
#define MLD_TOTAL_ALLOC_44_SIGN 52896
918+
#define MLD_TOTAL_ALLOC_44_SIGN 48800
919919
#define MLD_TOTAL_ALLOC_44_VERIFY 38816
920920
#define MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT 65792
921-
#define MLD_TOTAL_ALLOC_65_KEYPAIR_PCT 85856
921+
#define MLD_TOTAL_ALLOC_65_KEYPAIR_PCT 79712
922922
#define MLD_TOTAL_ALLOC_65_PK_FROM_SK 71872
923-
#define MLD_TOTAL_ALLOC_65_SIGN 80576
923+
#define MLD_TOTAL_ALLOC_65_SIGN 74432
924924
#define MLD_TOTAL_ALLOC_65_VERIFY 62432
925925
#define MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT 104704
926-
#define MLD_TOTAL_ALLOC_87_KEYPAIR_PCT 130816
926+
#define MLD_TOTAL_ALLOC_87_KEYPAIR_PCT 122624
927927
#define MLD_TOTAL_ALLOC_87_PK_FROM_SK 112832
928-
#define MLD_TOTAL_ALLOC_87_SIGN 123584
928+
#define MLD_TOTAL_ALLOC_87_SIGN 115392
929929
#define MLD_TOTAL_ALLOC_87_VERIFY 99552
930930
#else /* MLD_API_LEGACY_CONFIG || !MLD_CONFIG_REDUCE_RAM */
931931
#define MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT 28960
@@ -936,12 +936,12 @@ int MLD_API_NAMESPACE(pk_from_sk)(
936936
#define MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT 40224
937937
#define MLD_TOTAL_ALLOC_65_KEYPAIR_PCT 40224
938938
#define MLD_TOTAL_ALLOC_65_PK_FROM_SK 46304
939-
#define MLD_TOTAL_ALLOC_65_SIGN 27456
939+
#define MLD_TOTAL_ALLOC_65_SIGN 26432
940940
#define MLD_TOTAL_ALLOC_65_VERIFY 30720
941941
#define MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT 54560
942942
#define MLD_TOTAL_ALLOC_87_KEYPAIR_PCT 54560
943943
#define MLD_TOTAL_ALLOC_87_PK_FROM_SK 62688
944-
#define MLD_TOTAL_ALLOC_87_SIGN 35648
944+
#define MLD_TOTAL_ALLOC_87_SIGN 34624
945945
#define MLD_TOTAL_ALLOC_87_VERIFY 41216
946946
#endif /* !(MLD_API_LEGACY_CONFIG || !MLD_CONFIG_REDUCE_RAM) */
947947
/* check-magic: on */

mldsa/mldsa_native_asm.S

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,8 @@
262262
/* mldsa/src/packing.h */
263263
#undef MLD_PACKING_H
264264
#undef mld_pack_pk
265-
#undef mld_pack_sig_c_h
265+
#undef mld_pack_sig_c
266+
#undef mld_pack_sig_h_poly
266267
#undef mld_pack_sig_z
267268
#undef mld_pack_sk
268269
#undef mld_unpack_pk
@@ -324,7 +325,6 @@
324325
#undef mld_polyveck_chknorm
325326
#undef mld_polyveck_decompose
326327
#undef mld_polyveck_invntt_tomont
327-
#undef mld_polyveck_make_hint
328328
#undef mld_polyveck_ntt
329329
#undef mld_polyveck_pack_eta
330330
#undef mld_polyveck_pack_t0

mldsa/src/packing.c

Lines changed: 31 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -100,75 +100,51 @@ void mld_unpack_sk(uint8_t rho[MLDSA_SEEDBYTES], uint8_t tr[MLDSA_TRBYTES],
100100
}
101101

102102
MLD_INTERNAL_API
103-
void mld_pack_sig_c_h(uint8_t sig[MLDSA_CRYPTO_BYTES],
104-
const uint8_t c[MLDSA_CTILDEBYTES], const mld_polyveck *h,
105-
const unsigned int number_of_hints)
103+
void mld_pack_sig_c(uint8_t sig[MLDSA_CRYPTO_BYTES],
104+
const uint8_t c[MLDSA_CTILDEBYTES])
106105
{
107-
unsigned int i, j, k;
108-
109106
mld_memcpy(sig, c, MLDSA_CTILDEBYTES);
110-
sig += MLDSA_CTILDEBYTES;
111-
112-
/* skip z component - packed via mld_pack_sig_z */
113-
sig += MLDSA_L * MLDSA_POLYZ_PACKEDBYTES;
107+
}
114108

115-
/* Encode hints h */
109+
MLD_INTERNAL_API
110+
void mld_pack_sig_h_poly(uint8_t sig[MLDSA_CRYPTO_BYTES], const mld_poly *h,
111+
unsigned int k, unsigned int n)
112+
{
113+
unsigned int j;
116114

117-
/* The final section of sig[] is MLDSA_POLYVECH_PACKEDBYTES long, where
118-
* MLDSA_POLYVECH_PACKEDBYTES = MLDSA_OMEGA + MLDSA_K
115+
/* The hint section of sig[] is MLDSA_POLYVECH_PACKEDBYTES long, where
116+
* MLDSA_POLYVECH_PACKEDBYTES = MLDSA_OMEGA + MLDSA_K.
119117
*
120118
* The first OMEGA bytes record the index numbers of the coefficients
121-
* that are not equal to 0
119+
* that are not equal to 0.
122120
*
123121
* The final K bytes record a running tally of the number of hints
124-
* coming from each of the K polynomials in h.
125-
*
126-
* The pre-condition tells us that number_of_hints <= OMEGA, so some
127-
* bytes may not be written, so we initialize all of them to zero
128-
* to start.
129-
*/
130-
mld_memset(sig, 0, MLDSA_POLYVECH_PACKEDBYTES);
131-
132-
k = 0;
133-
/* For each polynomial in h... */
134-
for (i = 0; i < MLDSA_K; ++i)
122+
* coming from each of the K polynomials in h. */
123+
uint8_t *sig_h = sig + MLDSA_CTILDEBYTES + MLDSA_L * MLDSA_POLYZ_PACKEDBYTES;
124+
125+
/* For each coefficient in this polynomial, record it as a hint */
126+
/* if its value is not zero. */
127+
for (j = 0; j < MLDSA_N; j++)
135128
__loop__(
136-
assigns(i, j, k, memory_slice(sig, MLDSA_POLYVECH_PACKEDBYTES))
137-
invariant(i <= MLDSA_K)
138-
invariant(k <= number_of_hints)
139-
invariant(number_of_hints <= MLDSA_OMEGA)
140-
decreases(MLDSA_K - i)
129+
assigns(j, n, memory_slice(sig_h, MLDSA_POLYVECH_PACKEDBYTES))
130+
invariant(j <= MLDSA_N)
131+
invariant(n <= MLDSA_OMEGA)
132+
decreases(MLDSA_N - j)
141133
)
142134
{
143-
/* For each coefficient in that polynomial, record it as as hint */
144-
/* if its value is not zero */
145-
for (j = 0; j < MLDSA_N; ++j)
146-
__loop__(
147-
assigns(j, k, memory_slice(sig, MLDSA_POLYVECH_PACKEDBYTES))
148-
invariant(i <= MLDSA_K)
149-
invariant(j <= MLDSA_N)
150-
invariant(k <= number_of_hints)
151-
invariant(number_of_hints <= MLDSA_OMEGA)
152-
decreases(MLDSA_N - j)
153-
)
135+
/* The reference implementation implicitly relies on the total */
136+
/* number of hints being less than OMEGA, assuming h is valid. */
137+
/* In mldsa-native, we check this explicitly to ease proof of */
138+
/* type safety. */
139+
if (h->coeffs[j] != 0 && n < MLDSA_OMEGA)
154140
{
155-
/* The reference implementation implicitly relies on the total */
156-
/* number of hints being less than OMEGA, assuming h is valid. */
157-
/* In mldsa-native, we check this explicitly to ease proof of */
158-
/* type safety. */
159-
if (h->vec[i].coeffs[j] != 0 && k < number_of_hints)
160-
{
161-
/* The enclosing if condition AND the loop invariant infer */
162-
/* that k < MLDSA_OMEGA, so writing to sig[k] is safe and k */
163-
/* can be incremented. */
164-
sig[k++] = (uint8_t)j;
165-
}
141+
sig_h[n] = (uint8_t)j;
142+
n++;
166143
}
167-
/* Having recorded all the hints for this polynomial, also */
168-
/* record the running tally into the correct "slot" for that */
169-
/* coefficient in the final K bytes */
170-
sig[MLDSA_OMEGA + i] = (uint8_t)k;
171144
}
145+
/* Record the running tally into the correct slot for this */
146+
/* polynomial in the final K bytes. */
147+
sig_h[MLDSA_OMEGA + k] = (uint8_t)n;
172148
}
173149

174150
MLD_INTERNAL_API

mldsa/src/packing.h

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -69,35 +69,46 @@ __contract__(
6969
);
7070

7171

72-
#define mld_pack_sig_c_h MLD_NAMESPACE_KL(pack_sig_c_h)
72+
#define mld_pack_sig_c MLD_NAMESPACE_KL(pack_sig_c)
7373
/*************************************************
74-
* Name: mld_pack_sig_c_h
74+
* Name: mld_pack_sig_c
7575
*
76-
* Description: Bit-pack c and h component of sig = (c, z, h).
77-
* The z component is packed separately using mld_pack_sig_z.
76+
* Description: Bit-pack challenge c into sig = (c, z, h).
7877
*
7978
* Arguments: - uint8_t sig[]: output byte array
80-
* - const uint8_t *c: pointer to challenge hash length
81-
* MLDSA_SEEDBYTES
82-
* - const mld_polyveck *h: pointer to hint vector h
83-
* - const unsigned int number_of_hints: total
84-
* hints in *h
85-
*
86-
* Note that the number_of_hints argument is not present
87-
* in the reference implementation. It is added here to ease
88-
* proof of type safety.
79+
* - const uint8_t *c: pointer to challenge hash
8980
**************************************************/
9081
MLD_INTERNAL_API
91-
void mld_pack_sig_c_h(uint8_t sig[MLDSA_CRYPTO_BYTES],
92-
const uint8_t c[MLDSA_CTILDEBYTES], const mld_polyveck *h,
93-
const unsigned int number_of_hints)
82+
void mld_pack_sig_c(uint8_t sig[MLDSA_CRYPTO_BYTES],
83+
const uint8_t c[MLDSA_CTILDEBYTES])
9484
__contract__(
9585
requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES))
9686
requires(memory_no_alias(c, MLDSA_CTILDEBYTES))
97-
requires(memory_no_alias(h, sizeof(mld_polyveck)))
98-
requires(forall(k1, 0, MLDSA_K,
99-
array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2)))
100-
requires(number_of_hints <= MLDSA_OMEGA)
87+
assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES))
88+
);
89+
90+
#define mld_pack_sig_h_poly MLD_NAMESPACE_KL(pack_sig_h_poly)
91+
/*************************************************
92+
* Name: mld_pack_sig_h_poly
93+
*
94+
* Description: Pack hints for one polynomial into the hint section of sig.
95+
* Must be called once per polynomial in order k = 0, ..., K-1.
96+
* The hint section of sig must be zeroed before the first call.
97+
*
98+
* Arguments: - uint8_t sig[]: byte array containing signature
99+
* - const mld_poly *h: pointer to hint polynomial (0/1 coeffs)
100+
* - unsigned int k: index of polynomial in vector (0..K-1)
101+
* - unsigned int n: total number of hints written so far
102+
**************************************************/
103+
MLD_INTERNAL_API
104+
void mld_pack_sig_h_poly(uint8_t sig[MLDSA_CRYPTO_BYTES], const mld_poly *h,
105+
unsigned int k, unsigned int n)
106+
__contract__(
107+
requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES))
108+
requires(memory_no_alias(h, sizeof(mld_poly)))
109+
requires(k < MLDSA_K)
110+
requires(n <= MLDSA_OMEGA)
111+
requires(array_bound(h->coeffs, 0, MLDSA_N, 0, 2))
101112
assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES))
102113
);
103114

@@ -107,7 +118,7 @@ __contract__(
107118
*
108119
* Description: Bit-pack single polynomial of z component of sig = (c, z, h).
109120
* The c and h components are packed separately using
110-
* mld_pack_sig_c_h.
121+
* mld_pack_sig_c and mld_pack_sig_h_poly.
111122
*
112123
* Arguments: - uint8_t sig[]: output byte array
113124
* - const mld_poly *zi: pointer to a single polynomial in z

mldsa/src/polyvec.c

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -696,28 +696,6 @@ void mld_polyveck_decompose(mld_polyveck *v1, mld_polyveck *v0)
696696
mld_assert_abs_bound_2d(v0->vec, MLDSA_K, MLDSA_N, MLDSA_GAMMA2 + 1);
697697
}
698698

699-
MLD_INTERNAL_API
700-
unsigned int mld_polyveck_make_hint(mld_polyveck *h, const mld_polyveck *v0,
701-
const mld_polyveck *v1)
702-
{
703-
unsigned int i, s = 0;
704-
705-
for (i = 0; i < MLDSA_K; ++i)
706-
__loop__(
707-
assigns(i, s, memory_slice(h, sizeof(mld_polyveck)))
708-
invariant(i <= MLDSA_K)
709-
invariant(s <= i * MLDSA_N)
710-
invariant(forall(k1, 0, i, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2)))
711-
decreases(MLDSA_K - i)
712-
)
713-
{
714-
s += mld_poly_make_hint(&h->vec[i], &v0->vec[i], &v1->vec[i]);
715-
}
716-
717-
mld_assert_bound_2d(h->vec, MLDSA_K, MLDSA_N, 0, 2);
718-
return s;
719-
}
720-
721699
MLD_INTERNAL_API
722700
void mld_polyveck_use_hint(mld_polyveck *w, const mld_polyveck *u,
723701
const mld_polyveck *h)

mldsa/src/polyvec.h

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -413,31 +413,6 @@ __contract__(
413413
array_abs_bound(v0->vec[k2].coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1)))
414414
);
415415

416-
#define mld_polyveck_make_hint MLD_NAMESPACE_KL(polyveck_make_hint)
417-
/*************************************************
418-
* Name: mld_polyveck_make_hint
419-
*
420-
* Description: Compute hint vector.
421-
*
422-
* Arguments: - mld_polyveck *h: pointer to output vector
423-
* - const mld_polyveck *v0: pointer to low part of input vector
424-
* - const mld_polyveck *v1: pointer to high part of input vector
425-
*
426-
* Returns number of 1 bits.
427-
**************************************************/
428-
MLD_INTERNAL_API
429-
MLD_MUST_CHECK_RETURN_VALUE
430-
unsigned int mld_polyveck_make_hint(mld_polyveck *h, const mld_polyveck *v0,
431-
const mld_polyveck *v1)
432-
__contract__(
433-
requires(memory_no_alias(h, sizeof(mld_polyveck)))
434-
requires(memory_no_alias(v0, sizeof(mld_polyveck)))
435-
requires(memory_no_alias(v1, sizeof(mld_polyveck)))
436-
assigns(memory_slice(h, sizeof(mld_polyveck)))
437-
ensures(return_value <= MLDSA_N * MLDSA_K)
438-
ensures(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2)))
439-
);
440-
441416
#define mld_polyveck_use_hint MLD_NAMESPACE_KL(polyveck_use_hint)
442417
/*************************************************
443418
* Name: mld_polyveck_use_hint

0 commit comments

Comments
 (0)