diff --git a/README.md b/README.md index b557aa75..2091dc31 100644 --- a/README.md +++ b/README.md @@ -42,11 +42,7 @@ _The checking of items on this list is still being developed. Checked items shou * [x] Consistent test vectors on 32-bit and 64-bit machines * [x] No errors/warnings reported by valgrind * [x] No errors/warnings reported by address sanitizer -* [ ] Only dependencies: - * [x] `fips202.c` - * [x] `sha2.c` - * [ ] `aes.c` - * [x] `randombytes.c` +* [x] Only dependencies: `fips202.c`, `sha2.c`, `aes.c`, `randombytes.c` * [x] API functions return `0` on success * [x] No dynamic memory allocations * [ ] No branching on secret data (dynamically checked using valgrind) diff --git a/crypto_kem/frodokem1344shake/clean/util.c b/crypto_kem/frodokem1344shake/clean/util.c index 4a71e4b1..946f5a1c 100644 --- a/crypto_kem/frodokem1344shake/clean/util.c +++ b/crypto_kem/frodokem1344shake/clean/util.c @@ -13,7 +13,7 @@ #define min(x, y) (((x) < (y)) ? (x) : (y)) uint16_t PQCLEAN_FRODOKEM1344SHAKE_CLEAN_LE_TO_UINT16(const uint16_t n) { - return (((uint8_t *) &(n))[0] | (((uint8_t *) &(n))[1] << 8)); + return (((uint8_t *) &n)[0] | (((uint8_t *) &n)[1] << 8)); } uint16_t PQCLEAN_FRODOKEM1344SHAKE_CLEAN_UINT16_TO_LE(const uint16_t n) { diff --git a/crypto_kem/frodokem640shake/clean/util.c b/crypto_kem/frodokem640shake/clean/util.c index ba038d1d..50e5a074 100644 --- a/crypto_kem/frodokem640shake/clean/util.c +++ b/crypto_kem/frodokem640shake/clean/util.c @@ -13,7 +13,7 @@ #define min(x, y) (((x) < (y)) ? (x) : (y)) uint16_t PQCLEAN_FRODOKEM640SHAKE_CLEAN_LE_TO_UINT16(const uint16_t n) { - return (((uint8_t *) &(n))[0] | (((uint8_t *) &(n))[1] << 8)); + return (((uint8_t *) &n)[0] | (((uint8_t *) &n)[1] << 8)); } uint16_t PQCLEAN_FRODOKEM640SHAKE_CLEAN_UINT16_TO_LE(const uint16_t n) { diff --git a/crypto_kem/frodokem976shake/clean/util.c b/crypto_kem/frodokem976shake/clean/util.c index add8866a..28a119b8 100644 --- a/crypto_kem/frodokem976shake/clean/util.c +++ b/crypto_kem/frodokem976shake/clean/util.c @@ -13,7 +13,7 @@ #define min(x, y) (((x) < (y)) ? (x) : (y)) uint16_t PQCLEAN_FRODOKEM976SHAKE_CLEAN_LE_TO_UINT16(const uint16_t n) { - return (((uint8_t *) &(n))[0] | (((uint8_t *) &(n))[1] << 8)); + return (((uint8_t *) &n)[0] | (((uint8_t *) &n)[1] << 8)); } uint16_t PQCLEAN_FRODOKEM976SHAKE_CLEAN_UINT16_TO_LE(const uint16_t n) { diff --git a/crypto_sign/sphincs-shake256-128f-simple/clean/Makefile b/crypto_sign/sphincs-shake256-128f-simple/clean/Makefile index f2ba7804..93ae2300 100644 --- a/crypto_sign/sphincs-shake256-128f-simple/clean/Makefile +++ b/crypto_sign/sphincs-shake256-128f-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-128f-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_simple.o -CFLAGS=-Wall -Wextra -Wpedantic -Werror -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-128f-simple/clean/fors.c b/crypto_sign/sphincs-shake256-128f-simple/clean/fors.c index 74090621..9dbf4513 100644 --- a/crypto_sign/sphincs-shake256-128f-simple/clean/fors.c +++ b/crypto_sign/sphincs-shake256-128f-simple/clean/fors.c @@ -50,7 +50,7 @@ static void message_to_indices(uint32_t *indices, const unsigned char *m) { for (i = 0; i < SPX_FORS_TREES; i++) { indices[i] = 0; for (j = 0; j < SPX_FORS_HEIGHT; j++) { - indices[i] ^= ((m[offset >> 3] >> (offset & 0x7)) & 0x1) << j; + indices[i] ^= (((uint32_t)m[offset >> 3] >> (offset & 0x7)) & 0x1) << j; offset++; } } diff --git a/crypto_sign/sphincs-shake256-128f-simple/clean/wots.c b/crypto_sign/sphincs-shake256-128f-simple/clean/wots.c index f88b3a69..a6a8ada6 100644 --- a/crypto_sign/sphincs-shake256-128f-simple/clean/wots.c +++ b/crypto_sign/sphincs-shake256-128f-simple/clean/wots.c @@ -53,12 +53,13 @@ static void gen_chain(unsigned char *out, const unsigned char *in, * Interprets an array of bytes as integers in base w. * This only works when log_w is a divisor of 8. */ -static void base_w(int *output, const int out_len, const unsigned char *input) { - int in = 0; - int out = 0; +static void base_w(unsigned int *output, const size_t out_len, + const unsigned char *input) { + size_t in = 0; + size_t out = 0; unsigned char total = 0; - int bits = 0; - int consumed; + unsigned int bits = 0; + size_t consumed; for (consumed = 0; consumed < out_len; consumed++) { if (bits == 0) { @@ -73,8 +74,9 @@ static void base_w(int *output, const int out_len, const unsigned char *input) { } /* Computes the WOTS+ checksum over a message (in base_w). */ -static void wots_checksum(int *csum_base_w, const int *msg_base_w) { - int csum = 0; +static void wots_checksum(unsigned int *csum_base_w, + const unsigned int *msg_base_w) { + unsigned int csum = 0; unsigned char csum_bytes[(SPX_WOTS_LEN2 * SPX_WOTS_LOGW + 7) / 8]; unsigned int i; @@ -92,7 +94,7 @@ static void wots_checksum(int *csum_base_w, const int *msg_base_w) { } /* Takes a message and derives the matching chain lengths. */ -static void chain_lengths(int *lengths, const unsigned char *msg) { +static void chain_lengths(unsigned int *lengths, const unsigned char *msg) { base_w(lengths, SPX_WOTS_LEN1, msg); wots_checksum(lengths + SPX_WOTS_LEN1, lengths); } @@ -125,7 +127,7 @@ void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_wots_sign( unsigned char *sig, const unsigned char *msg, const unsigned char *sk_seed, const unsigned char *pub_seed, uint32_t addr[8]) { - int lengths[SPX_WOTS_LEN]; + unsigned int lengths[SPX_WOTS_LEN]; uint32_t i; chain_lengths(lengths, msg); @@ -146,7 +148,7 @@ void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_wots_pk_from_sig( unsigned char *pk, const unsigned char *sig, const unsigned char *msg, const unsigned char *pub_seed, uint32_t addr[8]) { - int lengths[SPX_WOTS_LEN]; + unsigned int lengths[SPX_WOTS_LEN]; uint32_t i; chain_lengths(lengths, msg); diff --git a/test/Makefile b/test/Makefile index bc7c08cb..822fc101 100644 --- a/test/Makefile +++ b/test/Makefile @@ -41,7 +41,7 @@ testvectors: $(DEST_DIR)/testvectors_$(SCHEME)_$(IMPLEMENTATION) .PHONY: printparams printparams: $(DEST_DIR)/printparams_$(SCHEME)_$(IMPLEMENTATION) -$(DEST_DIR)/test_%: common/%.c $(COMMON_FILES) +$(DEST_DIR)/test_common_%: common/%.c $(COMMON_FILES) mkdir -p $(DEST_DIR) $(CC) $(CFLAGS) $< $(COMMON_FILES) -o $@ diff --git a/test/helpers.py b/test/helpers.py index e6c3adc1..966510f1 100644 --- a/test/helpers.py +++ b/test/helpers.py @@ -5,6 +5,8 @@ import unittest import shutil import sys +import pqclean + def run_subprocess(command, working_dir='.', env=None, expected_returncode=0): """ @@ -97,3 +99,32 @@ def ensure_available(executable): else "On Windows, make sure to add it to PATH") ) raise AssertionError("{} not available on CI".format(executable)) + + +def permit_test(testname, thing, **args): + if 'PQCLEAN_ONLY_TESTS' in os.environ: + if not(testname.lower() in os.environ['PQCLEAN_ONLY_TESTS'].lower().split(',')): + return False + if 'PQCLEAN_SKIP_TESTS' in os.environ: + if testname.lower() in os.environ['PQCLEAN_SKIP_TESTS'].lower().split(','): + return False + + if isinstance(thing, pqclean.Implementation): + scheme = thing.scheme + else: + scheme = thing + + if 'PQCLEAN_ONLY_TYPES' in os.environ: + if not(scheme.type.lower() in os.environ['PQCLEAN_ONLY_TYPES'].lower().split(',')): + return False + if 'PQCLEAN_SKIP_TYPES' in os.environ: + if scheme.type.lower() in os.environ['PQCLEAN_SKIP_TYPES'].lower().split(','): + return False + if 'PQCLEAN_ONLY_SCHEMES' in os.environ: + if not(scheme.name.lower() in os.environ['PQCLEAN_ONLY_SCHEMES'].lower().split(',')): + return False + if 'PQCLEAN_SKIP_SCHEMES' in os.environ: + if scheme.name.lower() in os.environ['PQCLEAN_SKIP_SCHEMES'].lower().split(','): + return False + + return True diff --git a/test/test_api_h.py b/test/test_api_h.py index 501791f9..5ed2d121 100644 --- a/test/test_api_h.py +++ b/test/test_api_h.py @@ -1,13 +1,15 @@ import os import re +import helpers import pqclean def test_preprocessor(): for scheme in pqclean.Scheme.all_schemes(): for implementation in scheme.implementations: - yield check_preprocessor, implementation + if helpers.permit_test('preprocessor', implementation): + yield check_preprocessor, implementation def check_preprocessor(implementation: pqclean.Implementation): diff --git a/test/test_char.py b/test/test_char.py index 98f633ed..48aa55c9 100644 --- a/test/test_char.py +++ b/test/test_char.py @@ -17,7 +17,8 @@ def test_char(): ) for scheme in pqclean.Scheme.all_schemes(): for implementation in scheme.implementations: - yield check_char, implementation + if helpers.permit_test('char', implementation): + yield check_char, implementation def walk_tree(ast): diff --git a/test/test_common.py b/test/test_common.py index ec7a593f..3640bb3f 100644 --- a/test/test_common.py +++ b/test/test_common.py @@ -16,7 +16,7 @@ def test_common(): def check_common(primitive): - binname = os.path.join('..', 'bin', 'test_'+primitive) + binname = os.path.join('..', 'bin', 'test_common_'+primitive) helpers.make(binname) helpers.run_subprocess([binname]) diff --git a/test/test_compile_lib.py b/test/test_compile_lib.py index 7151975e..e4b1ae5c 100644 --- a/test/test_compile_lib.py +++ b/test/test_compile_lib.py @@ -10,7 +10,8 @@ import helpers def test_compile_lib(): for scheme in pqclean.Scheme.all_schemes(): for implementation in scheme.implementations: - yield check_compile_lib, implementation + if helpers.permit_test('compile_lib', implementation): + yield check_compile_lib, implementation def check_compile_lib(implementation): diff --git a/test/test_duplicate_consistency.py b/test/test_duplicate_consistency.py index 6ee7c7e0..a8f344d6 100644 --- a/test/test_duplicate_consistency.py +++ b/test/test_duplicate_consistency.py @@ -12,14 +12,15 @@ def test_duplicate_consistency(): helpers.skip_windows() for scheme in pqclean.Scheme.all_schemes(): for implementation in scheme.implementations: - if os.path.isfile(os.path.join('duplicate_consistency', '{}_{}.yml'.format(scheme.name, implementation.name))): - metafile = os.path.join('duplicate_consistency', '{}_{}.yml'.format(implementation.scheme.name, implementation.name)) - with open(metafile, encoding='utf-8') as f: - metadata = yaml.load(f.read()) - for group in metadata['consistency_checks']: - source = pqclean.Implementation.by_name(group['source']['scheme'], group['source']['implementation']) - for file in group['files']: - yield check_duplicate_consistency, implementation, source, file + if helpers.permit_test('duplicate_consistency', implementation): + if os.path.isfile(os.path.join('duplicate_consistency', '{}_{}.yml'.format(scheme.name, implementation.name))): + metafile = os.path.join('duplicate_consistency', '{}_{}.yml'.format(implementation.scheme.name, implementation.name)) + with open(metafile, encoding='utf-8') as f: + metadata = yaml.load(f.read()) + for group in metadata['consistency_checks']: + source = pqclean.Implementation.by_name(group['source']['scheme'], group['source']['implementation']) + for file in group['files']: + yield check_duplicate_consistency, implementation, source, file def file_get_contents(filename): with open(filename) as f: diff --git a/test/test_dynamic_memory.py b/test/test_dynamic_memory.py index 8853eaea..27257006 100644 --- a/test/test_dynamic_memory.py +++ b/test/test_dynamic_memory.py @@ -11,9 +11,10 @@ import unittest def test_dynamic_memory(): for scheme in pqclean.Scheme.all_schemes(): for implementation in scheme.implementations: - # Keep this loop outside, to allow multiple assertions - for function in ['malloc', 'free', 'realloc', 'calloc']: - yield (check_dynamic_memory, implementation, function) + if helpers.permit_test('dynamic_memory', implementation): + # Keep this loop outside, to allow multiple assertions + for function in ['malloc', 'free', 'realloc', 'calloc']: + yield (check_dynamic_memory, implementation, function) @helpers.skip_windows() diff --git a/test/test_format.py b/test/test_format.py index 09cc61fd..a55c78ef 100644 --- a/test/test_format.py +++ b/test/test_format.py @@ -1,22 +1,24 @@ +import helpers import pqclean -from helpers import run_subprocess, ensure_available def test_formatting(): for scheme in pqclean.Scheme.all_schemes(): for implementation in scheme.implementations: - yield check_format, implementation + if helpers.permit_test('format', implementation): + yield check_format, implementation def check_format(implementation: pqclean.Implementation): - ensure_available('astyle') + helpers.ensure_available('astyle') cfiles = implementation.cfiles() hfiles = implementation.hfiles() - run_subprocess(['astyle', + result = helpers.run_subprocess(['astyle', '--dry-run', '--options=../.astylerc', *cfiles, *hfiles]) + assert(not('Formatted' in result)) if __name__ == "__main__": diff --git a/test/test_functest.py b/test/test_functest.py index 01807e75..d4517947 100644 --- a/test/test_functest.py +++ b/test/test_functest.py @@ -14,13 +14,15 @@ import helpers def test_functest(): for scheme in pqclean.Scheme.all_schemes(): for implementation in scheme.implementations: - yield check_functest, implementation + if helpers.permit_test('functest', implementation): + yield check_functest, implementation def test_functest_sanitizers(): for scheme in pqclean.Scheme.all_schemes(): for implementation in scheme.implementations: - yield check_functest_sanitizers, implementation + if helpers.permit_test('functest_sanitizers', implementation): + yield check_functest_sanitizers, implementation def check_functest(implementation): diff --git a/test/test_license.py b/test/test_license.py index 64633a40..15c61491 100644 --- a/test/test_license.py +++ b/test/test_license.py @@ -5,12 +5,14 @@ implementation of the specified scheme. import os import pqclean +import helpers def test_license(): for scheme in pqclean.Scheme.all_schemes(): for implementation in scheme.implementations: - yield check_license, implementation + if helpers.permit_test('license', implementation): + yield check_license, implementation def check_license(implementation): diff --git a/test/test_linter.py b/test/test_linter.py index 33563f8b..07e01180 100644 --- a/test/test_linter.py +++ b/test/test_linter.py @@ -1,24 +1,29 @@ import os from glob import glob +import sys import pqclean -from helpers import run_subprocess, ensure_available +import helpers + +additional_flags = [] def test_clang_tidy(): for scheme in pqclean.Scheme.all_schemes(): for implementation in scheme.implementations: - yield check_tidy, implementation + if helpers.permit_test('linter', implementation): + yield check_tidy, implementation def check_tidy(implementation: pqclean.Implementation): - ensure_available('clang-tidy') + helpers.ensure_available('clang-tidy') cfiles = glob(os.path.join(implementation.path(), '*.c')) common_files = glob(os.path.join('..', 'common', '*.c')) - run_subprocess(['clang-tidy', + helpers.run_subprocess(['clang-tidy', '-quiet', - '-header-filter=.*', - *cfiles, + '-header-filter=.*'] + + additional_flags + + [*cfiles, *common_files, '--', '-iquote', os.path.join('..', 'common'), @@ -27,6 +32,10 @@ def check_tidy(implementation: pqclean.Implementation): if __name__ == "__main__": + # allow a user to specify --fix-errors, to immediately fix errors + if len(sys.argv) >= 2 and sys.argv[1] == '-fix-errors': + additional_flags = ['-fix-errors'] + sys.argv = sys.argv[0:1] + sys.argv[2:] try: import nose2 nose2.main() diff --git a/test/test_makefile_dependencies.py b/test/test_makefile_dependencies.py index 86730890..8305745e 100644 --- a/test/test_makefile_dependencies.py +++ b/test/test_makefile_dependencies.py @@ -13,14 +13,15 @@ import datetime 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) + if helpers.permit_test('makefile_dependencies', implementation): + # 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 touch(time, *files): diff --git a/test/test_metadata.py b/test/test_metadata.py index 11556a08..997ce831 100644 --- a/test/test_metadata.py +++ b/test/test_metadata.py @@ -3,13 +3,15 @@ Verify the metadata specified in the META.yml files. """ import copy +import helpers import itertools import pqclean def test_metadata(): for scheme in pqclean.Scheme.all_schemes(): - yield check_metadata, scheme + if helpers.permit_test('metadata', scheme): + yield check_metadata, scheme def check_metadata(scheme): diff --git a/test/test_metadata_sizes.py b/test/test_metadata_sizes.py index 38c77a5f..20915cce 100644 --- a/test/test_metadata_sizes.py +++ b/test/test_metadata_sizes.py @@ -8,7 +8,8 @@ import helpers def test_metadata_sizes(): for scheme in pqclean.Scheme.all_schemes(): for implementation in scheme.implementations: - yield check_metadata_sizes, implementation + if helpers.permit_test('metadata_sizes', implementation): + yield check_metadata_sizes, implementation def check_metadata_sizes(implementation): diff --git a/test/test_no_symlinks.py b/test/test_no_symlinks.py index 6f8eac6a..eb2a0656 100644 --- a/test/test_no_symlinks.py +++ b/test/test_no_symlinks.py @@ -4,12 +4,14 @@ Checks that no implementation makes use of symbolic links. import os import pqclean +import helpers def test_no_symlinks(): for scheme in pqclean.Scheme.all_schemes(): for implementation in scheme.implementations: - yield check_no_symlinks, implementation + if helpers.permit_test('no_symlinks', implementation): + yield check_no_symlinks, implementation def check_no_symlinks(implementation): diff --git a/test/test_preprocessor.py b/test/test_preprocessor.py index 64e0b1f4..c332362e 100644 --- a/test/test_preprocessor.py +++ b/test/test_preprocessor.py @@ -2,13 +2,14 @@ import os from glob import glob import pqclean -from helpers import run_subprocess, ensure_available +import helpers def test_preprocessor(): for scheme in pqclean.Scheme.all_schemes(): for implementation in scheme.implementations: - yield check_preprocessor, implementation + if helpers.permit_test('preprocessor', implementation): + yield check_preprocessor, implementation def check_preprocessor(implementation: pqclean.Implementation): diff --git a/test/test_symbol_namespace.py b/test/test_symbol_namespace.py index 5d6ea9a0..0b9fe933 100644 --- a/test/test_symbol_namespace.py +++ b/test/test_symbol_namespace.py @@ -12,7 +12,8 @@ import unittest def test_symbol_namespace(): for scheme in pqclean.Scheme.all_schemes(): for implementation in scheme.implementations: - yield check_symbol_namespace, implementation + if helpers.permit_test('symbol_namespace', implementation): + yield check_symbol_namespace, implementation def check_symbol_namespace(implementation): diff --git a/test/test_testvectors.py b/test/test_testvectors.py index 14afb92f..87c9c137 100644 --- a/test/test_testvectors.py +++ b/test/test_testvectors.py @@ -12,7 +12,8 @@ import helpers def test_testvectors(): for scheme in pqclean.Scheme.all_schemes(): for implementation in scheme.implementations: - yield check_vectors, implementation + if helpers.permit_test('testvectors', implementation): + yield check_vectors, implementation def check_vectors(implementation): diff --git a/test/test_valgrind.py b/test/test_valgrind.py index 1fa8b601..1a31f59a 100644 --- a/test/test_valgrind.py +++ b/test/test_valgrind.py @@ -13,7 +13,8 @@ import helpers def test_functest(): for scheme in pqclean.Scheme.all_schemes(): for implementation in scheme.implementations: - yield check_valgrind, implementation + if helpers.permit_test('valgrind', implementation): + yield check_valgrind, implementation def check_valgrind(implementation: pqclean.Implementation):