소스 검색

Reimplement Python tests using nose framework

master
Douglas Stebila 5 년 전
부모
커밋
f64a7e0dd4
12개의 변경된 파일206개의 추가작업 그리고 8개의 파일을 삭제
  1. +2
    -0
      .gitignore
  2. +4
    -1
      .travis.yml
  3. +4
    -4
      Makefile
  4. +3
    -3
      crypto_kem/kyber768/clean/Makefile
  5. +1
    -0
      requirements.txt
  6. +25
    -0
      test/Makefile
  7. +0
    -0
      test/check_tvectors.py
  8. +13
    -0
      test/helpers.py
  9. +103
    -0
      test/pqclean.py
  10. +15
    -0
      test/test_compile_lib.py
  11. +23
    -0
      test/test_functest.py
  12. +13
    -0
      test/test_license.py

+ 2
- 0
.gitignore 파일 보기

@@ -8,3 +8,5 @@ bin/
# Object and library files on Windows
*.lib
*.obj

__pycache__

+ 4
- 1
.travis.yml 파일 보기

@@ -14,6 +14,7 @@ matrix:
packages:
- python3
- python3-yaml
- python3-nose
- valgrind
- name: "Linux + Clang"
os: linux
@@ -25,6 +26,7 @@ matrix:
packages:
- python3
- python3-yaml
- python3-nose
- valgrind
- name: "Linux 32-bit GCC"
os: linux
@@ -35,6 +37,7 @@ matrix:
- gcc-multilib
- python3
- python3-yaml
- python3-nose
- valgrind
before_install:
- sudo dpkg --add-architecture i386
@@ -74,7 +77,7 @@ matrix:

script:
- make ${MAKETARGET}
- cd test && nosetest -v

cache: pip



+ 4
- 4
Makefile 파일 보기

@@ -159,17 +159,17 @@ run-valgrind-all:
done

.PHONY: run-testvectors
run-testvectors: test/check_testvectors.py | require_scheme
python3 test/check_testvectors.py $(SCHEME) || exit 1; \
run-testvectors: test/check_tvectors.py | require_scheme
python3 test/check_tvectors.py $(SCHEME) || exit 1; \

.PHONY: run-symbol-namespace
run-symbol-namespace: test/check_symbol_namespace.py | require_scheme
python3 test/check_symbol_namespace.py $(SCHEME) || exit 1; \

.PHONY: run-testvectors-all
run-testvectors-all: test/check_testvectors.py
run-testvectors-all: test/check_tvectors.py
@for scheme in $(ALL_SCHEMES); do \
python3 test/check_testvectors.py $$scheme || exit 1; \
python3 test/check_tvectors.py $$scheme || exit 1; \
done

.PHONY: run-symbol-namespace-all


+ 3
- 3
crypto_kem/kyber768/clean/Makefile 파일 보기

@@ -8,8 +8,8 @@ CFLAGS=-Wall -Wextra -Wpedantic -Werror -std=c99 -I../../../common $(EXTRAFLAGS)
all: $(LIB)

$(LIB): $(OBJECTS)
$(AR) -r $@ $(OBJECTS)
$(AR) -r $@ $(OBJECTS)

clean:
$(RM) $(OBJECTS)
$(RM) $(LIB)
$(RM) $(OBJECTS)
$(RM) $(LIB)

+ 1
- 0
requirements.txt 파일 보기

@@ -1 +1,2 @@
PyYAML
nose

+ 25
- 0
test/Makefile 파일 보기

@@ -0,0 +1,25 @@
# This Makefile can be used with GNU Make or BSD Make

# override as desired
TYPE=kem
SCHEME=kyber768
IMPLEMENTATION=clean

SCHEME_DIR="../crypto_$(TYPE)/$(SCHEME)/$(IMPLEMENTATION)"
SCHEME_UPPERCASE=$(shell echo $(SCHEME) | tr a-z A-Z | sed 's/-//')

COMMON_DIR=../common
COMMON_FILES=$(COMMON_DIR)/randombytes.c $(COMMON_DIR)/fips202.c $(COMMON_DIR)/sha2.c
DEST_DIR=../bin

CFLAGS=-Wall -Wextra -Wpedantic -Werror -std=c99 -I$(COMMON_DIR) $(EXTRAFLAGS)

all: $(DEST_DIR)/functest_$(SCHEME)_$(IMPLEMENTATION)

$(DEST_DIR)/functest_$(SCHEME)_$(IMPLEMENTATION): crypto_$(TYPE)/functest.c $(COMMON_FILES)
mkdir -p $(DEST_DIR)
cd $(SCHEME_DIR) && make clean && make
$(CC) $(CFLAGS) -DPQCLEAN_NAMESPACE=PQCLEAN_$(SCHEME_UPPERCASE) -I$(SCHEME_DIR) crypto_$(TYPE)/functest.c $(COMMON_FILES) -o $@ -L$(SCHEME_DIR) -l$(SCHEME)_$(IMPLEMENTATION)

clean:
$(RM) $(DEST_DIR)/functest_$(SCHEME)_$(IMPLEMENTATION)

test/check_testvectors.py → test/check_tvectors.py 파일 보기


+ 13
- 0
test/helpers.py 파일 보기

@@ -0,0 +1,13 @@
import subprocess

def run_subprocess(command, working_dir, expected_returncode = 0):
"""Helper function to run a shell command and report success/failure depending on the exit status of the shell command."""
# Note we need to capture stdout/stderr from the subprocess, then print it, which nose/unittest will then capture and buffer appropriately
result = subprocess.run(
command,
stdout = subprocess.PIPE,
stderr = subprocess.STDOUT,
cwd = working_dir
)
print(result.stdout.decode('utf-8'))
assert(result.returncode == expected_returncode)

+ 103
- 0
test/pqclean.py 파일 보기

@@ -0,0 +1,103 @@
import os
import yaml

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)

@staticmethod
def by_name(scheme_name):
for scheme in Scheme.all_schemes():
if scheme.name == scheme_name:
return scheme
raise KeyError()

@staticmethod
def all_schemes():
schemes = []
schemes.extend(Scheme.all_schemes_of_type('kem'))
schemes.extend(Scheme.all_schemes_of_type('sign'))
return schemes

@staticmethod
def all_implementations():
implementations = dict()
for scheme in Scheme.all_schemes().values():
implementations.extend(scheme.all_implementations())
return implementations

@staticmethod
def all_schemes_of_type(type: str) -> list:
schemes = []
p = os.path.join('..', 'crypto_' + type)
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

def metadata(self):
metafile = os.path.join(self.path(), 'META.yml')
try:
with open(metafile, encoding='utf-8') as f:
metadata = yaml.load(f.read())
return metadata
except Exception as e:
print("Can't open {}: {}".format(metafile, e))
return None

class Implementation:

def __init__(self, scheme, name):
self.scheme = scheme
self.name = name

def path(self, base='..') -> str:
return os.path.join(self.scheme.path(), self.name)

@staticmethod
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
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

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('sig')

+ 15
- 0
test/test_compile_lib.py 파일 보기

@@ -0,0 +1,15 @@
import os
import pqclean
import helpers

def test_compile_lib():
for scheme in pqclean.Scheme.all_schemes():
for implementation in scheme.implementations:
yield check_compile_lib, scheme.name, implementation.name

def check_compile_lib(scheme_name, implementation_name):
implementation = pqclean.Implementation.by_name(scheme_name, implementation_name)
helpers.run_subprocess(
['make'],
implementation.path()
)

+ 23
- 0
test/test_functest.py 파일 보기

@@ -0,0 +1,23 @@
import os
import pqclean
import helpers

def test_functest():
for scheme in pqclean.Scheme.all_schemes():
for implementation in scheme.implementations:
yield check_functest, scheme.name, implementation.name

def check_functest(scheme_name, implementation_name):
implementation = pqclean.Implementation.by_name(scheme_name, implementation_name)
helpers.run_subprocess(
['make', 'clean', 'TYPE=' + implementation.scheme.type, 'SCHEME=' + scheme_name, 'IMPLEMENTATION=' + implementation_name],
os.path.join('..', 'test')
)
helpers.run_subprocess(
['make', 'TYPE=' + implementation.scheme.type, 'SCHEME=' + scheme_name, 'IMPLEMENTATION=' + implementation_name],
os.path.join('..', 'test')
)
helpers.run_subprocess(
['./functest_{}_{}'.format(scheme_name, implementation_name)],
os.path.join('..', 'bin'),
)

+ 13
- 0
test/test_license.py 파일 보기

@@ -0,0 +1,13 @@
import os
import pqclean

def test_license():
for scheme in pqclean.Scheme.all_schemes():
for implementation in scheme.implementations:
yield check_license, scheme.name, implementation.name

def check_license(scheme_name, implementation_name):
implementation = pqclean.Implementation.by_name(scheme_name, implementation_name)
p1 = os.path.join(implementation.path(), 'LICENSE')
p2 = os.path.join(implementation.path(), 'LICENSE.txt')
assert(os.path.isfile(p1) or os.path.isfile(p2))

불러오는 중...
취소
저장