|
1 | 1 | #!/usr/bin/env python3 |
2 | 2 | """Generate ML-DSA test cases. |
3 | | -""" |
4 | 3 |
|
5 | | -# Copyright The Mbed TLS Contributors |
6 | | -# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later |
| 4 | +This is a transitional script that does not handle different feature sets |
| 5 | +in different states of TF-PSA-Crypto. The live version of this script |
| 6 | +is `scripts/maintainer/generate_mldsa_tests.py` in TF-PSA-Crypto. |
| 7 | +""" |
7 | 8 |
|
8 | 9 | import sys |
9 | | -from typing import Iterable, List, Optional |
10 | | - |
11 | | -# pip install dilithium-py |
12 | | -import dilithium_py.ml_dsa #type: ignore |
13 | 10 |
|
14 | 11 | import scripts_path # pylint: disable=unused-import |
15 | | -from mbedtls_framework import test_case |
16 | 12 | from mbedtls_framework import test_data_generation |
17 | | - |
18 | | -# ML_DSA instances for pure ML-DSA |
19 | | -PURE = { |
20 | | - #44: dilithium_py.ml_dsa.ML_DSA_44, |
21 | | - #65: dilithium_py.ml_dsa.ML_DSA_65, |
22 | | - 87: dilithium_py.ml_dsa.ML_DSA_87, |
23 | | -} |
24 | | - |
25 | | -# ML_DSA instances for HashML-DSA |
26 | | -HASH = { |
27 | | - #44: dilithium_py.ml_dsa.HASH_ML_DSA_44_WITH_SHA512, |
28 | | - #65: dilithium_py.ml_dsa.HASH_ML_DSA_65_WITH_SHA512, |
29 | | - 87: dilithium_py.ml_dsa.HASH_ML_DSA_87_WITH_SHA512, |
30 | | -} |
31 | | - |
32 | | -# Seeds (i.e. private keys) to test with. |
33 | | -SEEDS = [ |
34 | | - b'There was once upon a time a ...', |
35 | | - b'\x00' * 32, |
36 | | -] |
37 | | - |
38 | | -class Key: |
39 | | - """An MLDSA key pair.""" |
40 | | - #pylint: disable=too-few-public-methods |
41 | | - |
42 | | - def __init__(self, kl: int, seed: bytes) -> None: |
43 | | - self.kl = kl #pylint: disable=invalid-name |
44 | | - self.seed = seed |
45 | | - self.public, self.secret = PURE[kl]._keygen_internal(seed) |
46 | | - |
47 | | - def sign_message(self, message: bytes, deterministic: bool) -> bytes: |
48 | | - PURE[self.kl].set_drbg_seed(bytes(48)) |
49 | | - return PURE[self.kl].sign(self.secret, message, |
50 | | - deterministic=deterministic) |
51 | | - |
52 | | -# Key pairs to test with. |
53 | | -KEYS = {kl: [Key(kl, seed) for seed in SEEDS] |
54 | | - for kl in sorted(PURE.keys())} |
55 | | - |
56 | | -# Input messages to test with. |
57 | | -MESSAGES = [ |
58 | | - (b'This is a test', ''), |
59 | | - (b'', 'empty message'), |
60 | | - (b'\x00', '"\\x00"'), |
61 | | - (b'\x01', '"\\x01"'), |
62 | | - (b'ACBDEFGHIJ' * 100, '1000B'), |
63 | | -] |
64 | | - |
65 | | - |
66 | | -class API: |
67 | | - """Abstract base class for the interface of the test functions.""" |
68 | | - |
69 | | - @classmethod |
70 | | - def function(cls, func: str, kl: int) -> str: |
71 | | - raise NotImplementedError |
72 | | - |
73 | | - @classmethod |
74 | | - def metadata_arguments(cls, |
75 | | - kl: int, |
76 | | - pair: bool, |
77 | | - deterministic: Optional[bool]) -> List[str]: |
78 | | - raise NotImplementedError |
79 | | - |
80 | | - @classmethod |
81 | | - def final_arguments(cls) -> List[str]: |
82 | | - return [] |
83 | | - |
84 | | - @classmethod |
85 | | - def secret_is_seed(cls) -> bool: |
86 | | - return True |
87 | | - |
88 | | - |
89 | | -class PQCPAPI(API): |
90 | | - """Test mldsa-native entry points.""" |
91 | | - |
92 | | - @classmethod |
93 | | - def function(cls, func: str, kl: int) -> str: |
94 | | - return f'{func}_{kl}' |
95 | | - |
96 | | - @classmethod |
97 | | - def metadata_arguments(cls, |
98 | | - _kl: int, |
99 | | - _pair: bool, |
100 | | - _deterministic: Optional[bool]) -> List[str]: |
101 | | - return [] |
102 | | - |
103 | | - @classmethod |
104 | | - def secret_is_seed(cls) -> bool: |
105 | | - return False |
106 | | - |
107 | | - |
108 | | -def one_mldsa_key_pair_from_seed(key: Key, |
109 | | - descr: str) -> test_case.TestCase: |
110 | | - """Construct one test case for mldsa-native keypair_internal().""" |
111 | | - tc = test_case.TestCase() |
112 | | - tc.set_function(f'key_pair_from_seed_{key.kl}') |
113 | | - tc.set_dependencies([f'TF_PSA_CRYPTO_PQCP_MLDSA_{key.kl}_ENABLED']) |
114 | | - tc.set_arguments([ |
115 | | - test_case.hex_string(key.seed), |
116 | | - test_case.hex_string(key.secret), |
117 | | - test_case.hex_string(key.public), |
118 | | - ]) |
119 | | - tc.set_description(f'MLDSA-{key.kl} key pair from seed {descr}') |
120 | | - return tc |
121 | | - |
122 | | -def gen_pqcp_key_management(kl: int) -> Iterable[test_case.TestCase]: |
123 | | - """Generate test cases for mldsa-native keypair_internal().""" |
124 | | - for i, key in enumerate(KEYS[kl], 1): |
125 | | - yield one_mldsa_key_pair_from_seed(key, f'key#{i}') |
126 | | - |
127 | | -def one_mldsa_sign_deterministic_pure(api: API, |
128 | | - key: Key, |
129 | | - message: bytes, |
130 | | - descr: str) -> test_case.TestCase: |
131 | | - """Construct one test case for deterministic signature.""" |
132 | | - signature = key.sign_message(message, deterministic=True) |
133 | | - tc = test_case.TestCase() |
134 | | - tc.set_function(api.function('sign_deterministic_pure', key.kl)) |
135 | | - tc.set_dependencies([f'TF_PSA_CRYPTO_PQCP_MLDSA_{key.kl}_ENABLED']) |
136 | | - tc.set_arguments(api.metadata_arguments(key.kl, True, True) + [ |
137 | | - test_case.hex_string(key.seed if api.secret_is_seed() else key.secret), |
138 | | - test_case.hex_string(message), |
139 | | - test_case.hex_string(signature), |
140 | | - ] + api.final_arguments()) |
141 | | - tc.set_description(f'MLDSA-{key.kl} sign deterministic {descr}') |
142 | | - return tc |
143 | | - |
144 | | -def one_mldsa_verify_pure(api: API, |
145 | | - key: Key, |
146 | | - message: bytes, |
147 | | - deterministic: bool, |
148 | | - descr: str) -> test_case.TestCase: |
149 | | - """Construct one test case for verification. |
150 | | -
|
151 | | - When deterministic is true, the test case is a deterministic signature. |
152 | | - When deterministic is false, the test case is some other valid signature. |
153 | | - """ |
154 | | - signature = key.sign_message(message, deterministic=deterministic) |
155 | | - tc = test_case.TestCase() |
156 | | - tc.set_function(api.function('verify_pure', key.kl)) |
157 | | - tc.set_dependencies([f'TF_PSA_CRYPTO_PQCP_MLDSA_{key.kl}_ENABLED']) |
158 | | - tc.set_arguments(api.metadata_arguments(key.kl, False, True) + [ |
159 | | - test_case.hex_string(key.public), |
160 | | - test_case.hex_string(message), |
161 | | - test_case.hex_string(signature), |
162 | | - ] + api.final_arguments()) |
163 | | - variant = "deterministic" if deterministic else "randomized" |
164 | | - tc.set_description(f'MLDSA-{key.kl} verify {variant} {descr}') |
165 | | - return tc |
166 | | - |
167 | | -def gen_mldsa_pure(api: API, kl: int) -> Iterable[test_case.TestCase]: |
168 | | - """Generate all test cases for pure ML-DSA signature and verification.""" |
169 | | - for i, key in enumerate(KEYS[kl], 1): |
170 | | - yield one_mldsa_sign_deterministic_pure(api, key, MESSAGES[0][0], |
171 | | - f'key#{i}') |
172 | | - for message, descr in MESSAGES[1:]: |
173 | | - yield one_mldsa_sign_deterministic_pure(api, KEYS[kl][0], message, |
174 | | - f'key#1 {descr}') |
175 | | - for i, key in enumerate(KEYS[kl], 1): |
176 | | - yield one_mldsa_verify_pure(api, key, MESSAGES[0][0], True, |
177 | | - f'key#{i}') |
178 | | - for message, descr in MESSAGES[1:]: |
179 | | - yield one_mldsa_verify_pure(api, KEYS[kl][0], message, True, |
180 | | - f'key#1 {descr}') |
181 | | - for i, key in enumerate(KEYS[kl], 1): |
182 | | - yield one_mldsa_verify_pure(api, key, MESSAGES[0][0], False, |
183 | | - f'key#{i}') |
184 | | - for message, descr in MESSAGES[1:]: |
185 | | - yield one_mldsa_verify_pure(api, KEYS[kl][0], message, False, |
186 | | - f'key#1 {descr}') |
187 | | - |
188 | | -def gen_pqcp_mldsa_all() -> Iterable[test_case.TestCase]: |
189 | | - """Generate all test cases for mldsa-native.""" |
190 | | - api = PQCPAPI() |
191 | | - for kl in sorted(KEYS.keys()): |
192 | | - yield from gen_pqcp_key_management(kl) |
193 | | - yield from gen_mldsa_pure(api, kl) |
| 13 | +from mbedtls_maintainer import mldsa_test_generator |
194 | 14 |
|
195 | 15 | class MLDSATestGenerator(test_data_generation.TestGenerator): |
196 | 16 | """Generate test cases for ML-DSA.""" |
197 | 17 |
|
198 | 18 | def __init__(self, settings) -> None: |
199 | 19 | self.targets = { |
200 | | - 'test_suite_pqcp_mldsa.dilithium_py': gen_pqcp_mldsa_all, |
| 20 | + 'test_suite_pqcp_mldsa.dilithium_py': mldsa_test_generator.gen_pqcp_mldsa_all, |
201 | 21 | } |
202 | 22 | super().__init__(settings) |
203 | 23 |
|
|
0 commit comments