blob: fbccb8a9f59b71b616f99ac6f2faa2c564d0571f [file] [log] [blame]
Werner Lewis545911f2022-07-08 13:54:57 +01001#!/usr/bin/env python3
2"""Generate test data for bignum functions.
3
4With no arguments, generate all test data. With non-option arguments,
5generate only the specified files.
6"""
7
8# Copyright The Mbed TLS Contributors
9# SPDX-License-Identifier: Apache-2.0
10#
11# Licensed under the Apache License, Version 2.0 (the "License"); you may
12# not use this file except in compliance with the License.
13# You may obtain a copy of the License at
14#
15# http://www.apache.org/licenses/LICENSE-2.0
16#
17# Unless required by applicable law or agreed to in writing, software
18# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
19# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20# See the License for the specific language governing permissions and
21# limitations under the License.
22
Werner Lewis545911f2022-07-08 13:54:57 +010023import itertools
Werner Lewis545911f2022-07-08 13:54:57 +010024import sys
Werner Lewisdcad1e92022-08-24 11:30:03 +010025from typing import Callable, Dict, Iterator, List, Optional, Tuple, TypeVar
Werner Lewis545911f2022-07-08 13:54:57 +010026
27import scripts_path # pylint: disable=unused-import
Werner Lewis545911f2022-07-08 13:54:57 +010028from mbedtls_dev import test_case
Werner Lewisdcad1e92022-08-24 11:30:03 +010029from mbedtls_dev import test_generation
Werner Lewis545911f2022-07-08 13:54:57 +010030
31T = TypeVar('T') #pylint: disable=invalid-name
32
33def hex_to_int(val):
34 return int(val, 16) if val else 0
35
36def quote_str(val):
37 return "\"{}\"".format(val)
38
39
Werner Lewisdcad1e92022-08-24 11:30:03 +010040class BignumTarget(test_generation.BaseTarget):
Werner Lewis545911f2022-07-08 13:54:57 +010041 """Target for bignum (mpi) test case generation."""
Werner Lewis70d3f3d2022-08-23 14:21:53 +010042 target_basename = 'test_suite_mpi.generated'
Werner Lewis545911f2022-07-08 13:54:57 +010043
44
45class BignumOperation(BignumTarget):
46 """Common features for test cases covering bignum operations.
47
48 Attributes:
Werner Lewis70d3f3d2022-08-23 14:21:53 +010049 symbol: Symbol used for operation in description.
50 input_values: List of values to use as test case inputs.
51 input_cases: List of tuples containing pairs of test case inputs. This
Werner Lewis545911f2022-07-08 13:54:57 +010052 can be used to implement specific pairs of inputs.
53 """
Werner Lewis70d3f3d2022-08-23 14:21:53 +010054 symbol = ""
55 input_values = [
Werner Lewis545911f2022-07-08 13:54:57 +010056 "", "0", "7b", "-7b",
57 "0000000000000000123", "-0000000000000000123",
58 "1230000000000000000", "-1230000000000000000"
Werner Lewisd76c5ed2022-07-20 14:13:44 +010059 ] # type: List[str]
60 input_cases = [] # type: List[Tuple[str, ...]]
Werner Lewis545911f2022-07-08 13:54:57 +010061
62 def __init__(self, val_l: str, val_r: str) -> None:
63 super().__init__()
64
65 self.arg_l = val_l
66 self.arg_r = val_r
67 self.int_l = hex_to_int(val_l)
68 self.int_r = hex_to_int(val_r)
69
Werner Lewis70d3f3d2022-08-23 14:21:53 +010070 def arguments(self):
71 return [quote_str(self.arg_l), quote_str(self.arg_r), self.result()]
Werner Lewis545911f2022-07-08 13:54:57 +010072
Werner Lewis545911f2022-07-08 13:54:57 +010073 def description(self):
Werner Lewis70d3f3d2022-08-23 14:21:53 +010074 if not self.case_description:
75 self.case_description = "{} {} {}".format(
76 self.value_description(self.arg_l),
77 self.symbol,
78 self.value_description(self.arg_r)
79 )
80 return super().description()
Werner Lewis545911f2022-07-08 13:54:57 +010081
Werner Lewis545911f2022-07-08 13:54:57 +010082 def result(self) -> Optional[str]:
83 return None
84
85 @staticmethod
Werner Lewis70d3f3d2022-08-23 14:21:53 +010086 def value_description(val) -> str:
Werner Lewis545911f2022-07-08 13:54:57 +010087 if val == "":
88 return "0 (null)"
89 if val == "0":
90 return "0 (1 limb)"
91
92 if val[0] == "-":
93 tmp = "negative"
94 val = val[1:]
95 else:
96 tmp = "positive"
97 if val[0] == "0":
98 tmp += " with leading zero limb"
99 elif len(val) > 10:
100 tmp = "large " + tmp
101 return tmp
102
103 @classmethod
104 def get_value_pairs(cls) -> Iterator[Tuple[str, ...]]:
105 """Generate value pairs."""
Werner Lewis1bdee222022-07-20 13:35:53 +0100106 for pair in list(
Werner Lewis70d3f3d2022-08-23 14:21:53 +0100107 itertools.combinations(cls.input_values, 2)
Werner Lewis1bdee222022-07-20 13:35:53 +0100108 ) + cls.input_cases:
Werner Lewis545911f2022-07-08 13:54:57 +0100109 yield pair
110
111 @classmethod
112 def generate_tests(cls) -> Iterator[test_case.TestCase]:
Werner Lewis70d3f3d2022-08-23 14:21:53 +0100113 if cls.test_function:
Werner Lewis545911f2022-07-08 13:54:57 +0100114 # Generate tests for the current class
115 for l_value, r_value in cls.get_value_pairs():
116 cur_op = cls(l_value, r_value)
117 yield cur_op.create_test_case()
118 # Once current class completed, check descendants
119 yield from super().generate_tests()
120
121
122class BignumCmp(BignumOperation):
123 """Target for bignum comparison test cases."""
124 count = 0
Werner Lewis70d3f3d2022-08-23 14:21:53 +0100125 test_function = "mbedtls_mpi_cmp_mpi"
126 test_name = "MPI compare"
Werner Lewis545911f2022-07-08 13:54:57 +0100127 input_cases = [
128 ("-2", "-3"),
129 ("-2", "-2"),
130 ("2b4", "2b5"),
131 ("2b5", "2b6")
132 ]
133
134 def __init__(self, val_l, val_r):
135 super().__init__(val_l, val_r)
136 self._result = (self.int_l > self.int_r) - (self.int_l < self.int_r)
Werner Lewis70d3f3d2022-08-23 14:21:53 +0100137 self.symbol = ["<", "==", ">"][self._result + 1]
Werner Lewis545911f2022-07-08 13:54:57 +0100138
Werner Lewis545911f2022-07-08 13:54:57 +0100139 def result(self):
140 return str(self._result)
141
142
Werner Lewis423f99b2022-07-18 15:49:43 +0100143class BignumCmpAbs(BignumCmp):
144 """Target for abs comparison variant."""
145 count = 0
Werner Lewis70d3f3d2022-08-23 14:21:53 +0100146 test_function = "mbedtls_mpi_cmp_abs"
147 test_name = "MPI compare (abs)"
Werner Lewis423f99b2022-07-18 15:49:43 +0100148
149 def __init__(self, val_l, val_r):
150 super().__init__(val_l.strip("-"), val_r.strip("-"))
151
152
Werner Lewis5c1173b2022-07-18 17:22:58 +0100153class BignumAdd(BignumOperation):
154 """Target for bignum addition test cases."""
155 count = 0
Werner Lewis70d3f3d2022-08-23 14:21:53 +0100156 test_function = "mbedtls_mpi_add_mpi"
157 test_name = "MPI add"
Werner Lewis5c1173b2022-07-18 17:22:58 +0100158 input_cases = list(itertools.combinations(
159 [
160 "1c67967269c6", "9cde3",
161 "-1c67967269c6", "-9cde3",
162 ], 2
163 ))
164
165 def __init__(self, val_l, val_r):
166 super().__init__(val_l, val_r)
Werner Lewis70d3f3d2022-08-23 14:21:53 +0100167 self.symbol = "+"
Werner Lewis5c1173b2022-07-18 17:22:58 +0100168
Werner Lewis5c1173b2022-07-18 17:22:58 +0100169 def result(self):
170 return quote_str(hex(self.int_l + self.int_r).replace("0x", "", 1))
171
172
Werner Lewisdcad1e92022-08-24 11:30:03 +0100173class BignumTestGenerator(test_generation.TestGenerator):
174 """Test generator subclass including bignum targets."""
Werner Lewis545911f2022-07-08 13:54:57 +0100175 TARGETS = {
Werner Lewis70d3f3d2022-08-23 14:21:53 +0100176 subclass.target_basename: subclass.generate_tests for subclass in
Werner Lewisdcad1e92022-08-24 11:30:03 +0100177 test_generation.BaseTarget.__subclasses__()
178 } # type: Dict[str, Callable[[], test_case.TestCase]]
Werner Lewis545911f2022-07-08 13:54:57 +0100179
180if __name__ == '__main__':
Werner Lewisdcad1e92022-08-24 11:30:03 +0100181 test_generation.main(sys.argv[1:], BignumTestGenerator)