Skip to content

Commit 89b07cf

Browse files
committed
WIP: sign stack usage: compute z incrementally
Hoisted out from #791 Signed-off-by: Matthias J. Kannwischer <matthias@kannwischer.eu>
1 parent e9954fb commit 89b07cf

File tree

8 files changed

+162
-50
lines changed

8 files changed

+162
-50
lines changed

mldsa/src/packing.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,15 +100,15 @@ void mld_unpack_sk(uint8_t rho[MLDSA_SEEDBYTES], uint8_t tr[MLDSA_TRBYTES],
100100

101101
MLD_INTERNAL_API
102102
void mld_pack_sig(uint8_t sig[MLDSA_CRYPTO_BYTES],
103-
const uint8_t c[MLDSA_CTILDEBYTES], const mld_polyvecl *z,
103+
const uint8_t c[MLDSA_CTILDEBYTES],
104104
const mld_polyveck *h, const unsigned int number_of_hints)
105105
{
106106
unsigned int i, j, k;
107107

108108
mld_memcpy(sig, c, MLDSA_CTILDEBYTES);
109109
sig += MLDSA_CTILDEBYTES;
110110

111-
mld_polyvecl_pack_z(sig, z);
111+
/* skip z component - packed via mld_pack_sig_z */
112112
sig += MLDSA_L * MLDSA_POLYZ_PACKEDBYTES;
113113

114114
/* Encode hints h */
@@ -168,6 +168,15 @@ void mld_pack_sig(uint8_t sig[MLDSA_CRYPTO_BYTES],
168168
}
169169
}
170170

171+
MLD_INTERNAL_API
172+
void mld_pack_sig_z(uint8_t sig[MLDSA_CRYPTO_BYTES], const mld_poly *zi,
173+
unsigned i)
174+
{
175+
sig += MLDSA_CTILDEBYTES;
176+
sig += i * MLDSA_POLYZ_PACKEDBYTES;
177+
mld_polyz_pack(sig, zi);
178+
}
179+
171180
/*************************************************
172181
* Name: mld_unpack_hints
173182
*

mldsa/src/packing.h

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,12 @@ __contract__(
7373
/*************************************************
7474
* Name: mld_pack_sig
7575
*
76-
* Description: Bit-pack signature sig = (c, z, h).
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.
7778
*
7879
* Arguments: - uint8_t sig[]: output byte array
7980
* - const uint8_t *c: pointer to challenge hash length
8081
* MLDSA_SEEDBYTES
81-
* - const mld_polyvecl *z: pointer to vector z
8282
* - const mld_polyveck *h: pointer to hint vector h
8383
* - const unsigned int number_of_hints: total
8484
* hints in *h
@@ -89,21 +89,41 @@ __contract__(
8989
**************************************************/
9090
MLD_INTERNAL_API
9191
void mld_pack_sig(uint8_t sig[MLDSA_CRYPTO_BYTES],
92-
const uint8_t c[MLDSA_CTILDEBYTES], const mld_polyvecl *z,
92+
const uint8_t c[MLDSA_CTILDEBYTES],
9393
const mld_polyveck *h, const unsigned int number_of_hints)
9494
__contract__(
9595
requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES))
9696
requires(memory_no_alias(c, MLDSA_CTILDEBYTES))
97-
requires(memory_no_alias(z, sizeof(mld_polyvecl)))
9897
requires(memory_no_alias(h, sizeof(mld_polyveck)))
99-
requires(forall(k0, 0, MLDSA_L,
100-
array_bound(z->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)))
10198
requires(forall(k1, 0, MLDSA_K,
10299
array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2)))
103100
requires(number_of_hints <= MLDSA_OMEGA)
104101
assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES))
105102
);
106103

104+
#define mld_pack_sig_z MLD_NAMESPACE_KL(pack_sig_z)
105+
/*************************************************
106+
* Name: mld_pack_sig_z
107+
*
108+
* Description: Bit-pack single polynomial of z component of sig = (c, z, h).
109+
* The c and h components are packed separately using mld_pack_sig.
110+
*
111+
* Arguments: - uint8_t sig[]: output byte array
112+
* - const mld_poly *zi: pointer to a single polynomial in z
113+
* - const unsigned int i: index of zi in vector z
114+
*
115+
**************************************************/
116+
MLD_INTERNAL_API
117+
void mld_pack_sig_z(uint8_t sig[MLDSA_CRYPTO_BYTES], const mld_poly *zi,
118+
unsigned i)
119+
__contract__(
120+
requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES))
121+
requires(memory_no_alias(zi, sizeof(mld_poly)))
122+
requires(i < MLDSA_L)
123+
requires(array_bound(zi->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))
124+
assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES))
125+
);
126+
107127
#define mld_unpack_pk MLD_NAMESPACE_KL(unpack_pk)
108128
/*************************************************
109129
* Name: mld_unpack_pk

mldsa/src/sign.c

Lines changed: 50 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -486,7 +486,7 @@ __contract__(
486486
return_value == MLD_ERR_OUT_OF_MEMORY)
487487
)
488488
{
489-
unsigned int n;
489+
unsigned int n, i;
490490
uint32_t z_invalid, w0_invalid, h_invalid;
491491
int ret;
492492
/* TODO: Remove the following workaround for
@@ -495,34 +495,45 @@ __contract__(
495495
{
496496
mld_polyvecl y;
497497
mld_polyveck h;
498-
}
499-
yh_u;
498+
} yh_u;
500499
mld_polyvecl *y;
501500
mld_polyveck *h;
502501

502+
/* TODO: Remove the following workaround for
503+
* https://github.com/diffblue/cbmc/issues/8813 */
504+
typedef MLK_UNION_OR_STRUCT
505+
{
506+
mld_polyveck w1;
507+
mld_polyvecl tmp;
508+
} w1tmp_u;
509+
mld_polyveck *w1;
510+
mld_polyvecl *tmp;
511+
503512
MLD_ALLOC(challenge_bytes, uint8_t, MLDSA_CTILDEBYTES);
504513
MLD_ALLOC(yh, yh_u, 1);
505-
MLD_ALLOC(z, mld_polyvecl, 1);
506-
MLD_ALLOC(w1, mld_polyveck, 1);
514+
MLD_ALLOC(z, mld_poly, 1);
515+
MLD_ALLOC(w1tmp, w1tmp_u, 1);
507516
MLD_ALLOC(w0, mld_polyveck, 1);
508517
MLD_ALLOC(cp, mld_poly, 1);
509518

510-
if (challenge_bytes == NULL || yh == NULL || z == NULL || w1 == NULL ||
519+
if (challenge_bytes == NULL || yh == NULL || z == NULL || w1tmp == NULL ||
511520
w0 == NULL || cp == NULL)
512521
{
513522
ret = MLD_ERR_OUT_OF_MEMORY;
514523
goto cleanup;
515524
}
516525
y = &yh->y;
517526
h = &yh->h;
527+
w1 = &w1tmp->w1;
528+
tmp = &w1tmp->tmp;
518529

519530
/* Sample intermediate vector y */
520531
mld_polyvecl_uniform_gamma1(y, rhoprime, nonce);
521532

522533
/* Matrix-vector multiplication */
523-
*z = *y;
524-
mld_polyvecl_ntt(z);
525-
mld_polyvec_matrix_pointwise_montgomery(w0, mat, z);
534+
*tmp = *y;
535+
mld_polyvecl_ntt(tmp);
536+
mld_polyvec_matrix_pointwise_montgomery(w0, mat, tmp);
526537
mld_polyveck_reduce(w0);
527538
mld_polyveck_invntt_tomont(w0);
528539

@@ -541,31 +552,36 @@ __contract__(
541552
mld_poly_challenge(cp, challenge_bytes);
542553
mld_poly_ntt(cp);
543554

555+
ret = 0;
544556
/* Compute z, reject if it reveals secret */
545-
mld_polyvecl_pointwise_poly_montgomery(z, cp, s1);
546-
mld_polyvecl_invntt_tomont(z);
547-
mld_polyvecl_add(z, y);
548-
mld_polyvecl_reduce(z);
549-
550-
z_invalid = mld_polyvecl_chknorm(z, MLDSA_GAMMA1 - MLDSA_BETA);
551-
/* Constant time: It is fine (and prohibitively expensive to avoid)
552-
* leaking the result of the norm check. In case of rejection it
553-
* would even be okay to leak which coefficient led to rejection
554-
* as the candidate signature will be discarded anyway.
555-
* See Section 5.5 of @[Round3_Spec]. */
556-
MLD_CT_TESTING_DECLASSIFY(&z_invalid, sizeof(uint32_t));
557-
if (z_invalid)
558-
{
559-
ret = MLD_ERR_FAIL; /* reject */
560-
goto cleanup;
557+
for (i = 0; i < MLDSA_L; i++)
558+
__loop__(
559+
invariant(i <= MLDSA_L))
560+
{
561+
mld_poly_pointwise_montgomery(z, cp, &s1->vec[i]);
562+
mld_poly_invntt_tomont(z);
563+
mld_poly_add(z, &y->vec[i]);
564+
mld_poly_reduce(z);
565+
566+
z_invalid = mld_poly_chknorm(z, MLDSA_GAMMA1 - MLDSA_BETA);
567+
/* Constant time: It is fine (and prohibitively expensive to avoid)
568+
* leaking the result of the norm check. In case of rejection it
569+
* would even be okay to leak which coefficient led to rejection
570+
* as the candidate signature will be discarded anyway.
571+
* See Section 5.5 of @[Round3_Spec]. */
572+
MLD_CT_TESTING_DECLASSIFY(&z_invalid, sizeof(uint32_t));
573+
if (z_invalid)
574+
{
575+
ret = MLD_ERR_FAIL; /* reject */
576+
goto cleanup;
577+
}
578+
/* If z is valid, then its coefficients are bounded by */
579+
/* MLDSA_GAMMA1 - MLDSA_BETA. This will be needed below */
580+
/* to prove the pre-condition of pack_sig_z() */
581+
mld_assert_abs_bound(z, MLDSA_N, (MLDSA_GAMMA1 - MLDSA_BETA));
582+
mld_pack_sig_z(sig, z, i);
561583
}
562584

563-
/* If z is valid, then its coefficients are bounded by */
564-
/* MLDSA_GAMMA1 - MLDSA_BETA. This will be needed below */
565-
/* to prove the pre-condition of pack_sig() */
566-
mld_assert_abs_bound_2d(z->vec, MLDSA_L, MLDSA_N,
567-
(MLDSA_GAMMA1 - MLDSA_BETA));
568-
569585
/* Check that subtracting cs2 does not change high bits of w and low bits
570586
* do not reveal secret information */
571587
mld_polyveck_pointwise_poly_montgomery(h, cp, s2);
@@ -619,17 +635,16 @@ __contract__(
619635
/* Constant time: At this point it is clear that the signature is valid - it
620636
* can, hence, be considered public. */
621637
MLD_CT_TESTING_DECLASSIFY(h, sizeof(*h));
622-
MLD_CT_TESTING_DECLASSIFY(z, sizeof(*z));
623-
mld_pack_sig(sig, challenge_bytes, z, h, n);
638+
mld_pack_sig(sig, challenge_bytes, h, n);
624639

625640
ret = 0; /* success */
626641

627642
cleanup:
628643
/* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */
629644
MLD_FREE(cp, mld_poly, 1);
630645
MLD_FREE(w0, mld_polyveck, 1);
631-
MLD_FREE(w1, mld_polyveck, 1);
632-
MLD_FREE(z, mld_polyvecl, 1);
646+
MLD_FREE(w1tmp, w1tmp_u, 1);
647+
MLD_FREE(z, mld_poly, 1);
633648
MLD_FREE(yh, yh_u, 1);
634649
MLD_FREE(challenge_bytes, uint8_t, MLDSA_CTILDEBYTES);
635650

proofs/cbmc/attempt_signature_generation/Makefile

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,18 @@ USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyvecl_uniform_gamma1 \
3131
mld_H \
3232
$(MLD_NAMESPACE)poly_challenge \
3333
$(MLD_NAMESPACE)poly_ntt \
34-
$(MLD_NAMESPACE)polyvecl_pointwise_poly_montgomery \
35-
$(MLD_NAMESPACE)polyvecl_invntt_tomont \
36-
$(MLD_NAMESPACE)polyvecl_add \
37-
$(MLD_NAMESPACE)polyvecl_reduce \
34+
$(MLD_NAMESPACE)poly_pointwise_montgomery \
35+
$(MLD_NAMESPACE)poly_invntt_tomont \
36+
$(MLD_NAMESPACE)poly_add \
37+
$(MLD_NAMESPACE)poly_reduce \
3838
$(MLD_NAMESPACE)polyvecl_chknorm \
3939
$(MLD_NAMESPACE)polyveck_pointwise_poly_montgomery \
4040
$(MLD_NAMESPACE)polyveck_sub \
4141
$(MLD_NAMESPACE)polyveck_reduce \
4242
$(MLD_NAMESPACE)polyveck_chknorm \
4343
$(MLD_NAMESPACE)polyveck_add \
4444
$(MLD_NAMESPACE)polyveck_make_hint \
45+
$(MLD_NAMESPACE)pack_sig_z \
4546
$(MLD_NAMESPACE)pack_sig
4647
USE_FUNCTION_CONTRACTS+=mld_zeroize
4748

proofs/cbmc/pack_sig/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
1919
PROJECT_SOURCES += $(SRCDIR)/mldsa/src/packing.c
2020

2121
CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)pack_sig
22-
USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyvecl_pack_z
22+
USE_FUNCTION_CONTRACTS=
2323
APPLY_LOOP_CONTRACTS=on
2424
USE_DYNAMIC_FRAMES=1
2525

proofs/cbmc/pack_sig/pack_sig_harness.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ void harness(void)
88
{
99
uint8_t *a, *b;
1010
mld_polyveck *h;
11-
mld_polyvecl *z;
1211
unsigned int nh;
13-
mld_pack_sig(a, b, z, h, nh);
12+
mld_pack_sig(a, b, h, nh);
1413
}

proofs/cbmc/pack_sig_z/Makefile

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Copyright (c) The mldsa-native project authors
2+
# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
3+
4+
include ../Makefile_params.common
5+
6+
HARNESS_ENTRY = harness
7+
HARNESS_FILE = pack_sig_z_harness
8+
9+
# This should be a unique identifier for this proof, and will appear on the
10+
# Litani dashboard. It can be human-readable and contain spaces if you wish.
11+
PROOF_UID = pack_sig_z
12+
13+
DEFINES +=
14+
INCLUDES +=
15+
16+
REMOVE_FUNCTION_BODY +=
17+
18+
PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
19+
PROJECT_SOURCES += $(SRCDIR)/mldsa/src/packing.c
20+
21+
CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)pack_sig_z
22+
USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)polyz_pack
23+
APPLY_LOOP_CONTRACTS=on
24+
USE_DYNAMIC_FRAMES=1
25+
26+
# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead
27+
EXTERNAL_SAT_SOLVER=
28+
CBMCFLAGS=--smt2
29+
CBMCFLAGS+=--slice-formula
30+
31+
FUNCTION_NAME = pack_sig_z
32+
33+
# If this proof is found to consume huge amounts of RAM, you can set the
34+
# EXPENSIVE variable. With new enough versions of the proof tools, this will
35+
# restrict the number of EXPENSIVE CBMC jobs running at once. See the
36+
# documentation in Makefile.common under the "Job Pools" heading for details.
37+
# EXPENSIVE = true
38+
39+
# This function is large enough to need...
40+
CBMC_OBJECT_BITS = 9
41+
42+
# If you require access to a file-local ("static") function or object to conduct
43+
# your proof, set the following (and do not include the original source file
44+
# ("mldsa/poly.c") in PROJECT_SOURCES).
45+
# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i
46+
# include ../Makefile.common
47+
# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/src/poly.c
48+
# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar
49+
# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz
50+
# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must
51+
# be set before including Makefile.common, but any use of variables on the
52+
# left-hand side requires those variables to be defined. Hence, _SOURCE,
53+
# _FUNCTIONS, _OBJECTS is set after including Makefile.common.
54+
55+
include ../Makefile.common
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright (c) The mldsa-native project authors
2+
// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
3+
4+
#include "packing.h"
5+
6+
7+
void harness(void)
8+
{
9+
uint8_t *a;
10+
mld_poly *zi;
11+
unsigned i;
12+
mld_pack_sig_z(a, zi, i);
13+
}

0 commit comments

Comments
 (0)