blob: 471fd7724571db3d7a1760c286c48b4b998193b0 [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 Lewis02998c42022-08-23 16:07:19 +0100106 yield from itertools.combinations(cls.input_values, 2)
107 yield from cls.input_cases
Werner Lewis545911f2022-07-08 13:54:57 +0100108
109 @classmethod
110 def generate_tests(cls) -> Iterator[test_case.TestCase]:
Werner Lewis70d3f3d2022-08-23 14:21:53 +0100111 if cls.test_function:
Werner Lewis545911f2022-07-08 13:54:57 +0100112 # Generate tests for the current class
113 for l_value, r_value in cls.get_value_pairs():
114 cur_op = cls(l_value, r_value)
115 yield cur_op.create_test_case()
116 # Once current class completed, check descendants
117 yield from super().generate_tests()
118
119
120class BignumCmp(BignumOperation):
121 """Target for bignum comparison test cases."""
122 count = 0
Werner Lewis70d3f3d2022-08-23 14:21:53 +0100123 test_function = "mbedtls_mpi_cmp_mpi"
124 test_name = "MPI compare"
Werner Lewis545911f2022-07-08 13:54:57 +0100125 input_cases = [
126 ("-2", "-3"),
127 ("-2", "-2"),
128 ("2b4", "2b5"),
129 ("2b5", "2b6")
130 ]
131
132 def __init__(self, val_l, val_r):
133 super().__init__(val_l, val_r)
Werner Lewis1c2a7322022-08-24 16:37:44 +0100134 self._result = int(self.int_l > self.int_r) - int(self.int_l < self.int_r)
Werner Lewis70d3f3d2022-08-23 14:21:53 +0100135 self.symbol = ["<", "==", ">"][self._result + 1]
Werner Lewis545911f2022-07-08 13:54:57 +0100136
Werner Lewis545911f2022-07-08 13:54:57 +0100137 def result(self):
138 return str(self._result)
139
140
Werner Lewis423f99b2022-07-18 15:49:43 +0100141class BignumCmpAbs(BignumCmp):
142 """Target for abs comparison variant."""
143 count = 0
Werner Lewis70d3f3d2022-08-23 14:21:53 +0100144 test_function = "mbedtls_mpi_cmp_abs"
145 test_name = "MPI compare (abs)"
Werner Lewis423f99b2022-07-18 15:49:43 +0100146
147 def __init__(self, val_l, val_r):
148 super().__init__(val_l.strip("-"), val_r.strip("-"))
149
150
Werner Lewis5c1173b2022-07-18 17:22:58 +0100151class BignumAdd(BignumOperation):
152 """Target for bignum addition test cases."""
153 count = 0
Werner Lewis70d3f3d2022-08-23 14:21:53 +0100154 test_function = "mbedtls_mpi_add_mpi"
155 test_name = "MPI add"
Werner Lewis5c1173b2022-07-18 17:22:58 +0100156 input_cases = list(itertools.combinations(
157 [
158 "1c67967269c6", "9cde3",
159 "-1c67967269c6", "-9cde3",
160 ], 2
161 ))
162
163 def __init__(self, val_l, val_r):
164 super().__init__(val_l, val_r)
Werner Lewis70d3f3d2022-08-23 14:21:53 +0100165 self.symbol = "+"
Werner Lewis5c1173b2022-07-18 17:22:58 +0100166
Werner Lewis5c1173b2022-07-18 17:22:58 +0100167 def result(self):
168 return quote_str(hex(self.int_l + self.int_r).replace("0x", "", 1))
169
170
Werner Lewisdcad1e92022-08-24 11:30:03 +0100171class BignumTestGenerator(test_generation.TestGenerator):
172 """Test generator subclass including bignum targets."""
Werner Lewis545911f2022-07-08 13:54:57 +0100173 TARGETS = {
Werner Lewis70d3f3d2022-08-23 14:21:53 +0100174 subclass.target_basename: subclass.generate_tests for subclass in
Werner Lewisdcad1e92022-08-24 11:30:03 +0100175 test_generation.BaseTarget.__subclasses__()
176 } # type: Dict[str, Callable[[], test_case.TestCase]]
Werner Lewis545911f2022-07-08 13:54:57 +0100177
178if __name__ == '__main__':
Werner Lewisdcad1e92022-08-24 11:30:03 +0100179 test_generation.main(sys.argv[1:], BignumTestGenerator)