mirror of
https://github.com/henrydcase/pqc.git
synced 2024-11-30 03:11:43 +00:00
9e4d07dba1
* don't do filesystem operations during collection * Greatly speed up test collection * fixup! Greatly speed up test collection * Silence junit warning * fixup! Greatly speed up test collection
209 lines
6.3 KiB
Python
209 lines
6.3 KiB
Python
import glob
|
|
import os
|
|
from typing import Optional
|
|
from functools import lru_cache
|
|
|
|
import yaml
|
|
import platform
|
|
import helpers
|
|
|
|
|
|
class Scheme:
|
|
def __init__(self):
|
|
self.type = None
|
|
self.name = None
|
|
self.implementations = []
|
|
|
|
def path(self, base='..'):
|
|
return os.path.join(base, 'crypto_' + self.type, self.name)
|
|
|
|
def namespace_prefix(self):
|
|
return 'PQCLEAN_{}_'.format(self.name.upper()).replace('-', '')
|
|
|
|
@staticmethod
|
|
@lru_cache(maxsize=None)
|
|
def by_name(scheme_name):
|
|
for scheme in Scheme.all_schemes():
|
|
if scheme.name == scheme_name:
|
|
return scheme
|
|
raise KeyError()
|
|
|
|
@staticmethod
|
|
@lru_cache(maxsize=1)
|
|
def all_schemes():
|
|
schemes = []
|
|
schemes.extend(Scheme.all_schemes_of_type('kem'))
|
|
schemes.extend(Scheme.all_schemes_of_type('sign'))
|
|
return schemes
|
|
|
|
@staticmethod
|
|
@lru_cache(maxsize=1)
|
|
def all_implementations():
|
|
implementations = []
|
|
for scheme in Scheme.all_schemes():
|
|
implementations.extend(scheme.implementations)
|
|
return implementations
|
|
|
|
@staticmethod
|
|
@lru_cache(maxsize=1)
|
|
def all_supported_implementations():
|
|
return [impl for impl in Scheme.all_implementations()
|
|
if impl.supported_on_current_platform()]
|
|
|
|
@staticmethod
|
|
@lru_cache(maxsize=32)
|
|
def all_schemes_of_type(type: str) -> list:
|
|
schemes = []
|
|
p = os.path.join('..', 'crypto_' + type)
|
|
if os.path.isdir(p):
|
|
for d in os.listdir(p):
|
|
if os.path.isdir(os.path.join(p, d)):
|
|
if type == 'kem':
|
|
schemes.append(KEM(d))
|
|
elif type == 'sign':
|
|
schemes.append(Signature(d))
|
|
else:
|
|
assert('Unknown type')
|
|
return schemes
|
|
|
|
@lru_cache(maxsize=None)
|
|
def metadata(self):
|
|
metafile = os.path.join(self.path(), 'META.yml')
|
|
try:
|
|
with open(metafile, encoding='utf-8') as f:
|
|
metadata = yaml.safe_load(f)
|
|
return metadata
|
|
except Exception as e:
|
|
print("Can't open {}: {}".format(metafile, e))
|
|
return None
|
|
|
|
def __repr__(self):
|
|
return "<{}({})>".format(self.type.title(), self.name)
|
|
|
|
|
|
class Implementation:
|
|
|
|
def __init__(self, scheme, name):
|
|
self.scheme = scheme
|
|
self.name = name
|
|
|
|
@lru_cache(maxsize=None)
|
|
def metadata(self):
|
|
for i in self.scheme.metadata()['implementations']:
|
|
if i['name'] == self.name:
|
|
return i
|
|
|
|
def path(self, base='..') -> str:
|
|
return os.path.join(self.scheme.path(base=base), self.name)
|
|
|
|
def libname(self) -> str:
|
|
if os.name == 'nt':
|
|
return "lib{}_{}.lib".format(self.scheme.name, self.name)
|
|
return "lib{}_{}.a".format(self.scheme.name, self.name)
|
|
|
|
def cfiles(self) -> [str]:
|
|
return glob.glob(os.path.join(self.path(), '*.c'))
|
|
|
|
def hfiles(self) -> [str]:
|
|
return glob.glob(os.path.join(self.path(), '*.h'))
|
|
|
|
def ofiles(self) -> [str]:
|
|
return glob.glob(os.path.join(self.path(),
|
|
'*.o' if os.name != 'nt' else '*.obj'))
|
|
|
|
@staticmethod
|
|
@lru_cache(maxsize=None)
|
|
def by_name(scheme_name, implementation_name):
|
|
scheme = Scheme.by_name(scheme_name)
|
|
for implementation in scheme.implementations:
|
|
if implementation.name == implementation_name:
|
|
return implementation
|
|
raise KeyError()
|
|
|
|
@staticmethod
|
|
@lru_cache(maxsize=None)
|
|
def all_implementations(scheme: Scheme) -> list:
|
|
implementations = []
|
|
for d in os.listdir(scheme.path()):
|
|
if os.path.isdir(os.path.join(scheme.path(), d)):
|
|
implementations.append(Implementation(scheme, d))
|
|
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):
|
|
return '{}{}_'.format(self.scheme.namespace_prefix(),
|
|
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
|
|
|
|
@lru_cache(maxsize=10000)
|
|
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
|
|
|
|
cpuinfo = helpers.get_cpu_info()
|
|
|
|
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):
|
|
return "{} implementation of {}".format(self.name, self.scheme.name)
|
|
|
|
def __repr__(self):
|
|
return "<Implementation({}, {})>".format(self.scheme.name, self.name)
|
|
|
|
|
|
class KEM(Scheme):
|
|
|
|
def __init__(self, name: str):
|
|
self.type = 'kem'
|
|
self.name = name
|
|
self.implementations = Implementation.all_implementations(self)
|
|
|
|
@staticmethod
|
|
def all_kems() -> list:
|
|
return Scheme.all_schemes_of_type('kem')
|
|
|
|
|
|
class Signature(Scheme):
|
|
|
|
def __init__(self, name: str):
|
|
self.type = 'sign'
|
|
self.name = name
|
|
self.implementations = Implementation.all_implementations(self)
|
|
|
|
@staticmethod
|
|
def all_sigs():
|
|
return Scheme.all_schemes_of_type('sign')
|