Skip to content

Commit 56f194f

Browse files
authored
Merge pull request #573 from pq-code-package/autogen_configs
Test: Autogenerate test configurations
2 parents 0bfa77a + d4b8330 commit 56f194f

File tree

10 files changed

+948
-44
lines changed

10 files changed

+948
-44
lines changed

mldsa/config.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@
103103
* Name: MLD_CONFIG_FILE
104104
*
105105
* Description: If defined, this is a header that will be included instead
106-
* of this default configuration file mldsa/config.h.
106+
* of the default configuration file mldsa/config.h.
107107
*
108108
* When you need to build mldsa-native in multiple configurations,
109109
* using varying MLD_CONFIG_FILE can be more convenient

scripts/autogen

Lines changed: 146 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,17 +69,21 @@ def file_updated(filename):
6969
print(f"\r{BOLD}updated {filename}{NORMAL}")
7070

7171

72-
def gen_header():
73-
yield "/*"
74-
yield " * Copyright (c) The mldsa-native project authors"
75-
yield " * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT"
76-
yield " */"
72+
def gen_autogen_warning():
7773
yield ""
7874
yield "/*"
7975
yield " * WARNING: This file is auto-generated from scripts/autogen"
8076
yield " * in the mldsa-native repository."
8177
yield " * Do not modify it directly."
8278
yield " */"
79+
80+
81+
def gen_header():
82+
yield "/*"
83+
yield " * Copyright (c) The mldsa-native project authors"
84+
yield " * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT"
85+
yield " */"
86+
yield from gen_autogen_warning()
8387
yield ""
8488

8589

@@ -465,6 +469,7 @@ def update_file(
465469
force_format=False,
466470
skip_preprocessor_comments=False,
467471
):
472+
468473
if force_format is True or filename.endswith((".c", ".h", ".i")):
469474
if skip_preprocessor_comments is False:
470475
content = adjust_preprocessor_comments_for_filename(content, filename)
@@ -1713,6 +1718,140 @@ def gen_citations(dry_run=False):
17131718
gen_bib_file(bibliography, dry_run=dry_run)
17141719

17151720

1721+
def gen_test_config(config_path, config_spec, default_config_content, dry_run=False):
1722+
"""Generate a config file by modifying the default config."""
1723+
status_update("test configs", config_path)
1724+
1725+
# Start with the default config
1726+
lines = default_config_content.split("\n")
1727+
1728+
# Find copyright and reference header
1729+
references_start = None
1730+
references_end = None
1731+
1732+
# NOTE: This needs further work if any custom config contains citations
1733+
# not included in the default configuration. In this case, the reference
1734+
# section needs to be updated.
1735+
1736+
for i, line in enumerate(lines):
1737+
if "/* References" in line:
1738+
references_start = i
1739+
elif (
1740+
references_start is not None
1741+
and references_end is None
1742+
and line.strip() == "*/"
1743+
):
1744+
references_end = i + 1
1745+
break
1746+
1747+
header = lines[:references_end]
1748+
header += list(gen_autogen_warning())
1749+
1750+
header.append("")
1751+
header.append("/*")
1752+
header.append(f" * Test configuration: {config_spec['description']}")
1753+
header.append(" *")
1754+
header.append(
1755+
" * This configuration differs from the default mldsa/src/config.h in the following places:"
1756+
)
1757+
1758+
def spec_has_value(opt_value):
1759+
if not isinstance(opt_value, dict):
1760+
return True
1761+
else:
1762+
return "value" in opt_value.keys() or "content" in opt_value.keys()
1763+
1764+
for opt_name, opt_value in config_spec["defines"].items():
1765+
if not spec_has_value(opt_value):
1766+
continue
1767+
header.append(f" * - {opt_name}")
1768+
header.append(" */")
1769+
header.append("")
1770+
1771+
# Combine: new header + config body
1772+
lines = header + lines[references_end:]
1773+
1774+
def locate_config_option(lines, opt_name):
1775+
"""Locate configuration option in lines. Returns (start, end) line indices"""
1776+
i = 0
1777+
while i < len(lines):
1778+
if re.search(rf"\* Name:\s+{re.escape(opt_name)}\b", lines[i]):
1779+
# Skip to the end of this comment block (find the closing */)
1780+
while i < len(lines) and not lines[i].strip().endswith("*/"):
1781+
i += 1
1782+
i += 1 # Skip the closing */
1783+
1784+
start = i
1785+
# Find the next config option (starts with /*****)
1786+
while i < len(lines):
1787+
if lines[i].strip().startswith("/****"):
1788+
# Back up to exclude empty line before next option
1789+
while i > start and lines[i - 1].strip() == "":
1790+
i -= 1
1791+
return (start, i)
1792+
i += 1
1793+
# If no next option found, go to end
1794+
return (start, len(lines))
1795+
i += 1
1796+
raise Exception(f"Could not find config option {opt_name} in default config")
1797+
1798+
def replace_config_option(lines, opt_name, opt_value):
1799+
"""Replace config option with new value"""
1800+
block_start, block_end = locate_config_option(lines, opt_name)
1801+
1802+
def content_from_value(value):
1803+
if value is True:
1804+
return [f"#define {opt_name}"]
1805+
elif value is False:
1806+
return [f"/* #define {opt_name} */"]
1807+
else:
1808+
return [f"#define {opt_name} {str(value)}"]
1809+
1810+
if isinstance(opt_value, dict):
1811+
if "content" in opt_value:
1812+
content = opt_value.get("content").split("\n")
1813+
elif "value" in opt_value:
1814+
content = content_from_value(opt_value["value"])
1815+
else:
1816+
# Use original content
1817+
content = lines[block_start:block_end]
1818+
if "comment" in opt_value:
1819+
comment = opt_value.get("comment").split("\n")
1820+
else:
1821+
comment = []
1822+
else:
1823+
content = content_from_value(opt_value)
1824+
comment = []
1825+
1826+
lines[block_start:block_end] = comment + content
1827+
1828+
# Apply modifications for each defined option
1829+
for opt_name, opt_value in config_spec["defines"].items():
1830+
replace_config_option(lines, opt_name, opt_value)
1831+
1832+
content = "\n".join(lines)
1833+
update_file(
1834+
config_path,
1835+
content,
1836+
dry_run=dry_run,
1837+
)
1838+
1839+
1840+
def gen_test_configs(dry_run=False):
1841+
"""Generate all test configuration files from metadata."""
1842+
# Load metadata
1843+
with open("test/configs.yml", "r") as f:
1844+
metadata = yaml.safe_load(f)
1845+
1846+
# Load default config
1847+
with open("mldsa/config.h", "r") as f:
1848+
default_config = f.read()
1849+
1850+
# Generate each test config
1851+
for config_spec in metadata["configs"]:
1852+
gen_test_config(config_spec["path"], config_spec, default_config, dry_run)
1853+
1854+
17161855
def _main():
17171856
parser = argparse.ArgumentParser(
17181857
formatter_class=argparse.ArgumentDefaultsHelpFormatter
@@ -1759,6 +1898,8 @@ def _main():
17591898
no_simplify=args.no_simplify,
17601899
)
17611900
high_level_status("Completed final backend synchronization")
1901+
gen_test_configs(args.dry_run)
1902+
high_level_status("Generated test configs")
17621903

17631904

17641905
if __name__ == "__main__":

test/break_pct_config.h

Lines changed: 134 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,22 @@
1717
* https://csrc.nist.gov/pubs/fips/204/final
1818
*/
1919

20+
/*
21+
* WARNING: This file is auto-generated from scripts/autogen
22+
* in the mldsa-native repository.
23+
* Do not modify it directly.
24+
*/
25+
26+
/*
27+
* Test configuration: Test configuration for PCT breakage testing
28+
*
29+
* This configuration differs from the default mldsa/src/config.h in the
30+
* following places:
31+
* - MLD_CONFIG_KEYGEN_PCT
32+
* - MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST
33+
*/
34+
35+
2036
#ifndef MLD_CONFIG_H
2137
#define MLD_CONFIG_H
2238

@@ -103,7 +119,7 @@
103119
* Name: MLD_CONFIG_FILE
104120
*
105121
* Description: If defined, this is a header that will be included instead
106-
* of this default configuration file mldsa/config.h.
122+
* of the default configuration file mldsa/config.h.
107123
*
108124
* When you need to build mldsa-native in multiple configurations,
109125
* using varying MLD_CONFIG_FILE can be more convenient
@@ -153,7 +169,6 @@
153169
!defined(MLD_CONFIG_FIPS202_BACKEND_FILE)
154170
#define MLD_CONFIG_FIPS202_BACKEND_FILE "fips202/native/auto.h"
155171
#endif
156-
157172
/******************************************************************************
158173
* Name: MLD_CONFIG_FIPS202_CUSTOM_HEADER
159174
*
@@ -189,9 +204,9 @@
189204
/******************************************************************************
190205
* Name: MLD_CONFIG_CUSTOM_ZEROIZE
191206
*
192-
* Description: In compliance with @[FIPS204, Section 3.6.3], mldsa-native
207+
* Description: In compliance with @[FIPS204, Section 3.6.3], mldsa-native,
193208
* zeroizes intermediate stack buffers before returning from
194-
*. function calls.
209+
* function calls.
195210
*
196211
* Set this option and define `mld_zeroize_native` if you want to
197212
* use a custom method to zeroize intermediate stack buffers.
@@ -227,6 +242,78 @@
227242
#endif
228243
*/
229244

245+
/******************************************************************************
246+
* Name: MLD_CONFIG_CUSTOM_MEMCPY
247+
*
248+
* Description: Set this option and define `mld_memcpy` if you want to
249+
* use a custom method to copy memory instead of the standard
250+
* library memcpy function.
251+
*
252+
* The custom implementation must have the same signature and
253+
* behavior as the standard memcpy function:
254+
* void *mld_memcpy(void *dest, const void *src, size_t n)
255+
*
256+
*****************************************************************************/
257+
/* #define MLD_CONFIG_CUSTOM_MEMCPY
258+
#if !defined(__ASSEMBLER__)
259+
#include <stdint.h>
260+
#include "sys.h"
261+
static MLD_INLINE void *mld_memcpy(void *dest, const void *src, size_t n)
262+
{
263+
... your implementation ...
264+
}
265+
#endif
266+
*/
267+
268+
/******************************************************************************
269+
* Name: MLD_CONFIG_CUSTOM_MEMSET
270+
*
271+
* Description: Set this option and define `mld_memset` if you want to
272+
* use a custom method to set memory instead of the standard
273+
* library memset function.
274+
*
275+
* The custom implementation must have the same signature and
276+
* behavior as the standard memset function:
277+
* void *mld_memset(void *s, int c, size_t n)
278+
*
279+
*****************************************************************************/
280+
/* #define MLD_CONFIG_CUSTOM_MEMSET
281+
#if !defined(__ASSEMBLER__)
282+
#include <stdint.h>
283+
#include "sys.h"
284+
static MLD_INLINE void *mld_memset(void *s, int c, size_t n)
285+
{
286+
... your implementation ...
287+
}
288+
#endif
289+
*/
290+
291+
/******************************************************************************
292+
* Name: MLD_CONFIG_CUSTOM_RANDOMBYTES
293+
*
294+
* Description: mldsa-native does not provide a secure randombytes
295+
* implementation. Such an implementation has to provided by the
296+
* consumer.
297+
*
298+
* If this option is not set, mldsa-native expects a function
299+
* void randombytes(uint8_t *out, size_t outlen).
300+
*
301+
* Set this option and define `mld_randombytes` if you want to
302+
* use a custom method to sample randombytes with a different name
303+
* or signature.
304+
*
305+
*****************************************************************************/
306+
/* #define MLD_CONFIG_CUSTOM_RANDOMBYTES
307+
#if !defined(__ASSEMBLER__)
308+
#include <stdint.h>
309+
#include "sys.h"
310+
static MLD_INLINE void mld_randombytes(uint8_t *ptr, size_t len)
311+
{
312+
... your implementation ...
313+
}
314+
#endif
315+
*/
316+
230317
/******************************************************************************
231318
* Name: MLD_CONFIG_KEYGEN_PCT
232319
*
@@ -266,8 +353,47 @@ static MLD_INLINE int mld_break_pct(void)
266353
const char *val = getenv("MLD_BREAK_PCT");
267354
return val != NULL && strcmp(val, "1") == 0;
268355
}
269-
#endif
356+
#endif /* !__ASSEMBLER__ */
357+
270358

359+
/******************************************************************************
360+
* Name: MLD_CONFIG_INTERNAL_API_QUALIFIER
361+
*
362+
* Description: If set, this option provides an additional function
363+
* qualifier to be added to declarations of internal API.
364+
*
365+
* The primary use case for this option are single-CU builds,
366+
* in which case this option can be set to `static`.
367+
*
368+
*****************************************************************************/
369+
/* #define MLD_CONFIG_INTERNAL_API_QUALIFIER */
370+
371+
/******************************************************************************
372+
* Name: MLD_CONFIG_EXTERNAL_API_QUALIFIER
373+
*
374+
* Description: If set, this option provides an additional function
375+
* qualifier to be added to declarations of mldsa-native's
376+
* public API.
377+
*
378+
* The primary use case for this option are single-CU builds
379+
* where the public API exposed by mldsa-native is wrapped by
380+
* another API in the consuming application. In this case,
381+
* even mldsa-native's public API can be marked `static`.
382+
*
383+
*****************************************************************************/
384+
/* #define MLD_CONFIG_EXTERNAL_API_QUALIFIER */
385+
386+
/******************************************************************************
387+
* Name: MLD_CONFIG_CT_TESTING_ENABLED
388+
*
389+
* Description: If set, mldsa-native annotates data as secret / public using
390+
* valgrind's annotations VALGRIND_MAKE_MEM_UNDEFINED and
391+
* VALGRIND_MAKE_MEM_DEFINED, enabling various checks for secret-
392+
* dependent control flow of variable time execution (depending
393+
* on the exact version of valgrind installed).
394+
*
395+
*****************************************************************************/
396+
/* #define MLD_CONFIG_CT_TESTING_ENABLED */
271397

272398
/******************************************************************************
273399
* Name: MLD_CONFIG_NO_ASM
@@ -306,6 +432,8 @@ static MLD_INLINE int mld_break_pct(void)
306432
*****************************************************************************/
307433
/* #define MLD_CONFIG_NO_ASM_VALUE_BARRIER */
308434

435+
436+
309437
/************************* Config internals ********************************/
310438

311439
/* Default namespace
@@ -317,7 +445,7 @@ static MLD_INLINE int mld_break_pct(void)
317445
*
318446
* PQCP_MLDSA_NATIVE_MLDSA<LEVEL>_
319447
*
320-
* e.g., PQCP_MLDSA_NATIVE_MLDSA65_
448+
* e.g., PQCP_MLDSA_NATIVE_MLDSA44_
321449
*/
322450

323451
#if MLD_CONFIG_PARAMETER_SET == 44

0 commit comments

Comments
 (0)