Skip to content

Commit 9a180a9

Browse files
committed
ACVP: Support FIPS204-tr1 sigGen (v1.1.0.43)
The FIPS204-tr1 sigGen revision adds keyFormat 'seed'/'expanded' test groups: the private key may be supplied as a 32-byte seed to expand rather than as the expanded sk. Add a decode_sk() entry point to the ACVP harness accepting either sk=HEX or seed=HEX (expanding the seed via keyGen), and route all sigGen sub-modes through it. Download and run the ML-DSA-sigGen-FIPS204-tr1 vectors when the version ships them (v1.1.0.43+). Signed-off-by: Matthias J. Kannwischer <matthias@zerorisc.com>
1 parent 2d1bdf6 commit 9a180a9

7 files changed

Lines changed: 149 additions & 42 deletions

File tree

.github/workflows/base.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ jobs:
7070
name: 'aarch64'
7171
- runner: ubuntu-latest
7272
name: 'x86_64'
73-
acvp-version: [v1.1.0.40, v1.1.0.41, v1.1.0.42]
73+
acvp-version: [v1.1.0.41, v1.1.0.42, v1.1.0.43]
7474
exclude:
7575
- {external: true,
7676
target: {

mldsa/mldsa_native.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,7 @@
519519
#undef MLD_HAVE_INLINE_ASM
520520
#undef MLD_INLINE
521521
#undef MLD_MUST_CHECK_RETURN_VALUE
522+
#undef MLD_NOINLINE
522523
#undef MLD_RESTRICT
523524
#undef MLD_STATIC_TESTABLE
524525
#undef MLD_SYSV_ABI

mldsa/mldsa_native_asm.S

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,7 @@
546546
#undef MLD_HAVE_INLINE_ASM
547547
#undef MLD_INLINE
548548
#undef MLD_MUST_CHECK_RETURN_VALUE
549+
#undef MLD_NOINLINE
549550
#undef MLD_RESTRICT
550551
#undef MLD_STATIC_TESTABLE
551552
#undef MLD_SYSV_ABI

mldsa/src/sys.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,22 @@
169169
#endif
170170
#endif /* !MLD_ALWAYS_INLINE */
171171

172+
/*
173+
* MLD_NOINLINE: Prevent inlining.
174+
* - MSVC: __declspec(noinline)
175+
* - GCC/Clang: __attribute__((noinline))
176+
* - Other: empty
177+
*/
178+
#if !defined(MLD_NOINLINE)
179+
#if defined(_MSC_VER)
180+
#define MLD_NOINLINE __declspec(noinline)
181+
#elif defined(__GNUC__) || defined(__clang__)
182+
#define MLD_NOINLINE __attribute__((noinline))
183+
#else
184+
#define MLD_NOINLINE
185+
#endif
186+
#endif /* !MLD_NOINLINE */
187+
172188
#ifndef MLD_STATIC_TESTABLE
173189
#define MLD_STATIC_TESTABLE static
174190
#endif

scripts/tests

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1414,8 +1414,8 @@ def cli():
14141414
)
14151415
acvp_parser.add_argument(
14161416
"--version",
1417-
default="v1.1.0.41",
1418-
help="ACVP test vector version (default: v1.1.0.41)",
1417+
default="v1.1.0.43",
1418+
help="ACVP test vector version (default: v1.1.0.43)",
14191419
)
14201420

14211421
# wycheproof arguments

test/acvp/acvp_client.py

Lines changed: 57 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,23 @@ def download_file(url, dest, token):
4949
time.sleep(wait)
5050

5151

52+
def acvp_version_has_tr1(version):
53+
"""Whether `version` ships the FIPS204-tr1 sigGen vectors (v1.1.0.43+)."""
54+
try:
55+
parts = tuple(int(x) for x in version.lstrip("v").split("."))
56+
except ValueError:
57+
# Non-numeric ref (branch or commit); assume the vectors are present.
58+
return True
59+
return parts >= (1, 1, 0, 43)
60+
61+
5262
def download_acvp_files(version):
5363
"""Download ACVP test files for the specified version if not present."""
5464
api_base = (
5565
"https://api.github.com/repos/usnistgov/ACVP-Server/contents/gen-val/json-files"
5666
)
5767

58-
# Files we need to download for ML-KEM
68+
# Files we need to download for ML-DSA
5969
files_to_download = [
6070
"ML-DSA-keyGen-FIPS204/prompt.json",
6171
"ML-DSA-keyGen-FIPS204/expectedResults.json",
@@ -65,6 +75,13 @@ def download_acvp_files(version):
6575
"ML-DSA-sigVer-FIPS204/expectedResults.json",
6676
]
6777

78+
# The FIPS204-tr1 sigGen vectors add seed/expanded key-format groups.
79+
if acvp_version_has_tr1(version):
80+
files_to_download += [
81+
"ML-DSA-sigGen-FIPS204-tr1/prompt.json",
82+
"ML-DSA-sigGen-FIPS204-tr1/expectedResults.json",
83+
]
84+
6885
# Create directory structure
6986
data_dir = Path(f"test/acvp/.acvp-data/{version}/files")
7087
data_dir.mkdir(parents=True, exist_ok=True)
@@ -153,6 +170,17 @@ def loadDefaultAcvpData(version, supported_modes=None):
153170
f"{data_dir}/ML-DSA-sigVer-FIPS204/expectedResults.json",
154171
),
155172
]
173+
174+
# FIPS204-tr1 sigGen vectors (seed/expanded key formats) exist from v1.1.0.43.
175+
if acvp_version_has_tr1(version):
176+
acvp_jsons_for_version.append(
177+
(
178+
"sigGen",
179+
f"{data_dir}/ML-DSA-sigGen-FIPS204-tr1/prompt.json",
180+
f"{data_dir}/ML-DSA-sigGen-FIPS204-tr1/expectedResults.json",
181+
)
182+
)
183+
156184
acvp_data = []
157185
for mode, prompt, expectedResults in acvp_jsons_for_version:
158186
if mode not in supported_modes:
@@ -270,6 +298,13 @@ def unsupported_hash(tg, tc):
270298
return f"hash algorithm {hashAlg} unavailable in this Python's hashlib"
271299

272300

301+
def seed_key_format(tg, tc):
302+
# keyFormat 'seed' cases need keyGen to expand the key into the private key.
303+
if tg.get("keyFormat") == "seed":
304+
return "seed key format requires the keyGen API"
305+
return None
306+
307+
273308
def filter_test_cases(acvp_data, should_drop):
274309
# Drop cases for which should_drop(tg, tc) returns a reason (None keeps).
275310
# Reasons come from the prompt but are applied to expected data too.
@@ -299,6 +334,13 @@ def run_sigGen_test(tg, tc):
299334

300335
assert tg["testType"] == "AFT"
301336

337+
# keyFormat 'seed' passes a seed for the binary to expand into the private
338+
# key; 'expanded' (or absent) passes the expanded sk directly.
339+
if tg.get("keyFormat") == "seed":
340+
sk_arg = f"seed={tc['seed']}"
341+
else:
342+
sk_arg = f"sk={tc['sk']}"
343+
302344
is_deterministic = tg["deterministic"] is True
303345
if "preHash" in tg and tg["preHash"] == "preHash":
304346
assert len(tc["context"]) <= 2 * 255
@@ -315,7 +357,7 @@ def run_sigGen_test(tg, tc):
315357
target,
316358
f"message={tc['message']}",
317359
f"context={tc['context']}",
318-
f"sk={tc['sk']}",
360+
sk_arg,
319361
]
320362
else:
321363
ph = compute_hash(tc["message"], tc["hashAlg"])
@@ -327,7 +369,7 @@ def run_sigGen_test(tg, tc):
327369
target,
328370
f"ph={ph}",
329371
f"context={tc['context']}",
330-
f"sk={tc['sk']}",
372+
sk_arg,
331373
f"hashAlg={tc['hashAlg']}",
332374
]
333375
elif tg["signatureInterface"] == "external":
@@ -340,7 +382,7 @@ def run_sigGen_test(tg, tc):
340382
acvp_bin,
341383
target,
342384
f"message={tc['message']}",
343-
f"sk={tc['sk']}",
385+
sk_arg,
344386
f"context={tc['context']}",
345387
]
346388
else: # signatureInterface=internal
@@ -359,7 +401,7 @@ def run_sigGen_test(tg, tc):
359401
acvp_bin,
360402
target,
361403
f"message={msg}",
362-
f"sk={tc['sk']}",
404+
sk_arg,
363405
f"externalMu={externalMu}",
364406
]
365407

@@ -555,6 +597,14 @@ def test(
555597
info("No test data to run (all modes disabled in this build)")
556598
return
557599

600+
# Seed key-format cases require keyGen to expand the key; drop them when the
601+
# build does not provide it (unconditionally, unlike --skip-unsupported).
602+
if supported_modes is not None and "keyGen" not in supported_modes:
603+
seed_reasons = filter_test_cases(data, seed_key_format)
604+
if seed_reasons:
605+
summary = ", ".join(sorted(set(seed_reasons)))
606+
info(f"Skipping {len(seed_reasons)} test case(s): {summary}")
607+
558608
reasons = filter_test_cases(data, unsupported_hash)
559609
if reasons:
560610
summary = ", ".join(sorted(set(reasons)))
@@ -583,8 +633,8 @@ def test(
583633
parser.add_argument(
584634
"--version",
585635
"-v",
586-
default="v1.1.0.41",
587-
help="ACVP test vector version (default: v1.1.0.41)",
636+
default="v1.1.0.43",
637+
help="ACVP test vector version (default: v1.1.0.43)",
588638
)
589639
parser.add_argument(
590640
"--no-keygen",

0 commit comments

Comments
 (0)