def test_valgrind(implementation: pqclean.Implementation, impl_path, test_dir, init, destr): if (platform.machine() not in ('i386', 'x86_64') or platform.system() != 'Linux'): raise unittest.SkipTest() init() dest_dir = os.path.join(test_dir, 'bin') helpers.make(TYPE=implementation.scheme.type, SCHEME=implementation.scheme.name, SCHEME_DIR=os.path.abspath(impl_path), IMPLEMENTATION=implementation.name, DEST_DIR=dest_dir, EXTRAFLAGS="-g3", NTESTS=1, working_dir=os.path.join(test_dir, 'test')) functest_name = './functest_{}_{}'.format(implementation.scheme.name, implementation.name) helpers.run_subprocess([ 'valgrind', '--error-exitcode=1', '--leak-check=yes', *(['--exit-on-first-error=yes'] if valgrind_supports_exit_early() else []), '--max-stackframe=20933064', '--vex-guest-max-insns=25', functest_name ], dest_dir) destr()
def check_metadata_sizes(implementation): metadata = implementation.scheme.metadata() impl_meta = next((impl for impl in metadata['implementations'] if impl['name'] == implementation.name), None) helpers.make('printparams', TYPE=implementation.scheme.type, SCHEME=implementation.scheme.name, IMPLEMENTATION=implementation.name, working_dir=os.path.join('..', 'test')) out = helpers.run_subprocess( [ os.path.join( '..', 'bin', 'printparams_{}_{}{}'.format( implementation.scheme.name, implementation.name, '.exe' if os.name == 'nt' else '')) ], os.path.join('..', 'bin'), ).replace('\r', '') parsed = json.loads(out) assert parsed['CRYPTO_SECRETKEYBYTES'] == impl_meta['length-secret-key'] assert parsed['CRYPTO_PUBLICKEYBYTES'] == metadata['length-public-key'] if implementation.scheme.type == 'kem': assert ( parsed['CRYPTO_CIPHERTEXTBYTES'] == metadata['length-ciphertext']) assert parsed['CRYPTO_BYTES'] == metadata['length-shared-secret'] else: assert parsed['CRYPTO_BYTES'] == metadata['length-signature']
def check_symbol_namespace(implementation): if sys.platform not in ['linux', 'darwin']: raise unittest.SkipTest("Unsupported platform") helpers.make(working_dir=implementation.path()) out = helpers.run_subprocess( ['nm', '-g', implementation.libname()], implementation.path() ) lines = out.strip().split("\n") symbols = [] for line in lines: if ' T ' in line or ' D ' in line or ' S ' in line: symbols.append(line) namespace = implementation.namespace_prefix() non_namespaced = [] for symbolstr in symbols: *_, symtype, symbol = symbolstr.split() if symtype in 'TR': if (not symbol.startswith(namespace) and # weird things on i386 not symbol.startswith('__x86.get_pc_thunk.') and not symbol.startswith('_' + namespace)): non_namespaced.append(symbol) if non_namespaced: print("Missing namespace literal {}".format(namespace)) for symbol in non_namespaced: print("\ttype: {}, symbol: {}".format(symtype, symbol)) assert(False)
def make_check(path, expect_error=False): makeflag = '-q' if os.name != 'nt' else '/Q' expected_returncode = 0 if expect_error: expected_returncode = 1 if os.name != 'nt' else 255 helpers.make(makeflag, working_dir=path, expected_returncode=expected_returncode)
def check_functest_sanitizers(implementation): env = None if platform.machine() == 'ppc' and os.environ.get('CC', 'gcc') == 'clang': raise unittest.SkipTest("Clang does not support ASAN on ppc") elif platform.machine() in ['armv7l', 'aarch64']: env = {'ASAN_OPTIONS': 'detect_leaks=0'} else: print("Supported platform: {}".format(platform.machine())) helpers.ensure_available('valgrind') helpers.make('clean-scheme', 'functest', TYPE=implementation.scheme.type, SCHEME=implementation.scheme.name, IMPLEMENTATION=implementation.name, EXTRAFLAGS='-fsanitize=address,undefined', working_dir=os.path.join('..', 'test'), env=env) helpers.run_subprocess( [ os.path.join( '..', 'bin', 'functest_{}_{}{}'.format( implementation.scheme.name, implementation.name, '.exe' if os.name == 'nt' else '')) ], os.path.join('..', 'bin'), env=env, ) # Remove files with ASAN library compiled in helpers.make('clean-scheme', TYPE=implementation.scheme.type, SCHEME=implementation.scheme.name, IMPLEMENTATION=implementation.name, working_dir=os.path.join('..', 'test'))
def test_functest_sanitizers(implementation, impl_path, test_dir, init, destr): dest_dir = os.path.join(test_dir, 'bin') env = None if platform.machine() == 'ppc' and os.environ.get('CC', 'gcc') == 'clang': raise unittest.SkipTest("Clang does not support ASAN on ppc") elif platform.machine() in ['armv7l', 'aarch64']: env = {'ASAN_OPTIONS': 'detect_leaks=0'} elif platform.system() == 'Darwin': raise unittest.SkipTest('ASAN is not reliable on OSX') else: print("Supported platform: {}".format(platform.machine())) init() helpers.make('clean-scheme', 'functest', TYPE=implementation.scheme.type, SCHEME=implementation.scheme.name, IMPLEMENTATION=implementation.name, EXTRAFLAGS='-g -fsanitize=address,undefined', SCHEME_DIR=impl_path, DEST_DIR=dest_dir, working_dir=os.path.join(test_dir, 'test'), env=env) helpers.run_subprocess( [ os.path.join( dest_dir, 'functest_{}_{}{}'.format( implementation.scheme.name, implementation.name, '.exe' if os.name == 'nt' else '')) ], env=env, ) destr()
def test_metadata_sizes(implementation, impl_path, test_dir, init, destr): init() metadata = implementation.scheme.metadata() dest_dir = os.path.join(test_dir, 'bin') helpers.make('printparams', TYPE=implementation.scheme.type, SCHEME=implementation.scheme.name, IMPLEMENTATION=implementation.name, SCHEME_DIR=impl_path, DEST_DIR=dest_dir, working_dir=os.path.join(test_dir, 'test')) out = helpers.run_subprocess([ os.path.join( dest_dir, 'printparams_{}_{}{}'.format(implementation.scheme.name, implementation.name, '.exe' if os.name == 'nt' else '')) ]).replace('\r', '') parsed = json.loads(out) assert parsed['CRYPTO_SECRETKEYBYTES'] == metadata['length-secret-key'] assert parsed['CRYPTO_PUBLICKEYBYTES'] == metadata['length-public-key'] assert parsed['CRYPTO_ALGNAME'] == metadata['name'] if implementation.scheme.type == 'kem': assert ( parsed['CRYPTO_CIPHERTEXTBYTES'] == metadata['length-ciphertext']) assert parsed['CRYPTO_BYTES'] == metadata['length-shared-secret'] else: assert parsed['CRYPTO_BYTES'] == metadata['length-signature'] destr()
def test_makefile_dependencies(): for scheme in pqclean.Scheme.all_schemes(): for implementation in scheme.implementations: # initial build - want to have *all* files in place at beginning helpers.make('clean', working_dir=implementation.path()) helpers.make(working_dir=implementation.path()) # test case for each candidate file cfiles = glob.glob(os.path.join(implementation.path(), '*.c')) hfiles = glob.glob(os.path.join(implementation.path(), '*.h')) for file in (cfiles + hfiles): yield (check_makefile_dependencies, implementation, file)
def test_makefile_dependencies(implementation, impl_path, test_dir, init, destr): init() # initial build - want to have *all* files in place at beginning helpers.make('clean', working_dir=impl_path) helpers.make(working_dir=impl_path) # test case for each candidate file cfiles = glob.glob(os.path.join(impl_path, '*.c')) hfiles = glob.glob(os.path.join(impl_path, '*.h')) for file in (cfiles + hfiles): check_makefile_dependencies(implementation, impl_path, file) destr()
def check_valgrind(implementation: pqclean.Implementation): if (platform.machine() not in ('i386', 'x86_64') or platform.system() != 'Linux'): raise unittest.SkipTest() helpers.make(TYPE=implementation.scheme.type, SCHEME=implementation.scheme.name, IMPLEMENTATION=implementation.name, working_dir=os.path.join('..', 'test')) functest_name = './functest_{}_{}'.format(implementation.scheme.name, implementation.name) helpers.run_subprocess(['valgrind', functest_name], os.path.join('..', 'bin'))
def check_dynamic_memory(implementation, function): # 'make' will take care of not rebuilding existing library files helpers.make(working_dir=implementation.path()) scheme_name = implementation.scheme.name out = helpers.run_subprocess( ['nm', '-g', 'lib{}_{}.a'.format(scheme_name, implementation.name)], implementation.path()) lines = out.strip().split("\n") for line in lines: if 'U {}'.format(function) in line: raise AssertionError( "Illegal use of dynamic memory function '{}'".format(function))
def check_functest(implementation): helpers.make('functest', TYPE=implementation.scheme.type, SCHEME=implementation.scheme.name, IMPLEMENTATION=implementation.name, working_dir=os.path.join('..', 'test')) helpers.run_subprocess( [os.path.join('..', 'bin', 'functest_{}_{}{}'.format( implementation.scheme.name, implementation.name, '.exe' if os.name == 'nt' else '' ))], os.path.join('..', 'bin'), )
def check_vectors(implementation): helpers.make('testvectors', TYPE=implementation.scheme.type, SCHEME=implementation.scheme.name, IMPLEMENTATION=implementation.name, working_dir=os.path.join('..', 'test')) out = helpers.run_subprocess( [os.path.join('..', 'bin', 'testvectors_{}_{}{}'.format( implementation.scheme.name, implementation.name, '.exe' if os.name == 'nt' else '' ))], os.path.join('..', 'bin'), ).replace('\r', '') assert(implementation.scheme.metadata()['testvectors-sha256'].lower() == hashlib.sha256(out.encode('utf-8')).hexdigest().lower())
def test_functest(implementation, impl_path, test_dir, init, destr): init() dest_dir = os.path.join(test_dir, 'bin') helpers.make('functest', TYPE=implementation.scheme.type, SCHEME=implementation.scheme.name, IMPLEMENTATION=implementation.name, SCHEME_DIR=impl_path, DEST_DIR=dest_dir, working_dir=os.path.join(test_dir, 'test')) helpers.run_subprocess([ os.path.join( dest_dir, 'functest_{}_{}{}'.format( implementation.scheme.name, implementation.name, '.exe' if os.name == 'nt' else '')) ], ) destr()
def check_valgrind(implementation: pqclean.Implementation): if (platform.machine() not in ('i386', 'x86_64') or platform.system() != 'Linux'): raise unittest.SkipTest() if os.environ.get('CIRCLECI') == 'true' and os.environ.get( 'ARCH') == 'i386' and ( implementation.scheme.name == 'frodokem1344aes' or implementation.scheme.name == 'frodokem1344shake'): raise unittest.SkipTest('Skipping too-slow valgrind test') helpers.make(TYPE=implementation.scheme.type, SCHEME=implementation.scheme.name, IMPLEMENTATION=implementation.name, working_dir=os.path.join('..', 'test')) functest_name = './functest_{}_{}'.format(implementation.scheme.name, implementation.name) helpers.run_subprocess(['valgrind', functest_name], os.path.join('..', 'bin'))
def test_functest_sanitizers(implementation, impl_path, test_dir, init, destr): dest_dir = os.path.join(test_dir, 'bin') env = None if (implementation.scheme.name == "sphincs-sha256-192s-robust" and 'CI' in os.environ and implementation.name == "clean" and 'clang' in os.environ.get('CC', '')): raise unittest.SkipTest("Clang makes this test use too much RAM") if platform.machine() == 'ppc' and 'clang' in os.environ.get('CC', 'gcc'): raise unittest.SkipTest("Clang does not support ASAN on ppc") elif platform.machine() in ['armv7l', 'aarch64']: env = {'ASAN_OPTIONS': 'detect_leaks=0'} elif platform.system() == 'Darwin': raise unittest.SkipTest('ASAN is not reliable on OSX') else: print("Supported platform: {}".format(platform.machine())) init() helpers.make( 'clean-scheme', 'functest', TYPE=implementation.scheme.type, SCHEME=implementation.scheme.name, IMPLEMENTATION=implementation.name, EXTRAFLAGS=( '-g -fsanitize=address,undefined ' '-fno-sanitize-recover=undefined ' # TODO(JMS) Remove explicit -latomic if/when gcc fixes: # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81358 '-Wno-unused-command-line-argument -latomic'), SCHEME_DIR=impl_path, DEST_DIR=dest_dir, working_dir=os.path.join(test_dir, 'test'), env=env) helpers.run_subprocess( [ os.path.join( dest_dir, 'functest_{}_{}{}'.format( implementation.scheme.name, implementation.name, '.exe' if os.name == 'nt' else '')) ], env=env, ) destr()
def test_dynamic_memory(implementation, test_dir, impl_path, init, destr): init() # 'make' will take care of not rebuilding existing library files helpers.make(working_dir=impl_path) scheme_name = implementation.scheme.name out = helpers.run_subprocess( ['nm', '-g', 'lib{}_{}.a'.format(scheme_name, implementation.name)], impl_path, ) lines = out.strip().split("\n") for line in lines: for function in ['malloc', 'free', 'realloc', 'calloc']: if line.endswith('U {}'.format(function)): raise AssertionError("Illegal use of dynamic memory function " "'{function}'".format(function=function)) destr()
def test_makefile_dependencies(implementation, impl_path, test_dir, init, destr): init() # initial build - want to have *all* files in place at beginning helpers.make('clean', working_dir=impl_path) helpers.make(working_dir=impl_path) # test case for each candidate file cfiles = glob.glob(os.path.join(impl_path, '*.c')) sfiles = glob.glob(os.path.join(impl_path, '*.[sS]')) incfiles = glob.glob(os.path.join(impl_path, '*.inc')) hfiles = glob.glob(os.path.join(impl_path, '*.h')) try: for file in (cfiles + hfiles + sfiles + incfiles): check_makefile_dependencies(implementation, impl_path, file) except Exception as e: print("Affected file: {}".format(file)) raise e finally: destr()
def test_nistkat(implementation, impl_path, test_dir, init, destr): init() dest_path = os.path.join(test_dir, 'bin') helpers.make('nistkat', TYPE=implementation.scheme.type, SCHEME=implementation.scheme.name, IMPLEMENTATION=implementation.name, SCHEME_DIR=impl_path, DEST_DIR=dest_path, working_dir=os.path.join(test_dir, 'test')) out = helpers.run_subprocess([ os.path.join( dest_path, 'nistkat_{}_{}{}'.format( implementation.scheme.name, implementation.name, '.exe' if os.name == 'nt' else '')) ], ).replace('\r', '') assert (implementation.scheme.metadata()['nistkat-sha256'].lower() == hashlib.sha256(out.encode('utf-8')).hexdigest().lower()) destr()
def test_valgrind(implementation: pqclean.Implementation, impl_path, test_dir, init, destr): if (platform.machine() not in ('i386', 'x86_64') or platform.system() != 'Linux'): raise unittest.SkipTest() init() dest_dir = os.path.join(test_dir, 'bin') helpers.make(TYPE=implementation.scheme.type, SCHEME=implementation.scheme.name, SCHEME_DIR=os.path.abspath(impl_path), IMPLEMENTATION=implementation.name, DEST_DIR=dest_dir, NTESTS=1, working_dir=os.path.join(test_dir, 'test')) functest_name = './functest_{}_{}'.format(implementation.scheme.name, implementation.name) helpers.run_subprocess(['valgrind', functest_name], dest_dir) destr()
def check_nistkat(implementation): if implementation.scheme.name == "kyber768": raise unittest.SkipTest( "Temporarily skip NIST KAT check for kyber768 since it's " "an outdated implementation") helpers.make('nistkat', TYPE=implementation.scheme.type, SCHEME=implementation.scheme.name, IMPLEMENTATION=implementation.name, working_dir=os.path.join('..', 'test')) out = helpers.run_subprocess( [ os.path.join( '..', 'bin', 'nistkat_{}_{}{}'.format( implementation.scheme.name, implementation.name, '.exe' if os.name == 'nt' else '')) ], os.path.join('..', 'bin'), ).replace('\r', '') assert (implementation.scheme.metadata()['nistkat-sha256'].lower() == hashlib.sha256(out.encode('utf-8')).hexdigest().lower())
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() dest_dir = os.path.join(test_dir, 'bin') helpers.make('testvectors', TYPE=implementation.scheme.type, SCHEME=implementation.scheme.name, SCHEME_DIR=impl_path, IMPLEMENTATION=implementation.name, DEST_DIR=dest_dir, working_dir=os.path.join(test_dir, 'test')) out = helpers.run_subprocess( [os.path.join(dest_dir, 'testvectors_{}_{}{}'.format( implementation.scheme.name, implementation.name, '.exe' if os.name == 'nt' else '' ))], ).replace('\r', '') assert(implementation.scheme.metadata()['testvectors-sha256'].lower() == hashlib.sha256(out.encode('utf-8')).hexdigest().lower()) destr()
def test_symbol_namespaces(implementation, impl_path, test_dir, init, destr): if sys.platform not in ['linux', 'darwin']: raise unittest.SkipTest("Unsupported platform") init() helpers.make(working_dir=impl_path) out = helpers.run_subprocess( ['nm', '-g', implementation.libname()], impl_path, ) lines = out.strip().split("\n") symbols = [] for line in lines: if ' T ' in line or ' D ' in line or ' S ' in line: symbols.append(line) namespace = implementation.namespace_prefix() non_namespaced = [] for symbolstr in symbols: *_, symtype, symbol = symbolstr.split() if symtype in 'TR': if not (symbol.startswith(namespace) or symbol.startswith('_' + namespace) or # KeccakP-1600 for AVX2 symbol.startswith('KeccakF1600times4') or symbol.startswith('_KeccakF1600times4') or # MacOS symbol.startswith('KeccakP1600times4') or symbol.startswith('_KeccakP1600times4') or # MacOS # weird things on i386 symbol.startswith('__x86.get_pc_thunk.')): non_namespaced.append(symbol) if non_namespaced: print("Missing namespace literal {}".format(namespace)) for symbol in non_namespaced: print("\ttype: {}, symbol: {}".format(symtype, symbol)) assert not non_namespaced, "Literals with missing namespaces" destr()
def check_compile_lib(implementation): helpers.make('clean', working_dir=implementation.path()) helpers.make(working_dir=implementation.path())
def test_compile_lib(implementation, test_dir, impl_dir, init, destr): init() helpers.make('clean', working_dir=impl_dir) helpers.make(working_dir=impl_dir) destr()
def build(buildonly = False): # Crossdomain sed = Sed() sed.add("<\!--.*-->\s*", "") combine("src/crossdomain.xml", Yak.build_root + "/crossdomain.xml", replace = sed) # Robots sed = Sed() # XXX partially f****d-up sed.add("(?:^|\n+)(?:#[^\n]*\n*)+", "") combine("src/robots.txt", Yak.build_root + "/robots.txt", replace = sed) # Deepcopy other stuff sed = Sed() PH.replacer(sed) list = FileList("src/", exclude="*robots.txt,*crossdomain.xml,*index.html") deepcopy(list, Yak.build_root, replace=sed) # Process the remote leaves description = {} # Yak.collection.items() colls = PH.getyanks() # print Yak.collection # for name in Yak.collection: # print name for name in colls: packinfo = colls[name] # Temporary and build output directories definitions tmpdir = FileSystem.join(Yak.tmp_root, "lib", packinfo["Destination"], name) builddir = FileSystem.join(Yak.build_root, "lib", packinfo["Destination"], name) desclist = [] marker = 'lib/%s/' % packinfo["Destination"] for(localname, url) in packinfo["Source"].items(): # Do the fetch of PH.fetchone(url, tmpdir, localname) # Copy files that "exists" to build directory f = FileSystem.join(tmpdir, localname) if FileSystem.exists(f): d = FileSystem.join(builddir, localname) # if not FileSystem.exists(FileSystem.dirname(d)): # FileSystem.makedir(FileSystem.dirname(d)); FileSystem.copyfile(f, d) # Augment desclist with provided localname desclist += [FileSystem.join(marker, name, localname)] if "Build" in packinfo: buildinfo = packinfo["Build"] production = buildinfo["production"] tmpdir = FileSystem.join(tmpdir, buildinfo["dir"]) extra = '' if 'args' in buildinfo: extra = buildinfo["args"] if not buildonly or buildonly == name: PH.make(tmpdir, buildinfo["type"], extra) # Copy production to build dir for(local, builded) in production.items(): f = FileSystem.join(tmpdir, builded) d = FileSystem.join(builddir, local) desclist += [FileSystem.join(marker, name, local)] if FileSystem.isfile(f): FileSystem.copyfile(f, d) elif FileSystem.isdir(f): deepcopy(FileList(f), d) # ["coin%s" % key for key in ['item1', 'item2']] # map((lambda item: "%s%s" % (name, item)), ['item1', 'item2']) # # Augment description list with build result # bitch = production.keys(); # for x in bitch: # bitch[x] = FileSystem.join(name, bitch[x]); # print bitch # raise "toto" # desclist = desclist + production.keys() description[name] = desclist # description[name] = "%s%s" % (name, marker, ('",\n"%s' % marker).join(desclist))) # miam += """ # %s: # ["%s%s"] # """ % (name, marker, ('", "%s' % marker).join(desclist)) # FileSystem.writefile(FileSystem.join(Yak.build_root, "airstrip.yaml"), yaml.dump(yaml.load('\n'.join(description)))) # print json.dumps(description) # raise "toto" shortversion = Yak.package['version'].split('-').pop(0).split('.') shortversion = shortversion[0] + "." + shortversion[1] PH.describe(shortversion, "airstrip", description) # Write description file # FileSystem.writefile(FileSystem.join(Yak.build_root, "airstrip.json"), '{%s}' % ',\n'.join(description)) # Build-up the description file file = "src/index.html" sed.add("{PUKE-LIST}", json.dumps(description, indent=4)) deepcopy(file, Yak.build_root, replace=sed)
def check_common(primitive): binname = os.path.join('..', 'bin', 'test_common_'+primitive) helpers.make(binname) helpers.run_subprocess([binname])