1
1
mirror of https://github.com/henrydcase/pqc.git synced 2024-11-22 23:48:58 +00:00

Add support for specifying architecture and feature limits (#224)

* Add support for specifying architecture and feature limits

* cpuinfo not supported on ppc

* Detect 32-bit python interpreter on 64-bit CPU

* Fix bugs in isolated tests

* Also support restricting operating system
This commit is contained in:
Thom Wiggers 2019-09-06 12:01:44 +02:00 committed by Matthias J. Kannwischer
parent aa46b5239d
commit 2eaf382689
15 changed files with 117 additions and 21 deletions

View File

@ -2,3 +2,4 @@ PyYAML
pytest pytest
pytest-xdist pytest-xdist
pycparser pycparser
py-cpuinfo

View File

@ -69,7 +69,7 @@ $(DEST_DIR)/testvectors_$(SCHEME)_$(IMPLEMENTATION): build-scheme crypto_$(TYPE)
mkdir -p $(DEST_DIR) mkdir -p $(DEST_DIR)
$(CC) $(CFLAGS) -DPQCLEAN_NAMESPACE=PQCLEAN_$(SCHEME_UPPERCASE)_$(IMPLEMENTATION_UPPERCASE) -I$(SCHEME_DIR) crypto_$(TYPE)/testvectors.c $(COMMON_FILES) $(TEST_COMMON_DIR)/notrandombytes.c -o $@ -L$(SCHEME_DIR) -l$(SCHEME)_$(IMPLEMENTATION) $(CC) $(CFLAGS) -DPQCLEAN_NAMESPACE=PQCLEAN_$(SCHEME_UPPERCASE)_$(IMPLEMENTATION_UPPERCASE) -I$(SCHEME_DIR) crypto_$(TYPE)/testvectors.c $(COMMON_FILES) $(TEST_COMMON_DIR)/notrandombytes.c -o $@ -L$(SCHEME_DIR) -l$(SCHEME)_$(IMPLEMENTATION)
$(DEST_DIR)/printparams_$(SCHEME)_$(IMPLEMENTATION): build-scheme crypto_$(TYPE)/printparams.c $(DEST_DIR)/printparams_$(SCHEME)_$(IMPLEMENTATION): crypto_$(TYPE)/printparams.c
mkdir -p $(DEST_DIR) mkdir -p $(DEST_DIR)
$(CC) $(CFLAGS) -DPQCLEAN_NAMESPACE=PQCLEAN_$(SCHEME_UPPERCASE)_$(IMPLEMENTATION_UPPERCASE) -I$(SCHEME_DIR) crypto_$(TYPE)/printparams.c -o $@ $(CC) $(CFLAGS) -DPQCLEAN_NAMESPACE=PQCLEAN_$(SCHEME_UPPERCASE)_$(IMPLEMENTATION_UPPERCASE) -I$(SCHEME_DIR) crypto_$(TYPE)/printparams.c -o $@

View File

@ -1,7 +1,9 @@
import glob import glob
import os import os
from typing import Optional
import yaml import yaml
import platform
class Scheme: class Scheme:
@ -37,6 +39,11 @@ class Scheme:
implementations.extend(scheme.implementations) implementations.extend(scheme.implementations)
return implementations return implementations
@staticmethod
def all_supported_implementations():
return [impl for impl in Scheme.all_implementations()
if impl.supported_on_current_platform()]
@staticmethod @staticmethod
def all_schemes_of_type(type: str) -> list: def all_schemes_of_type(type: str) -> list:
schemes = [] schemes = []
@ -111,10 +118,57 @@ class Implementation:
implementations.append(Implementation(scheme, d)) implementations.append(Implementation(scheme, d))
return implementations return implementations
@staticmethod
def all_supported_implementations(scheme: Scheme) -> list:
return [impl for impl in Implementation.all_implementations(scheme)
if impl.supported_on_current_platform()]
def namespace_prefix(self): def namespace_prefix(self):
return '{}{}_'.format(self.scheme.namespace_prefix(), return '{}{}_'.format(self.scheme.namespace_prefix(),
self.name.upper()).replace('-', '') self.name.upper()).replace('-', '')
def supported_on_os(self, os: Optional[str] = None) -> bool:
"""Check if we support the OS
If no OS is specified, then we run on the current OS
"""
if os is None:
os = platform.system()
for platform_ in self.metadata().get('supported_platforms', []):
if 'operating_systems' in platform_:
if os not in platform_['operating_systems']:
return False
return True
def supported_on_current_platform(self) -> bool:
if 'supported_platforms' not in self.metadata():
return True
if platform.machine() == 'ppc':
return False
if not self.supported_on_os():
return False
if not hasattr(Implementation, 'CPUINFO'):
import cpuinfo
Implementation.CPUINFO = cpuinfo.get_cpu_info()
CPUINFO = Implementation.CPUINFO
for platform_ in self.metadata()['supported_platforms']:
if platform_['architecture'] == CPUINFO['arch'].lower():
# Detect actually running on emulated i386
if (platform_['architecture'] == 'x86_64' and
platform.architecture()[0] == '32bit'):
continue
if all([flag in CPUINFO['flags']
for flag in platform_['required_flags']]):
return True
return False
def __str__(self): def __str__(self):
return "{} implementation of {}".format(self.name, self.scheme.name) return "{} implementation of {}".format(self.name, self.scheme.name)

View File

@ -11,8 +11,8 @@ import pqclean
@pytest.mark.parametrize( @pytest.mark.parametrize(
'implementation,test_dir,impl_dir, init, destr', 'implementation,test_dir,impl_dir, init, destr',
[(impl, *helpers.isolate_test_files(impl.path(), 'test_functest_')) [(impl, *helpers.isolate_test_files(impl.path(), 'test_functest_'))
for impl in pqclean.Scheme.all_implementations()], for impl in pqclean.Scheme.all_supported_implementations()],
ids=[str(impl) for impl in pqclean.Scheme.all_implementations()], ids=[str(impl) for impl in pqclean.Scheme.all_supported_implementations()],
) )
@helpers.filtered_test @helpers.filtered_test
def test_compile_lib(implementation, test_dir, impl_dir, init, destr): def test_compile_lib(implementation, test_dir, impl_dir, init, destr):

View File

@ -11,8 +11,8 @@ import pqclean
@pytest.mark.parametrize( @pytest.mark.parametrize(
'implementation,test_dir,impl_path, init, destr', 'implementation,test_dir,impl_path, init, destr',
[(impl, *helpers.isolate_test_files(impl.path(), 'test_functest_')) [(impl, *helpers.isolate_test_files(impl.path(), 'test_functest_'))
for impl in pqclean.Scheme.all_implementations()], for impl in pqclean.Scheme.all_supported_implementations()],
ids=[str(impl) for impl in pqclean.Scheme.all_implementations()], ids=[str(impl) for impl in pqclean.Scheme.all_supported_implementations()],
) )
@helpers.skip_windows() @helpers.skip_windows()
@helpers.filtered_test @helpers.filtered_test

View File

@ -16,8 +16,8 @@ import pqclean
@pytest.mark.parametrize( @pytest.mark.parametrize(
'implementation,test_dir,impl_path, init, destr', 'implementation,test_dir,impl_path, init, destr',
[(impl, *helpers.isolate_test_files(impl.path(), 'test_functest_')) [(impl, *helpers.isolate_test_files(impl.path(), 'test_functest_'))
for impl in pqclean.Scheme.all_implementations()], for impl in pqclean.Scheme.all_supported_implementations()],
ids=[str(impl) for impl in pqclean.Scheme.all_implementations()], ids=[str(impl) for impl in pqclean.Scheme.all_supported_implementations()],
) )
@helpers.filtered_test @helpers.filtered_test
def test_functest(implementation, impl_path, test_dir, def test_functest(implementation, impl_path, test_dir,
@ -45,8 +45,8 @@ def test_functest(implementation, impl_path, test_dir,
'implementation,test_dir,impl_path, init, destr', 'implementation,test_dir,impl_path, init, destr',
[(impl, [(impl,
*helpers.isolate_test_files(impl.path(), 'test_functest_sanitizers_')) *helpers.isolate_test_files(impl.path(), 'test_functest_sanitizers_'))
for impl in pqclean.Scheme.all_implementations()], for impl in pqclean.Scheme.all_supported_implementations()],
ids=[str(impl) for impl in pqclean.Scheme.all_implementations()], ids=[str(impl) for impl in pqclean.Scheme.all_supported_implementations()],
) )
@helpers.skip_windows() @helpers.skip_windows()
@helpers.filtered_test @helpers.filtered_test

View File

@ -13,7 +13,7 @@ additional_flags = [] #['-fix-errors']
@pytest.mark.parametrize( @pytest.mark.parametrize(
'implementation', 'implementation',
pqclean.Scheme.all_implementations(), pqclean.Scheme.all_supported_implementations(),
ids=str, ids=str,
) )
@helpers.skip_windows() @helpers.skip_windows()

View File

@ -17,8 +17,8 @@ import pqclean
'implementation,test_dir,impl_path, init, destr', 'implementation,test_dir,impl_path, init, destr',
[(impl, [(impl,
*helpers.isolate_test_files(impl.path(), 'test_makefile_deps_')) *helpers.isolate_test_files(impl.path(), 'test_makefile_deps_'))
for impl in pqclean.Scheme.all_implementations()], for impl in pqclean.Scheme.all_supported_implementations()],
ids=[str(impl) for impl in pqclean.Scheme.all_implementations()], ids=[str(impl) for impl in pqclean.Scheme.all_supported_implementations()],
) )
@helpers.filtered_test @helpers.filtered_test
def test_makefile_dependencies(implementation, impl_path, test_dir, def test_makefile_dependencies(implementation, impl_path, test_dir,

View File

@ -17,10 +17,23 @@ import pqclean
ids=str, ids=str,
) )
@helpers.filtered_test @helpers.filtered_test
def test_makefiles_present(implementation): def test_makefile_present(implementation):
p1 = os.path.join(implementation.path(), 'Makefile') p1 = os.path.join(implementation.path(), 'Makefile')
assert os.path.isfile(p1)
@pytest.mark.parametrize(
'implementation',
pqclean.Scheme.all_implementations(),
ids=str,
)
@helpers.filtered_test
def test_microsoft_nmakefile_present(implementation):
p2 = os.path.join(implementation.path(), 'Makefile.Microsoft_nmake') p2 = os.path.join(implementation.path(), 'Makefile.Microsoft_nmake')
assert(os.path.isfile(p1) and os.path.isfile(p2)) if implementation.supported_on_os(os='Windows'):
assert os.path.isfile(p2)
else:
assert not os.path.isfile(p2), "Should not have an NMake file"
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -61,6 +61,31 @@ EXPECTED_FIELDS = {
'spec': { 'spec': {
'name': {'type': str}, 'name': {'type': str},
'version': {'type': str}, 'version': {'type': str},
'supported_platforms': {
'type': list,
'optional': True,
'elements': {
'type': dict,
'spec': {
'architecture': {
'type': str,
'values': ['x86', 'x86_64', 'aarch64']},
'required_flags': {
'type': list,
'optional': True,
'elements': {'type': str},
},
'operating_systems': {
'type': list,
'optional': True,
'elements': {
'type': str,
'values': ['Linux', 'Windows', 'Darwin'],
},
},
},
},
},
}, },
}, },
}, },

View File

@ -9,7 +9,7 @@ import pqclean
@pytest.mark.parametrize( @pytest.mark.parametrize(
'implementation,test_dir,impl_path, init, destr', 'implementation,test_dir,impl_path, init, destr',
[(impl, *helpers.isolate_test_files(impl.path(), 'test_functest_')) [(impl, *helpers.isolate_test_files(impl.path(), 'test_printparams_'))
for impl in pqclean.Scheme.all_implementations()], for impl in pqclean.Scheme.all_implementations()],
ids=[str(impl) for impl in pqclean.Scheme.all_implementations()], ids=[str(impl) for impl in pqclean.Scheme.all_implementations()],
) )

View File

@ -20,8 +20,8 @@ import pqclean
@pytest.mark.parametrize( @pytest.mark.parametrize(
'implementation,test_dir,impl_path, init, destr', 'implementation,test_dir,impl_path, init, destr',
[(impl, *helpers.isolate_test_files(impl.path(), 'test_functest_')) [(impl, *helpers.isolate_test_files(impl.path(), 'test_functest_'))
for impl in pqclean.Scheme.all_implementations()], for impl in pqclean.Scheme.all_supported_implementations()],
ids=[str(impl) for impl in pqclean.Scheme.all_implementations()], ids=[str(impl) for impl in pqclean.Scheme.all_supported_implementations()],
) )
@helpers.filtered_test @helpers.filtered_test
def test_nistkat(implementation, impl_path, test_dir, init, destr): def test_nistkat(implementation, impl_path, test_dir, init, destr):

View File

@ -16,8 +16,8 @@ import pqclean
'implementation,test_dir,impl_path,init,destr', 'implementation,test_dir,impl_path,init,destr',
[(impl, [(impl,
*helpers.isolate_test_files(impl.path(), 'test_symbol_ns_')) *helpers.isolate_test_files(impl.path(), 'test_symbol_ns_'))
for impl in pqclean.Scheme.all_implementations()], for impl in pqclean.Scheme.all_supported_implementations()],
ids=[str(impl) for impl in pqclean.Scheme.all_implementations()], ids=[str(impl) for impl in pqclean.Scheme.all_supported_implementations()],
) )
@helpers.filtered_test @helpers.filtered_test
def test_symbol_namespaces(implementation, impl_path, test_dir, init, destr): def test_symbol_namespaces(implementation, impl_path, test_dir, init, destr):

View File

@ -5,6 +5,7 @@ the one provided in the META file for every scheme/implementation.
import hashlib import hashlib
import os import os
import unittest
import pytest import pytest
@ -22,6 +23,8 @@ import pqclean
) )
@helpers.filtered_test @helpers.filtered_test
def test_testvectors(implementation, impl_path, test_dir, init, destr): def test_testvectors(implementation, impl_path, test_dir, init, destr):
if not implementation.supported_on_current_platform():
raise unittest.SkipTest("Not supported on current platform")
init() init()
dest_dir = os.path.join(test_dir, 'bin') dest_dir = os.path.join(test_dir, 'bin')
helpers.make('testvectors', helpers.make('testvectors',

View File

@ -27,8 +27,8 @@ def valgrind_supports_exit_early():
@pytest.mark.parametrize( @pytest.mark.parametrize(
'implementation,test_dir,impl_path, init, destr', 'implementation,test_dir,impl_path, init, destr',
[(impl, *helpers.isolate_test_files(impl.path(), 'test_functest_')) [(impl, *helpers.isolate_test_files(impl.path(), 'test_functest_'))
for impl in pqclean.Scheme.all_implementations()], for impl in pqclean.Scheme.all_supported_implementations()],
ids=[str(impl) for impl in pqclean.Scheme.all_implementations()], ids=[str(impl) for impl in pqclean.Scheme.all_supported_implementations()],
) )
@helpers.slow_test @helpers.slow_test
@helpers.filtered_test @helpers.filtered_test