Skip to content

Commit e8dabd1

Browse files
committed
sign: Consolidate make_hint and pack_sig_h_poly
Replace mld_poly_make_hint + mld_pack_sig_h_poly with a single mld_make_pack_sig_h_poly that takes (a0, a1) directly, computes hint bits via mld_make_hint, writes hint indices into sig in one pass, and returns the updated running tally. The function returns MLD_ERR_FAIL if the number of hints would exceed MLDSA_OMEGA. This removes the duplicated hint counting (previously make_hint returned the count and pack iterated the hint poly again without re-validating) and drops the temporary scratch hint polynomial from the sign.c hint loop. Signed-off-by: Matthias J. Kannwischer <matthias@zerorisc.com>
1 parent 9c62ded commit e8dabd1

File tree

12 files changed

+55
-157
lines changed

12 files changed

+55
-157
lines changed

mldsa/mldsa_native.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,9 +256,9 @@
256256
#undef mld_memset
257257
/* mldsa/src/packing.h */
258258
#undef MLD_PACKING_H
259+
#undef mld_make_pack_sig_h_poly
259260
#undef mld_pack_pk
260261
#undef mld_pack_sig_c
261-
#undef mld_pack_sig_h_poly
262262
#undef mld_pack_sig_z
263263
#undef mld_pack_sk
264264
#undef mld_unpack_pk
@@ -297,7 +297,6 @@
297297
#undef MLD_POLY_KL_H
298298
#undef mld_poly_challenge
299299
#undef mld_poly_decompose
300-
#undef mld_poly_make_hint
301300
#undef mld_poly_uniform_eta
302301
#undef mld_poly_uniform_eta_4x
303302
#undef mld_poly_uniform_gamma1

mldsa/mldsa_native_asm.S

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -261,9 +261,9 @@
261261
#undef mld_memset
262262
/* mldsa/src/packing.h */
263263
#undef MLD_PACKING_H
264+
#undef mld_make_pack_sig_h_poly
264265
#undef mld_pack_pk
265266
#undef mld_pack_sig_c
266-
#undef mld_pack_sig_h_poly
267267
#undef mld_pack_sig_z
268268
#undef mld_pack_sk
269269
#undef mld_unpack_pk
@@ -302,7 +302,6 @@
302302
#undef MLD_POLY_KL_H
303303
#undef mld_poly_challenge
304304
#undef mld_poly_decompose
305-
#undef mld_poly_make_hint
306305
#undef mld_poly_uniform_eta
307306
#undef mld_poly_uniform_eta_4x
308307
#undef mld_poly_uniform_gamma1

mldsa/src/packing.c

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "packing.h"
99
#include "poly.h"
1010
#include "polyvec.h"
11+
#include "rounding.h"
1112

1213
/* Parameter set namespacing
1314
* This is to facilitate building multiple instances
@@ -107,8 +108,9 @@ void mld_pack_sig_c(uint8_t sig[MLDSA_CRYPTO_BYTES],
107108
}
108109

109110
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)
111+
int mld_make_pack_sig_h_poly(uint8_t sig[MLDSA_CRYPTO_BYTES],
112+
const mld_poly *a0, const mld_poly *a1,
113+
unsigned int k, unsigned int n)
112114
{
113115
unsigned int j;
114116

@@ -119,11 +121,16 @@ void mld_pack_sig_h_poly(uint8_t sig[MLDSA_CRYPTO_BYTES], const mld_poly *h,
119121
* that are not equal to 0.
120122
*
121123
* The final K bytes record a running tally of the number of hints
122-
* coming from each of the K polynomials in h. */
124+
* coming from each of the K polynomials. */
123125
uint8_t *sig_h = sig + MLDSA_CTILDEBYTES + MLDSA_L * MLDSA_POLYZ_PACKEDBYTES;
124126

125-
/* For each coefficient in this polynomial, record it as a hint */
126-
/* if its value is not zero. */
127+
/* For each coefficient in this polynomial, compute its hint bit and, if
128+
* non-zero, record the index in the hint section of sig. If recording the
129+
* hint would overflow the OMEGA-sized index array, abort early and return
130+
* MLD_ERR_FAIL. The caller is expected to reject the signature in that case.
131+
*
132+
* Constant time: At this point a0/a1 are public (see comment in sign.c
133+
* before the call), so a data-dependent early return is fine. */
127134
for (j = 0; j < MLDSA_N; j++)
128135
__loop__(
129136
assigns(j, n, memory_slice(sig_h, MLDSA_POLYVECH_PACKEDBYTES))
@@ -132,19 +139,21 @@ void mld_pack_sig_h_poly(uint8_t sig[MLDSA_CRYPTO_BYTES], const mld_poly *h,
132139
decreases(MLDSA_N - j)
133140
)
134141
{
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)
142+
const unsigned int hint_bit = mld_make_hint(a0->coeffs[j], a1->coeffs[j]);
143+
if (hint_bit)
140144
{
145+
if (n == MLDSA_OMEGA)
146+
{
147+
return MLD_ERR_FAIL;
148+
}
141149
sig_h[n] = (uint8_t)j;
142150
n++;
143151
}
144152
}
145153
/* Record the running tally into the correct slot for this */
146154
/* polynomial in the final K bytes. */
147155
sig_h[MLDSA_OMEGA + k] = (uint8_t)n;
156+
return (int)n;
148157
}
149158

150159
MLD_INTERNAL_API

mldsa/src/packing.h

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -87,29 +87,41 @@ __contract__(
8787
assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES))
8888
);
8989

90-
#define mld_pack_sig_h_poly MLD_NAMESPACE_KL(pack_sig_h_poly)
90+
#define mld_make_pack_sig_h_poly MLD_NAMESPACE_KL(make_pack_sig_h_poly)
9191
/*************************************************
92-
* Name: mld_pack_sig_h_poly
92+
* Name: mld_make_pack_sig_h_poly
9393
*
94-
* Description: Pack hints for one polynomial into the hint section of sig.
94+
* Description: Compute hints for one polynomial of (w0, w1) and pack them
95+
* into the hint section of sig.
9596
* Must be called once per polynomial in order k = 0, ..., K-1.
9697
* The hint section of sig must be zeroed before the first call.
9798
*
9899
* Arguments: - uint8_t sig[]: byte array containing signature
99-
* - const mld_poly *h: pointer to hint polynomial (0/1 coeffs)
100+
* - const mld_poly *a0: pointer to low part of input polynomial
101+
* - const mld_poly *a1: pointer to high part of input polynomial
100102
* - unsigned int k: index of polynomial in vector (0..K-1)
101103
* - unsigned int n: total number of hints written so far
104+
*
105+
* Returns: - the updated running tally of hints (non-negative, at most
106+
* MLDSA_OMEGA) on success;
107+
* - MLD_ERR_FAIL if writing all hints for this polynomial
108+
* would exceed MLDSA_OMEGA. In this case the caller must
109+
* reject the signature.
102110
**************************************************/
103111
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)
112+
MLD_MUST_CHECK_RETURN_VALUE
113+
int mld_make_pack_sig_h_poly(uint8_t sig[MLDSA_CRYPTO_BYTES],
114+
const mld_poly *a0, const mld_poly *a1,
115+
unsigned int k, unsigned int n)
106116
__contract__(
107117
requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES))
108-
requires(memory_no_alias(h, sizeof(mld_poly)))
118+
requires(memory_no_alias(a0, sizeof(mld_poly)))
119+
requires(memory_no_alias(a1, sizeof(mld_poly)))
109120
requires(k < MLDSA_K)
110121
requires(n <= MLDSA_OMEGA)
111-
requires(array_bound(h->coeffs, 0, MLDSA_N, 0, 2))
112122
assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES))
123+
ensures(return_value == MLD_ERR_FAIL ||
124+
(return_value >= 0 && return_value <= MLDSA_OMEGA))
113125
);
114126

115127
#define mld_pack_sig_z MLD_NAMESPACE_KL(pack_sig_z)
@@ -118,7 +130,7 @@ __contract__(
118130
*
119131
* Description: Bit-pack single polynomial of z component of sig = (c, z, h).
120132
* The c and h components are packed separately using
121-
* mld_pack_sig_c and mld_pack_sig_h_poly.
133+
* mld_pack_sig_c and mld_make_pack_sig_h_poly.
122134
*
123135
* Arguments: - uint8_t sig[]: output byte array
124136
* - const mld_poly *zi: pointer to a single polynomial in z

mldsa/src/poly_kl.c

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -100,30 +100,6 @@ void mld_poly_decompose(mld_poly *a1, mld_poly *a0)
100100
mld_poly_decompose_c(a1, a0);
101101
}
102102

103-
MLD_INTERNAL_API
104-
unsigned int mld_poly_make_hint(mld_poly *h, const mld_poly *a0,
105-
const mld_poly *a1)
106-
{
107-
unsigned int i, s = 0;
108-
109-
for (i = 0; i < MLDSA_N; ++i)
110-
__loop__(
111-
invariant(i <= MLDSA_N)
112-
invariant(s <= i)
113-
invariant(array_bound(h->coeffs, 0, i, 0, 2))
114-
decreases(MLDSA_N - i)
115-
)
116-
{
117-
const unsigned int hint_bit = mld_make_hint(a0->coeffs[i], a1->coeffs[i]);
118-
h->coeffs[i] = (int32_t)hint_bit;
119-
s += hint_bit;
120-
}
121-
122-
mld_assert(s <= MLDSA_N);
123-
mld_assert_bound(h->coeffs, MLDSA_N, 0, 2);
124-
return s;
125-
}
126-
127103
MLD_STATIC_TESTABLE void mld_poly_use_hint_c(mld_poly *b, const mld_poly *a,
128104
const mld_poly *h)
129105
__contract__(

mldsa/src/poly_kl.h

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -43,33 +43,6 @@ __contract__(
4343
);
4444

4545

46-
#define mld_poly_make_hint MLD_NAMESPACE_KL(poly_make_hint)
47-
/*************************************************
48-
* Name: mld_poly_make_hint
49-
*
50-
* Description: Compute hint polynomial. The coefficients of which indicate
51-
* whether the low bits of the corresponding coefficient of
52-
* the input polynomial overflow into the high bits.
53-
*
54-
* Arguments: - mld_poly *h: pointer to output hint polynomial
55-
* - const mld_poly *a0: pointer to low part of input polynomial
56-
* - const mld_poly *a1: pointer to high part of input polynomial
57-
*
58-
* Returns number of 1 bits.
59-
**************************************************/
60-
MLD_INTERNAL_API
61-
MLD_MUST_CHECK_RETURN_VALUE
62-
unsigned int mld_poly_make_hint(mld_poly *h, const mld_poly *a0,
63-
const mld_poly *a1)
64-
__contract__(
65-
requires(memory_no_alias(h, sizeof(mld_poly)))
66-
requires(memory_no_alias(a0, sizeof(mld_poly)))
67-
requires(memory_no_alias(a1, sizeof(mld_poly)))
68-
assigns(memory_slice(h, sizeof(mld_poly)))
69-
ensures(return_value <= MLDSA_N)
70-
ensures(array_bound(h->coeffs, 0, MLDSA_N, 0, 2))
71-
);
72-
7346
#define mld_poly_use_hint MLD_NAMESPACE_KL(poly_use_hint)
7447
/*************************************************
7548
* Name: mld_poly_use_hint

mldsa/src/sign.c

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -728,22 +728,18 @@ __contract__(
728728
n = 0;
729729
for (k = 0; k < MLDSA_K; k++)
730730
__loop__(
731-
assigns(k, n,
732-
memory_slice(z, sizeof(mld_poly)),
733-
memory_slice(sig, MLDSA_CRYPTO_BYTES))
731+
assigns(k, n, ret, memory_slice(sig, MLDSA_CRYPTO_BYTES))
734732
invariant(k <= MLDSA_K)
735733
invariant(n <= MLDSA_OMEGA)
736734
decreases(MLDSA_K - k)
737735
)
738736
{
739-
unsigned int hints = mld_poly_make_hint(z, &w0->vec[k], &w1->vec[k]);
740-
if (n + hints > MLDSA_OMEGA)
737+
ret = mld_make_pack_sig_h_poly(sig, &w0->vec[k], &w1->vec[k], k, n);
738+
if (ret == MLD_ERR_FAIL)
741739
{
742-
ret = MLD_ERR_FAIL; /* reject */
743740
goto cleanup;
744741
}
745-
mld_pack_sig_h_poly(sig, z, k, n);
746-
n += hints;
742+
n = (unsigned int)ret;
747743
}
748744

749745
/* Constant time: At this point it is clear that the signature is valid - it

proofs/cbmc/attempt_signature_generation/Makefile

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,8 @@ USE_FUNCTION_CONTRACTS+=mld_poly_sub
3737
USE_FUNCTION_CONTRACTS+=mld_poly_reduce
3838
USE_FUNCTION_CONTRACTS+=mld_poly_chknorm
3939
USE_FUNCTION_CONTRACTS+=mld_poly_add
40-
USE_FUNCTION_CONTRACTS+=mld_poly_make_hint
4140
USE_FUNCTION_CONTRACTS+=mld_pack_sig_c
42-
USE_FUNCTION_CONTRACTS+=mld_pack_sig_h_poly
41+
USE_FUNCTION_CONTRACTS+=mld_make_pack_sig_h_poly
4342
USE_FUNCTION_CONTRACTS+=mld_zeroize
4443

4544
APPLY_LOOP_CONTRACTS=on
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
include ../Makefile_params.common
55

66
HARNESS_ENTRY = harness
7-
HARNESS_FILE = pack_sig_h_poly_harness
7+
HARNESS_FILE = make_pack_sig_h_poly_harness
88

99
# This should be a unique identifier for this proof, and will appear on the
1010
# Litani dashboard. It can be human-readable and contain spaces if you wish.
11-
PROOF_UID = pack_sig_h_poly
11+
PROOF_UID = make_pack_sig_h_poly
1212

1313
DEFINES +=
1414
INCLUDES +=
@@ -19,8 +19,8 @@ UNWINDSET +=
1919
PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
2020
PROJECT_SOURCES += $(SRCDIR)/mldsa/src/packing.c
2121

22-
CHECK_FUNCTION_CONTRACTS=mld_pack_sig_h_poly
23-
USE_FUNCTION_CONTRACTS=
22+
CHECK_FUNCTION_CONTRACTS=mld_make_pack_sig_h_poly
23+
USE_FUNCTION_CONTRACTS=mld_make_hint
2424
APPLY_LOOP_CONTRACTS=on
2525
USE_DYNAMIC_FRAMES=1
2626

@@ -29,7 +29,7 @@ EXTERNAL_SAT_SOLVER=
2929
CBMCFLAGS=--external-smt2-solver $(PROOF_ROOT)/lib/z3_no_bv_extract --z3
3030
CBMCFLAGS+=--slice-formula
3131

32-
FUNCTION_NAME = pack_sig_h_poly
32+
FUNCTION_NAME = make_pack_sig_h_poly
3333

3434
# If this proof is found to consume huge amounts of RAM, you can set the
3535
# EXPENSIVE variable. With new enough versions of the proof tools, this will

proofs/cbmc/pack_sig_h_poly/pack_sig_h_poly_harness.c renamed to proofs/cbmc/make_pack_sig_h_poly/make_pack_sig_h_poly_harness.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
void harness(void)
77
{
88
uint8_t *sig;
9-
mld_poly *h;
9+
mld_poly *a0, *a1;
1010
unsigned int k, n;
11-
mld_pack_sig_h_poly(sig, h, k, n);
11+
int r;
12+
r = mld_make_pack_sig_h_poly(sig, a0, a1, k, n);
1213
}

0 commit comments

Comments
 (0)