diff --git a/scripts/generate_bignum_tests.py b/scripts/generate_bignum_tests.py index 74ad934a8..cfafc5658 100755 --- a/scripts/generate_bignum_tests.py +++ b/scripts/generate_bignum_tests.py @@ -122,6 +122,71 @@ class BignumOperation(bignum_common.OperationCommon, BignumTarget, return tmp +class BignumGCDInvModOperation(BignumOperation): + #pylint: disable=abstract-method + """Common features for testing GCD and Invmod functions.""" + def __init__(self, val_a: str, val_b: str) -> None: + super().__init__(val_a=val_a, val_b=val_b) + + def description_suffix(self) -> str: + comparison_symbol = '=' + if abs(self.int_a) > abs(self.int_b): + comparison_symbol = '>' + elif abs(self.int_a) < abs(self.int_b): + comparison_symbol = '<' + suffix_parts = [ + f"|A|{comparison_symbol}|N|", + *(["A<0"] if self.int_a < 0 else []), + *(["N<0"] if self.int_b < 0 else []), + "A=0" if self.int_a == 0 else f"A {'even' if self.int_a % 2 == 0 else 'odd'}", + "N=0" if self.int_b == 0 else f"B {'even' if self.int_b % 2 == 0 else 'odd'}" + ] + return ": " + ", ".join(suffix_parts) + + # The default values from BignumOperation are not useful, so overwrite them. + input_values = [ + "c79e27fc71c69a08b3e85bd48b9cd3be9aa8e2e56df39f4ed8", + "299dd34be98436729eb10f690f8d2bfc5bee21984b775e1e75", + "-ecbb3a4e986d488172ecd54f7bd71bd18050c4ed", + "7da9ec44f42e6311c56a", + "cdbcce3f763819345cfb", + "100000000", "300000000", "500000000", + "50000", "30000", + "1", "2", "3", "", "00", "-1" + ] + input_cases = [ + ("bc7fa9fb389618302e8b", "d49730e586607d42269f"), + ("28bcc01a2d54b174532e", "d1915057d829a934c25d"), + ("d56b50834719280dfa1d", "f007b78f6278ebcccd57"), + ("8c327d1d8743c89d4483", "aa20b0c1f97a428311b5"), + ("e905382f38", "c844b4f9bdaa5ed0002df3dbd2991cd9b9d"), + ("e4623ef13d", "f2a4894ede013e354e481fe8974e67"), + ("9f6afa8bdb", "b50aa03a7066df6f27bd6267b"), + ("95f99b7122", "e8c74031ec75839f7539"), + ("32", "948fbec067"), + ("7445", "948fbec067"), + ("31850e", "948fbec067"), + ("421c2cc8", "948fbec067"), + ("32a69", "71e107"), + ("36d4e9", "3e05d1"), + ("babf01", "1bf699d1"), + ("7", "31"), + ] + + def get_return_code_gcd_modinv_odd_gcd_only(self) -> str: + code = "0" + if (self.int_a > self.int_b) or \ + (self.int_a < 0) or \ + (self.int_b % 2 == 0): + code = "MBEDTLS_ERR_MPI_BAD_INPUT_DATA" + return code + + def get_return_code_gcd_modinv_odd(self) -> str: + if self.int_b < 2: + return "MBEDTLS_ERR_MPI_BAD_INPUT_DATA" + return self.get_return_code_gcd_modinv_odd_gcd_only() + + class BignumCmp(BignumOperation): """Test cases for bignum value comparison.""" count = 0 @@ -260,6 +325,81 @@ class BignumGCD(BignumOperation): return [bignum_common.quote_str("{:x}".format(self._result))] +class BignumGCDModInvOdd(BignumGCDInvModOperation): + """Test cases for both modular inverse and greatest common divisor.""" + count = 0 + symbol = "GCD & ^-1 mod" + test_function = "mpi_gcd_modinv_odd_both" + test_name = "GCD & mod inv" + + def __init__(self, val_a: str, val_b: str) -> None: + super().__init__(val_a, val_b) + self._result_code = self.get_return_code_gcd_modinv_odd() + self._result_gcd = math.gcd(self.int_a, self.int_b) + # Only compute the modular inverse if we will get a result - negative + # and zero Ns are also present in the test data so skip them too. + if self._result_gcd == 1 and self.int_b > 1: + self._result_invmod = \ + bignum_common.invmod_positive(self.int_a, self.int_b) # type: int | None + else: + self._result_invmod = None # No inverse + + def result(self) -> List[str]: + # The test requires us to tell it if there is no modular inverse. + if self._result_invmod is None: + result_invmod = "no_inverse" + else: + result_invmod = "{:x}".format(self._result_invmod) + return [ + self.format_result(self._result_gcd), + bignum_common.quote_str(result_invmod), + self._result_code, + ] + + +class BignumGCDModInvOddOnlyGCD(BignumGCDInvModOperation): + """Test cases for greatest common divisor only.""" + count = 0 + symbol = "GCD" + test_function = "mpi_gcd_modinv_odd_only_gcd" + test_name = "GCD only" + + def __init__(self, val_a: str, val_b: str) -> None: + super().__init__(val_a, val_b) + self._result_code = self.get_return_code_gcd_modinv_odd_gcd_only() + # We always expect a positive result as the function should reject + # negative inputs. + self._result_gcd = math.gcd(self.int_a, self.int_b) + + def result(self) -> List[str]: + return [self.format_result(self._result_gcd), self._result_code] + + +class BignumGCDModInvOddOnlyModInv(BignumGCDInvModOperation): + """Test cases for modular inverse only.""" + count = 0 + symbol = "^-1 mod" + test_function = "mpi_gcd_modinv_odd_only_modinv" + test_name = "Mod inv only" + + def __init__(self, val_a: str, val_b: str) -> None: + super().__init__(val_a, val_b) + self._result_code = self.get_return_code_gcd_modinv_odd() + # Only compute the modular inverse if we will get a result - negative + # and zero Ns are also present in the test data so skip them too. + if math.gcd(self.int_a, self.int_b) == 1 and self.int_b > 1: + self._result_invmod = \ + bignum_common.invmod_positive(self.int_a, self.int_b) # type: int | None + else: + self._result_invmod = None # No inverse + + def result(self) -> List[str]: + # The test requires us to tell it if there is no modular inverse. + if self._result_invmod is None: + return [bignum_common.quote_str("no_inverse"), self._result_code] + return [self.format_result(self._result_invmod), self._result_code] + + class BignumAdd(BignumOperation): """Test cases for bignum value addition.""" count = 0