blob: f885167cfa717951d4d340461430ff5f860d9966 [file] [log] [blame]
Werner Lewis8b2df742022-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 Lewis8b2df742022-07-08 13:54:57 +010023import itertools
Werner Lewis8b2df742022-07-08 13:54:57 +010024import sys
Werner Lewisfbb75e32022-08-24 11:30:03 +010025from typing import Callable, Dict, Iterator, List, Optional, Tuple, TypeVar
Werner Lewis8b2df742022-07-08 13:54:57 +010026
27import scripts_path # pylint: disable=unused-import
Werner Lewis8b2df742022-07-08 13:54:57 +010028from mbedtls_dev import test_case
Werner Lewisfbb75e32022-08-24 11:30:03 +010029from mbedtls_dev import test_generation
Werner Lewis8b2df742022-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 Lewisfbb75e32022-08-24 11:30:03 +010040class BignumTarget(test_generation.BaseTarget):
Werner Lewis8b2df742022-07-08 13:54:57 +010041 """Target for bignum (mpi) test case generation."""
42 gen_file = 'test_suite_mpi.generated'
43
44
45class BignumOperation(BignumTarget):
46 """Common features for test cases covering bignum operations.
47
48 Attributes:
49 symb: Symbol used for operation in description.
50 input_vals: List of values used to generate test case args.
51 input_cases: List of tuples containing test case inputs. This
52 can be used to implement specific pairs of inputs.
53 """
54 symb = ""
55 input_vals = [
56 "", "0", "7b", "-7b",
57 "0000000000000000123", "-0000000000000000123",
58 "1230000000000000000", "-1230000000000000000"
Werner Lewisc442f6a2022-07-20 14:13:44 +010059 ] # type: List[str]
60 input_cases = [] # type: List[Tuple[str, ...]]
Werner Lewis8b2df742022-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
70 @property
71 def args(self):
72 return [quote_str(self.arg_l), quote_str(self.arg_r), self.result]
73
74 @property
75 def description(self):
76 desc = self.desc if self.desc else "{} {} {}".format(
77 self.val_desc(self.arg_l),
78 self.symb,
79 self.val_desc(self.arg_r)
80 )
81 return "{} #{} {}".format(self.title, self.count, desc)
82
83 @property
84 def result(self) -> Optional[str]:
85 return None
86
87 @staticmethod
88 def val_desc(val) -> str:
89 """Generate description of the argument val."""
90 if val == "":
91 return "0 (null)"
92 if val == "0":
93 return "0 (1 limb)"
94
95 if val[0] == "-":
96 tmp = "negative"
97 val = val[1:]
98 else:
99 tmp = "positive"
100 if val[0] == "0":
101 tmp += " with leading zero limb"
102 elif len(val) > 10:
103 tmp = "large " + tmp
104 return tmp
105
106 @classmethod
107 def get_value_pairs(cls) -> Iterator[Tuple[str, ...]]:
108 """Generate value pairs."""
Werner Lewisb17ca8a2022-07-20 13:35:53 +0100109 for pair in list(
Werner Lewis6a313962022-07-20 15:16:50 +0100110 itertools.combinations(cls.input_vals, 2)
Werner Lewisb17ca8a2022-07-20 13:35:53 +0100111 ) + cls.input_cases:
Werner Lewis8b2df742022-07-08 13:54:57 +0100112 yield pair
113
114 @classmethod
115 def generate_tests(cls) -> Iterator[test_case.TestCase]:
Werner Lewis265e0512022-07-20 14:45:23 +0100116 if cls.func:
Werner Lewis8b2df742022-07-08 13:54:57 +0100117 # Generate tests for the current class
118 for l_value, r_value in cls.get_value_pairs():
119 cur_op = cls(l_value, r_value)
120 yield cur_op.create_test_case()
121 # Once current class completed, check descendants
122 yield from super().generate_tests()
123
124
125class BignumCmp(BignumOperation):
126 """Target for bignum comparison test cases."""
127 count = 0
128 func = "mbedtls_mpi_cmp_mpi"
129 title = "MPI compare"
130 input_cases = [
131 ("-2", "-3"),
132 ("-2", "-2"),
133 ("2b4", "2b5"),
134 ("2b5", "2b6")
135 ]
136
137 def __init__(self, val_l, val_r):
138 super().__init__(val_l, val_r)
139 self._result = (self.int_l > self.int_r) - (self.int_l < self.int_r)
140 self.symb = ["<", "==", ">"][self._result + 1]
141
142 @property
143 def result(self):
144 return str(self._result)
145
146
Werner Lewis69a92ce2022-07-18 15:49:43 +0100147class BignumCmpAbs(BignumCmp):
148 """Target for abs comparison variant."""
149 count = 0
150 func = "mbedtls_mpi_cmp_abs"
151 title = "MPI compare (abs)"
152
153 def __init__(self, val_l, val_r):
154 super().__init__(val_l.strip("-"), val_r.strip("-"))
155
156
Werner Lewis86caf852022-07-18 17:22:58 +0100157class BignumAdd(BignumOperation):
158 """Target for bignum addition test cases."""
159 count = 0
160 func = "mbedtls_mpi_add_mpi"
161 title = "MPI add"
162 input_cases = list(itertools.combinations(
163 [
164 "1c67967269c6", "9cde3",
165 "-1c67967269c6", "-9cde3",
166 ], 2
167 ))
168
169 def __init__(self, val_l, val_r):
170 super().__init__(val_l, val_r)
171 self.symb = "+"
172
173 @property
174 def result(self):
175 return quote_str(hex(self.int_l + self.int_r).replace("0x", "", 1))
176
177
Werner Lewisfbb75e32022-08-24 11:30:03 +0100178class BignumTestGenerator(test_generation.TestGenerator):
179 """Test generator subclass including bignum targets."""
Werner Lewis8b2df742022-07-08 13:54:57 +0100180 TARGETS = {
181 subclass.gen_file: subclass.generate_tests for subclass in
Werner Lewisfbb75e32022-08-24 11:30:03 +0100182 test_generation.BaseTarget.__subclasses__()
183 } # type: Dict[str, Callable[[], test_case.TestCase]]
Werner Lewis8b2df742022-07-08 13:54:57 +0100184
185if __name__ == '__main__':
Werner Lewisfbb75e32022-08-24 11:30:03 +0100186 test_generation.main(sys.argv[1:], BignumTestGenerator)