1
0
mirror of https://github.com/Mbed-TLS/mbedtls.git synced 2025-07-28 00:21:48 +03:00

Merge pull request #6747 from gilles-peskine-arm/bignum-mod-random

Bignum mod random
This commit is contained in:
Manuel Pégourié-Gonnard
2022-12-23 10:36:22 +01:00
committed by GitHub
15 changed files with 909 additions and 175 deletions

View File

@ -15,6 +15,7 @@
# limitations under the License.
from abc import abstractmethod
import enum
from typing import Iterator, List, Tuple, TypeVar, Any
from itertools import chain
@ -53,7 +54,7 @@ def hex_to_int(val: str) -> int:
return 0
return int(val, 16)
def quote_str(val) -> str:
def quote_str(val: str) -> str:
return "\"{}\"".format(val)
def bound_mpi(val: int, bits_in_limb: int) -> int:
@ -139,7 +140,7 @@ class OperationCommon(test_data_generation.BaseTest):
def hex_digits(self) -> int:
return 2 * (self.limbs * self.bits_in_limb // 8)
def format_arg(self, val) -> str:
def format_arg(self, val: str) -> str:
if self.input_style not in self.input_styles:
raise ValueError("Unknown input style!")
if self.input_style == "variable":
@ -147,7 +148,7 @@ class OperationCommon(test_data_generation.BaseTest):
else:
return val.zfill(self.hex_digits)
def format_result(self, res) -> str:
def format_result(self, res: int) -> str:
res_str = '{:x}'.format(res)
return quote_str(self.format_arg(res_str))
@ -245,6 +246,23 @@ class OperationCommon(test_data_generation.BaseTest):
)
class ModulusRepresentation(enum.Enum):
"""Representation selector of a modulus."""
# Numerical values aligned with the type mbedtls_mpi_mod_rep_selector
INVALID = 0
MONTGOMERY = 2
OPT_RED = 3
def symbol(self) -> str:
"""The C symbol for this representation selector."""
return 'MBEDTLS_MPI_MOD_REP_' + self.name
@classmethod
def supported_representations(cls) -> List['ModulusRepresentation']:
"""Return all representations that are supported in positive test cases."""
return [cls.MONTGOMERY, cls.OPT_RED]
class ModOperationCommon(OperationCommon):
#pylint: disable=abstract-method
"""Target for bignum mod_raw test case generation."""
@ -266,6 +284,17 @@ class ModOperationCommon(OperationCommon):
def from_montgomery(self, val: int) -> int:
return (val * self.r_inv) % self.int_n
def convert_from_canonical(self, canonical: int,
rep: ModulusRepresentation) -> int:
"""Convert values from canonical representation to the given representation."""
if rep is ModulusRepresentation.MONTGOMERY:
return self.to_montgomery(canonical)
elif rep is ModulusRepresentation.OPT_RED:
return canonical
else:
raise ValueError('Modulus representation not supported: {}'
.format(rep.name))
@property
def boundary(self) -> int:
return self.int_n
@ -282,6 +311,9 @@ class ModOperationCommon(OperationCommon):
def arg_n(self) -> str:
return self.format_arg(self.val_n)
def format_arg(self, val: str) -> str:
return super().format_arg(val).zfill(self.hex_digits)
def arguments(self) -> List[str]:
return [quote_str(self.arg_n)] + super().arguments()

View File

@ -14,8 +14,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import Dict, List
from typing import Iterator, List
from . import test_case
from . import test_data_generation
from . import bignum_common
from .bignum_data import ONLY_PRIME_MODULI
@ -116,6 +117,88 @@ class BignumModRawAdd(bignum_common.ModOperationCommon,
# BEGIN MERGE SLOT 6
class BignumModRawConvertRep(bignum_common.ModOperationCommon,
BignumModRawTarget):
# This is an abstract class, it's ok to have unimplemented methods.
#pylint: disable=abstract-method
"""Test cases for representation conversion."""
symbol = ""
input_style = "arch_split"
arity = 1
rep = bignum_common.ModulusRepresentation.INVALID
def set_representation(self, r: bignum_common.ModulusRepresentation) -> None:
self.rep = r
def arguments(self) -> List[str]:
return ([bignum_common.quote_str(self.arg_n), self.rep.symbol(),
bignum_common.quote_str(self.arg_a)] +
self.result())
def description(self) -> str:
base = super().description()
mod_with_rep = 'mod({})'.format(self.rep.name)
return base.replace('mod', mod_with_rep, 1)
@classmethod
def test_cases_for_values(cls, rep: bignum_common.ModulusRepresentation,
n: str, a: str) -> Iterator[test_case.TestCase]:
"""Emit test cases for the given values (if any).
This may emit no test cases if a isn't valid for the modulus n,
or multiple test cases if rep requires different data depending
on the limb size.
"""
for bil in cls.limb_sizes:
test_object = cls(n, a, bits_in_limb=bil)
test_object.set_representation(rep)
# The class is set to having separate test cases for each limb
# size, because the Montgomery representation requires it.
# But other representations don't require it. So for other
# representations, emit a single test case with no dependency
# on the limb size.
if rep is not bignum_common.ModulusRepresentation.MONTGOMERY:
test_object.dependencies = \
[dep for dep in test_object.dependencies
if not dep.startswith('MBEDTLS_HAVE_INT')]
if test_object.is_valid:
yield test_object.create_test_case()
if rep is not bignum_common.ModulusRepresentation.MONTGOMERY:
# A single test case (emitted, or skipped due to invalidity)
# is enough, since this test case doesn't depend on the
# limb size.
break
# The parent class doesn't support non-bignum parameters. So we override
# test generation, in order to have the representation as a parameter.
@classmethod
def generate_function_tests(cls) -> Iterator[test_case.TestCase]:
for rep in bignum_common.ModulusRepresentation.supported_representations():
for n in cls.moduli:
for a in cls.input_values:
yield from cls.test_cases_for_values(rep, n, a)
class BignumModRawCanonicalToModulusRep(BignumModRawConvertRep):
"""Test cases for mpi_mod_raw_canonical_to_modulus_rep."""
test_function = "mpi_mod_raw_canonical_to_modulus_rep"
test_name = "Rep canon->mod"
def result(self) -> List[str]:
return [self.format_result(self.convert_from_canonical(self.int_a, self.rep))]
class BignumModRawModulusToCanonicalRep(BignumModRawConvertRep):
"""Test cases for mpi_mod_raw_modulus_to_canonical_rep."""
test_function = "mpi_mod_raw_modulus_to_canonical_rep"
test_name = "Rep mod->canon"
@property
def arg_a(self) -> str:
return self.format_arg("{:x}".format(self.convert_from_canonical(self.int_a, self.rep)))
def result(self) -> List[str]:
return [self.format_result(self.int_a)]
# END MERGE SLOT 6
# BEGIN MERGE SLOT 7