Merge branch 'master' into frodo-aes

This commit is contained in:
Douglas Stebila 2019-04-11 08:15:40 -04:00
commit b7f390368e
27 changed files with 125 additions and 65 deletions

View File

@ -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] Consistent test vectors on 32-bit and 64-bit machines
* [x] No errors/warnings reported by valgrind * [x] No errors/warnings reported by valgrind
* [x] No errors/warnings reported by address sanitizer * [x] No errors/warnings reported by address sanitizer
* [ ] Only dependencies: * [x] Only dependencies: `fips202.c`, `sha2.c`, `aes.c`, `randombytes.c`
* [x] `fips202.c`
* [x] `sha2.c`
* [ ] `aes.c`
* [x] `randombytes.c`
* [x] API functions return `0` on success * [x] API functions return `0` on success
* [x] No dynamic memory allocations * [x] No dynamic memory allocations
* [ ] No branching on secret data (dynamically checked using valgrind) * [ ] No branching on secret data (dynamically checked using valgrind)

View File

@ -13,7 +13,7 @@
#define min(x, y) (((x) < (y)) ? (x) : (y)) #define min(x, y) (((x) < (y)) ? (x) : (y))
uint16_t PQCLEAN_FRODOKEM1344SHAKE_CLEAN_LE_TO_UINT16(const uint16_t n) { 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) { uint16_t PQCLEAN_FRODOKEM1344SHAKE_CLEAN_UINT16_TO_LE(const uint16_t n) {

View File

@ -13,7 +13,7 @@
#define min(x, y) (((x) < (y)) ? (x) : (y)) #define min(x, y) (((x) < (y)) ? (x) : (y))
uint16_t PQCLEAN_FRODOKEM640SHAKE_CLEAN_LE_TO_UINT16(const uint16_t n) { 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) { uint16_t PQCLEAN_FRODOKEM640SHAKE_CLEAN_UINT16_TO_LE(const uint16_t n) {

View File

@ -13,7 +13,7 @@
#define min(x, y) (((x) < (y)) ? (x) : (y)) #define min(x, y) (((x) < (y)) ? (x) : (y))
uint16_t PQCLEAN_FRODOKEM976SHAKE_CLEAN_LE_TO_UINT16(const uint16_t n) { 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) { uint16_t PQCLEAN_FRODOKEM976SHAKE_CLEAN_UINT16_TO_LE(const uint16_t n) {

View File

@ -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 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 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) all: $(LIB)

View File

@ -50,7 +50,7 @@ static void message_to_indices(uint32_t *indices, const unsigned char *m) {
for (i = 0; i < SPX_FORS_TREES; i++) { for (i = 0; i < SPX_FORS_TREES; i++) {
indices[i] = 0; indices[i] = 0;
for (j = 0; j < SPX_FORS_HEIGHT; j++) { 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++; offset++;
} }
} }

View File

@ -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. * Interprets an array of bytes as integers in base w.
* This only works when log_w is a divisor of 8. * 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) { static void base_w(unsigned int *output, const size_t out_len,
int in = 0; const unsigned char *input) {
int out = 0; size_t in = 0;
size_t out = 0;
unsigned char total = 0; unsigned char total = 0;
int bits = 0; unsigned int bits = 0;
int consumed; size_t consumed;
for (consumed = 0; consumed < out_len; consumed++) { for (consumed = 0; consumed < out_len; consumed++) {
if (bits == 0) { 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). */ /* Computes the WOTS+ checksum over a message (in base_w). */
static void wots_checksum(int *csum_base_w, const int *msg_base_w) { static void wots_checksum(unsigned int *csum_base_w,
int csum = 0; const unsigned int *msg_base_w) {
unsigned int csum = 0;
unsigned char csum_bytes[(SPX_WOTS_LEN2 * SPX_WOTS_LOGW + 7) / 8]; unsigned char csum_bytes[(SPX_WOTS_LEN2 * SPX_WOTS_LOGW + 7) / 8];
unsigned int i; 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. */ /* 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); base_w(lengths, SPX_WOTS_LEN1, msg);
wots_checksum(lengths + SPX_WOTS_LEN1, lengths); wots_checksum(lengths + SPX_WOTS_LEN1, lengths);
} }
@ -125,7 +127,7 @@ void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_wots_sign(
unsigned char *sig, const unsigned char *msg, unsigned char *sig, const unsigned char *msg,
const unsigned char *sk_seed, const unsigned char *pub_seed, const unsigned char *sk_seed, const unsigned char *pub_seed,
uint32_t addr[8]) { uint32_t addr[8]) {
int lengths[SPX_WOTS_LEN]; unsigned int lengths[SPX_WOTS_LEN];
uint32_t i; uint32_t i;
chain_lengths(lengths, msg); chain_lengths(lengths, msg);
@ -146,7 +148,7 @@ void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_wots_pk_from_sig(
unsigned char *pk, unsigned char *pk,
const unsigned char *sig, const unsigned char *msg, const unsigned char *sig, const unsigned char *msg,
const unsigned char *pub_seed, uint32_t addr[8]) { const unsigned char *pub_seed, uint32_t addr[8]) {
int lengths[SPX_WOTS_LEN]; unsigned int lengths[SPX_WOTS_LEN];
uint32_t i; uint32_t i;
chain_lengths(lengths, msg); chain_lengths(lengths, msg);

View File

@ -41,7 +41,7 @@ testvectors: $(DEST_DIR)/testvectors_$(SCHEME)_$(IMPLEMENTATION)
.PHONY: printparams .PHONY: printparams
printparams: $(DEST_DIR)/printparams_$(SCHEME)_$(IMPLEMENTATION) 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) mkdir -p $(DEST_DIR)
$(CC) $(CFLAGS) $< $(COMMON_FILES) -o $@ $(CC) $(CFLAGS) $< $(COMMON_FILES) -o $@

View File

@ -5,6 +5,8 @@ import unittest
import shutil import shutil
import sys import sys
import pqclean
def run_subprocess(command, working_dir='.', env=None, expected_returncode=0): 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") else "On Windows, make sure to add it to PATH")
) )
raise AssertionError("{} not available on CI".format(executable)) 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

View File

@ -1,12 +1,14 @@
import os import os
import re import re
import helpers
import pqclean import pqclean
def test_preprocessor(): def test_preprocessor():
for scheme in pqclean.Scheme.all_schemes(): for scheme in pqclean.Scheme.all_schemes():
for implementation in scheme.implementations: for implementation in scheme.implementations:
if helpers.permit_test('preprocessor', implementation):
yield check_preprocessor, implementation yield check_preprocessor, implementation

View File

@ -17,6 +17,7 @@ def test_char():
) )
for scheme in pqclean.Scheme.all_schemes(): for scheme in pqclean.Scheme.all_schemes():
for implementation in scheme.implementations: for implementation in scheme.implementations:
if helpers.permit_test('char', implementation):
yield check_char, implementation yield check_char, implementation

View File

@ -16,7 +16,7 @@ def test_common():
def check_common(primitive): def check_common(primitive):
binname = os.path.join('..', 'bin', 'test_'+primitive) binname = os.path.join('..', 'bin', 'test_common_'+primitive)
helpers.make(binname) helpers.make(binname)
helpers.run_subprocess([binname]) helpers.run_subprocess([binname])

View File

@ -10,6 +10,7 @@ import helpers
def test_compile_lib(): def test_compile_lib():
for scheme in pqclean.Scheme.all_schemes(): for scheme in pqclean.Scheme.all_schemes():
for implementation in scheme.implementations: for implementation in scheme.implementations:
if helpers.permit_test('compile_lib', implementation):
yield check_compile_lib, implementation yield check_compile_lib, implementation

View File

@ -12,6 +12,7 @@ def test_duplicate_consistency():
helpers.skip_windows() helpers.skip_windows()
for scheme in pqclean.Scheme.all_schemes(): for scheme in pqclean.Scheme.all_schemes():
for implementation in scheme.implementations: for implementation in scheme.implementations:
if helpers.permit_test('duplicate_consistency', implementation):
if os.path.isfile(os.path.join('duplicate_consistency', '{}_{}.yml'.format(scheme.name, implementation.name))): 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)) metafile = os.path.join('duplicate_consistency', '{}_{}.yml'.format(implementation.scheme.name, implementation.name))
with open(metafile, encoding='utf-8') as f: with open(metafile, encoding='utf-8') as f:

View File

@ -11,6 +11,7 @@ import unittest
def test_dynamic_memory(): def test_dynamic_memory():
for scheme in pqclean.Scheme.all_schemes(): for scheme in pqclean.Scheme.all_schemes():
for implementation in scheme.implementations: for implementation in scheme.implementations:
if helpers.permit_test('dynamic_memory', implementation):
# Keep this loop outside, to allow multiple assertions # Keep this loop outside, to allow multiple assertions
for function in ['malloc', 'free', 'realloc', 'calloc']: for function in ['malloc', 'free', 'realloc', 'calloc']:
yield (check_dynamic_memory, implementation, function) yield (check_dynamic_memory, implementation, function)

View File

@ -1,22 +1,24 @@
import helpers
import pqclean import pqclean
from helpers import run_subprocess, ensure_available
def test_formatting(): def test_formatting():
for scheme in pqclean.Scheme.all_schemes(): for scheme in pqclean.Scheme.all_schemes():
for implementation in scheme.implementations: for implementation in scheme.implementations:
if helpers.permit_test('format', implementation):
yield check_format, implementation yield check_format, implementation
def check_format(implementation: pqclean.Implementation): def check_format(implementation: pqclean.Implementation):
ensure_available('astyle') helpers.ensure_available('astyle')
cfiles = implementation.cfiles() cfiles = implementation.cfiles()
hfiles = implementation.hfiles() hfiles = implementation.hfiles()
run_subprocess(['astyle', result = helpers.run_subprocess(['astyle',
'--dry-run', '--dry-run',
'--options=../.astylerc', '--options=../.astylerc',
*cfiles, *cfiles,
*hfiles]) *hfiles])
assert(not('Formatted' in result))
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -14,12 +14,14 @@ import helpers
def test_functest(): def test_functest():
for scheme in pqclean.Scheme.all_schemes(): for scheme in pqclean.Scheme.all_schemes():
for implementation in scheme.implementations: for implementation in scheme.implementations:
if helpers.permit_test('functest', implementation):
yield check_functest, implementation yield check_functest, implementation
def test_functest_sanitizers(): def test_functest_sanitizers():
for scheme in pqclean.Scheme.all_schemes(): for scheme in pqclean.Scheme.all_schemes():
for implementation in scheme.implementations: for implementation in scheme.implementations:
if helpers.permit_test('functest_sanitizers', implementation):
yield check_functest_sanitizers, implementation yield check_functest_sanitizers, implementation

View File

@ -5,11 +5,13 @@ implementation of the specified scheme.
import os import os
import pqclean import pqclean
import helpers
def test_license(): def test_license():
for scheme in pqclean.Scheme.all_schemes(): for scheme in pqclean.Scheme.all_schemes():
for implementation in scheme.implementations: for implementation in scheme.implementations:
if helpers.permit_test('license', implementation):
yield check_license, implementation yield check_license, implementation

View File

@ -1,24 +1,29 @@
import os import os
from glob import glob from glob import glob
import sys
import pqclean import pqclean
from helpers import run_subprocess, ensure_available import helpers
additional_flags = []
def test_clang_tidy(): def test_clang_tidy():
for scheme in pqclean.Scheme.all_schemes(): for scheme in pqclean.Scheme.all_schemes():
for implementation in scheme.implementations: for implementation in scheme.implementations:
if helpers.permit_test('linter', implementation):
yield check_tidy, implementation yield check_tidy, implementation
def check_tidy(implementation: pqclean.Implementation): def check_tidy(implementation: pqclean.Implementation):
ensure_available('clang-tidy') helpers.ensure_available('clang-tidy')
cfiles = glob(os.path.join(implementation.path(), '*.c')) cfiles = glob(os.path.join(implementation.path(), '*.c'))
common_files = glob(os.path.join('..', 'common', '*.c')) common_files = glob(os.path.join('..', 'common', '*.c'))
run_subprocess(['clang-tidy', helpers.run_subprocess(['clang-tidy',
'-quiet', '-quiet',
'-header-filter=.*', '-header-filter=.*'] +
*cfiles, additional_flags +
[*cfiles,
*common_files, *common_files,
'--', '--',
'-iquote', os.path.join('..', 'common'), '-iquote', os.path.join('..', 'common'),
@ -27,6 +32,10 @@ def check_tidy(implementation: pqclean.Implementation):
if __name__ == "__main__": 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: try:
import nose2 import nose2
nose2.main() nose2.main()

View File

@ -13,6 +13,7 @@ import datetime
def test_makefile_dependencies(): def test_makefile_dependencies():
for scheme in pqclean.Scheme.all_schemes(): for scheme in pqclean.Scheme.all_schemes():
for implementation in scheme.implementations: for implementation in scheme.implementations:
if helpers.permit_test('makefile_dependencies', implementation):
# initial build - want to have *all* files in place at beginning # initial build - want to have *all* files in place at beginning
helpers.make('clean', working_dir=implementation.path()) helpers.make('clean', working_dir=implementation.path())
helpers.make(working_dir=implementation.path()) helpers.make(working_dir=implementation.path())

View File

@ -3,12 +3,14 @@ Verify the metadata specified in the META.yml files.
""" """
import copy import copy
import helpers
import itertools import itertools
import pqclean import pqclean
def test_metadata(): def test_metadata():
for scheme in pqclean.Scheme.all_schemes(): for scheme in pqclean.Scheme.all_schemes():
if helpers.permit_test('metadata', scheme):
yield check_metadata, scheme yield check_metadata, scheme

View File

@ -8,6 +8,7 @@ import helpers
def test_metadata_sizes(): def test_metadata_sizes():
for scheme in pqclean.Scheme.all_schemes(): for scheme in pqclean.Scheme.all_schemes():
for implementation in scheme.implementations: for implementation in scheme.implementations:
if helpers.permit_test('metadata_sizes', implementation):
yield check_metadata_sizes, implementation yield check_metadata_sizes, implementation

View File

@ -4,11 +4,13 @@ Checks that no implementation makes use of symbolic links.
import os import os
import pqclean import pqclean
import helpers
def test_no_symlinks(): def test_no_symlinks():
for scheme in pqclean.Scheme.all_schemes(): for scheme in pqclean.Scheme.all_schemes():
for implementation in scheme.implementations: for implementation in scheme.implementations:
if helpers.permit_test('no_symlinks', implementation):
yield check_no_symlinks, implementation yield check_no_symlinks, implementation

View File

@ -2,12 +2,13 @@ import os
from glob import glob from glob import glob
import pqclean import pqclean
from helpers import run_subprocess, ensure_available import helpers
def test_preprocessor(): def test_preprocessor():
for scheme in pqclean.Scheme.all_schemes(): for scheme in pqclean.Scheme.all_schemes():
for implementation in scheme.implementations: for implementation in scheme.implementations:
if helpers.permit_test('preprocessor', implementation):
yield check_preprocessor, implementation yield check_preprocessor, implementation

View File

@ -12,6 +12,7 @@ import unittest
def test_symbol_namespace(): def test_symbol_namespace():
for scheme in pqclean.Scheme.all_schemes(): for scheme in pqclean.Scheme.all_schemes():
for implementation in scheme.implementations: for implementation in scheme.implementations:
if helpers.permit_test('symbol_namespace', implementation):
yield check_symbol_namespace, implementation yield check_symbol_namespace, implementation

View File

@ -12,6 +12,7 @@ import helpers
def test_testvectors(): def test_testvectors():
for scheme in pqclean.Scheme.all_schemes(): for scheme in pqclean.Scheme.all_schemes():
for implementation in scheme.implementations: for implementation in scheme.implementations:
if helpers.permit_test('testvectors', implementation):
yield check_vectors, implementation yield check_vectors, implementation

View File

@ -13,6 +13,7 @@ import helpers
def test_functest(): def test_functest():
for scheme in pqclean.Scheme.all_schemes(): for scheme in pqclean.Scheme.all_schemes():
for implementation in scheme.implementations: for implementation in scheme.implementations:
if helpers.permit_test('valgrind', implementation):
yield check_valgrind, implementation yield check_valgrind, implementation