From b1db2ba3746d1ccad7e85ed033ca17e1fb4ffdff Mon Sep 17 00:00:00 2001 From: Felix Conway Date: Mon, 4 Aug 2025 11:14:22 +0100 Subject: [PATCH] Add generated tests for mpi_gcd_invmod_odd Signed-off-by: Felix Conway --- scripts/generate_bignum_tests.py | 138 +++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) diff --git a/scripts/generate_bignum_tests.py b/scripts/generate_bignum_tests.py index 74ad934a8..267fa6c9f 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 = bignum_common.expand_list_negative([ + "c79e27fc71c69a08b3e85bd48b9cd3be9aa8e2e56df39f4ed8", + "299dd34be98436729eb10f690f8d2bfc5bee21984b775e1e75", + "7da9ec44f42e6311c56a", + "cdbcce3f763819345cfb", + "100000000", "300000000", "500000000", + "50000", "30000", + "1", "2", "3", "", "00", + ]) + 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"), + ] + + @staticmethod + def get_return_code_gcd(int_a: int, int_b: int) -> str: + code = "0" + if (int_a > int_b) or \ + (int_a < 0) or \ + (int_b % 2 == 0): + code = "MBEDTLS_ERR_MPI_BAD_INPUT_DATA" + return code + + def get_return_code_invmod(self, int_a: int, int_b: int) -> str: + if int_b < 2: + return "MBEDTLS_ERR_MPI_BAD_INPUT_DATA" + return self.get_return_code_gcd(int_a, int_b) + + class BignumCmp(BignumOperation): """Test cases for bignum value comparison.""" count = 0 @@ -260,6 +325,79 @@ 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_invmod(self.int_a, self.int_b) + 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) + else: + self._result_invmod = -1 # No inverse + + def result(self) -> List[str]: + # The test requires us to tell it if there is no modular inverse. + if self._result_invmod == -1: + result_invmod = "no_inverse" + else: + result_invmod = "{:x}".format(self._result_invmod) + return [ + bignum_common.quote_str("{:x}".format(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(self.int_a, self.int_b) + # 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 [bignum_common.quote_str("{:x}".format(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_invmod(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 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) + else: + self._result_invmod = -1 # No inverse + + def result(self) -> List[str]: + # The test requires us to tell it if there is no modular inverse. + if self._result_invmod == -1: + return [bignum_common.quote_str("no_inverse"), self._result_code] + return [bignum_common.quote_str("{:x}".format(self._result_invmod)), self._result_code] + + class BignumAdd(BignumOperation): """Test cases for bignum value addition.""" count = 0