diff --git a/.github/workflows/c.yml b/.github/workflows/c.yml new file mode 100644 index 0000000..8d85435 --- /dev/null +++ b/.github/workflows/c.yml @@ -0,0 +1,97 @@ +name: Test C implementation + +on: + push: + paths: + - '.github/workflows/c.yml' + - Makefile + - 'KAT/**' + - 'src/**' + - 'tests/**' + pull_request: + paths: + - '.github/workflows/c.yml' + - Makefile + - 'KAT/**' + - 'src/**' + - 'tests/**' + +jobs: + test-basic: + runs-on: ubuntu-latest + strategy: + matrix: + opt_level: ['GENERIC', 'FAST'] + steps: + - uses: actions/checkout@v2 + - name: Build + env: + OPT_LEVEL: ${{ matrix.opt_level }} + run: make + - name: SIKEp434 + run: make test434 + - name: SIKEp503 + run: make test503 + - name: SIKEp610 + run: make test610 + - name: SIKEp751 + run: make test751 + - name: SIKEp434 KATs + run: sike434/PQCtestKAT_kem + - name: SIKEp503 KATs + run: sike503/PQCtestKAT_kem + - name: SIKEp610 KATs + run: sike610/PQCtestKAT_kem + - name: SIKEp751 KATs + run: sike751/PQCtestKAT_kem + test-sanitize: + runs-on: ubuntu-latest + strategy: + matrix: + opt_level: ['GENERIC', 'FAST'] + sanitizer: ['address', 'undefined'] + steps: + - uses: actions/checkout@v2 + - name: Build + env: + OPT_LEVEL: ${{ matrix.opt_level }} + EXTRA_CFLAGS: -g3 -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize-address-use-after-scope -fsanitize=${{ matrix.sanitizer }} -fno-sanitize-recover=${{ matrix.sanitizer }} + run: make CC=clang-11 + - name: SIKEp434 + run: sike434/test_SIKE nobench + - name: SIKEp503 + run: sike503/test_SIKE nobench + - name: SIKEp610 + run: sike610/test_SIKE nobench + - name: SIKEp751 + run: sike751/test_SIKE nobench + test-valgrind-constant-time: + runs-on: ubuntu-latest + strategy: + matrix: + opt_level: ['GENERIC', 'FAST'] + steps: + - uses: actions/checkout@v2 + - name: Install valgrind + run: sudo apt-get install -y valgrind + - name: Build + env: + DO_VALGRIND_CHECK: "TRUE" + OPT_LEVEL: ${{ matrix.opt_level }} + run: make CC=clang-11 + - name: SIKEp434 + env: + DO_VALGRIND_CHECK: "TRUE" + run: make test434 + - name: SIKEp503 + env: + DO_VALGRIND_CHECK: "TRUE" + run: make test503 + - name: SIKEp610 + env: + DO_VALGRIND_CHECK: "TRUE" + run: make test610 + - name: SIKEp751 + env: + DO_VALGRIND_CHECK: "TRUE" + run: make test751 diff --git a/Makefile b/Makefile index f8d4d17..b2188c9 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,5 @@ #### Makefile for compilation on Unix-like operative systems #### -OPT=-O3 # Optimization option by default - CC=clang ifeq "$(CC)" "gcc" COMPILER=gcc @@ -65,7 +63,18 @@ ifeq "$(ARCHITECTURE)" "_S390X_" ADDITIONAL_SETTINGS=-march=z10 endif -CFLAGS=$(OPT) -std=gnu11 $(ADDITIONAL_SETTINGS) -D $(ARCHITECTURE) -D __NIX__ -D $(USE_OPT_LEVEL) $(MULX) $(ADX) +VALGRIND_CFLAGS= +ifeq "$(DO_VALGRIND_CHECK)" "TRUE" +VALGRIND_CFLAGS= -g -O0 -DDO_VALGRIND_CHECK +endif + +ifeq "$(EXTRA_CFLAGS)" "" +CFLAGS= -O3 # Optimization option by default +else +CFLAGS= $(EXTRA_CFLAGS) +endif +CFLAGS+= $(VALGRIND_CFLAGS) +CFLAGS+= -std=gnu11 $(ADDITIONAL_SETTINGS) -D $(ARCHITECTURE) -D __NIX__ -D $(USE_OPT_LEVEL) $(MULX) $(ADX) LDFLAGS=-lm ifeq "$(USE_OPT_LEVEL)" "_GENERIC_" EXTRA_OBJECTS_434=objs434/fp_generic.o @@ -320,6 +329,34 @@ KATS: lib434_for_KATs lib503_for_KATs lib610_for_KATs lib751_for_KATs lib434comp check: tests +test434: +ifeq "$(DO_VALGRIND_CHECK)" "TRUE" + valgrind --tool=memcheck --error-exitcode=1 --max-stackframe=20480000 sike434/test_SIKE +else + sike434/test_SIKE +endif + +test503: +ifeq "$(DO_VALGRIND_CHECK)" "TRUE" + valgrind --tool=memcheck --error-exitcode=1 --max-stackframe=20480000 sike503/test_SIKE +else + sike503/test_SIKE +endif + +test610: +ifeq "$(DO_VALGRIND_CHECK)" "TRUE" + valgrind --tool=memcheck --error-exitcode=1 --max-stackframe=20480000 sike610/test_SIKE +else + sike610/test_SIKE +endif + +test751: +ifeq "$(DO_VALGRIND_CHECK)" "TRUE" + valgrind --tool=memcheck --error-exitcode=1 --max-stackframe=20480000 sike751/test_SIKE +else + sike751/test_SIKE +endif + .PHONY: clean clean: diff --git a/src/sike.c b/src/sike.c index c166450..36d7293 100644 --- a/src/sike.c +++ b/src/sike.c @@ -7,6 +7,10 @@ #include #include "sha3/fips202.h" +#ifdef DO_VALGRIND_CHECK +#include +#endif + int crypto_kem_keypair(unsigned char *pk, unsigned char *sk) { // SIKE's key generation @@ -16,6 +20,9 @@ int crypto_kem_keypair(unsigned char *pk, unsigned char *sk) // Generate lower portion of secret key sk <- s||SK randombytes(sk, MSG_BYTES); random_mod_order_B(sk + MSG_BYTES); +#ifdef DO_VALGRIND_CHECK + VALGRIND_MAKE_MEM_UNDEFINED(sk, MSG_BYTES + SECRETKEY_B_BYTES); +#endif // Generate public key pk EphemeralKeyGeneration_B(sk + MSG_BYTES, pk); @@ -23,6 +30,9 @@ int crypto_kem_keypair(unsigned char *pk, unsigned char *sk) // Append public key pk to secret key sk memcpy(&sk[MSG_BYTES + SECRETKEY_B_BYTES], pk, CRYPTO_PUBLICKEYBYTES); +#ifdef DO_VALGRIND_CHECK + VALGRIND_MAKE_MEM_DEFINED(sk, MSG_BYTES + SECRETKEY_B_BYTES); +#endif return 0; } @@ -39,6 +49,9 @@ int crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk // Generate ephemeralsk <- G(m||pk) mod oA randombytes(temp, MSG_BYTES); +#ifdef DO_VALGRIND_CHECK + VALGRIND_MAKE_MEM_UNDEFINED(temp, MSG_BYTES); +#endif memcpy(&temp[MSG_BYTES], pk, CRYPTO_PUBLICKEYBYTES); shake256(ephemeralsk, SECRETKEY_A_BYTES, temp, CRYPTO_PUBLICKEYBYTES+MSG_BYTES); ephemeralsk[SECRETKEY_A_BYTES - 1] &= MASK_ALICE; @@ -55,6 +68,9 @@ int crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk memcpy(&temp[MSG_BYTES], ct, CRYPTO_CIPHERTEXTBYTES); shake256(ss, CRYPTO_BYTES, temp, CRYPTO_CIPHERTEXTBYTES+MSG_BYTES); +#ifdef DO_VALGRIND_CHECK + VALGRIND_MAKE_MEM_DEFINED(temp, MSG_BYTES); +#endif return 0; } @@ -69,6 +85,9 @@ int crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned ch unsigned char h_[MSG_BYTES]; unsigned char c0_[CRYPTO_PUBLICKEYBYTES]; unsigned char temp[CRYPTO_CIPHERTEXTBYTES+MSG_BYTES]; +#ifdef DO_VALGRIND_CHECK + VALGRIND_MAKE_MEM_UNDEFINED(sk, CRYPTO_SECRETKEYBYTES); +#endif // Decrypt EphemeralSecretAgreement_B(sk + MSG_BYTES, ct, jinvariant_); @@ -89,6 +108,9 @@ int crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned ch ct_cmov(temp, sk, MSG_BYTES, selector); memcpy(&temp[MSG_BYTES], ct, CRYPTO_CIPHERTEXTBYTES); shake256(ss, CRYPTO_BYTES, temp, CRYPTO_CIPHERTEXTBYTES+MSG_BYTES); - + +#ifdef DO_VALGRIND_CHECK + VALGRIND_MAKE_MEM_DEFINED(sk, CRYPTO_SECRETKEYBYTES); +#endif return 0; } \ No newline at end of file diff --git a/tests/test_sike.c b/tests/test_sike.c index 34483be..33007ae 100644 --- a/tests/test_sike.c +++ b/tests/test_sike.c @@ -6,14 +6,24 @@ #include "../src/random/random.h" +#ifdef DO_VALGRIND_CHECK +#include +#endif -// Benchmark and test parameters +#ifdef DO_VALGRIND_CHECK + #define TEST_LOOPS 1 +#else #if defined(GENERIC_IMPLEMENTATION) || (TARGET == TARGET_ARM) - #define BENCH_LOOPS 5 // Number of iterations per bench #define TEST_LOOPS 5 // Number of iterations per test #else - #define BENCH_LOOPS 100 #define TEST_LOOPS 10 +#endif +#endif + +#if defined(GENERIC_IMPLEMENTATION) || (TARGET == TARGET_ARM) + #define BENCH_LOOPS 5 // Number of iterations per bench +#else + #define BENCH_LOOPS 100 #endif @@ -29,6 +39,14 @@ int cryptotest_kem() uint32_t* pos = (uint32_t*)bytes; bool passed = true; + #ifdef DO_VALGRIND_CHECK + if (!RUNNING_ON_VALGRIND) { + fprintf(stderr, "This test can only usefully be run inside valgrind.\n"); + fprintf(stderr, "valgrind sikexxx/test_SIKE\n"); + exit(1); + } + #endif + printf("\n\nTESTING ISOGENY-BASED KEY ENCAPSULATION MECHANISM %s\n", SCHEME_NAME); printf("--------------------------------------------------------------------------------------------------------\n\n"); @@ -37,6 +55,10 @@ int cryptotest_kem() crypto_kem_keypair(pk, sk); crypto_kem_enc(ct, ss, pk); crypto_kem_dec(ss_, ct, sk); +#ifdef DO_VALGRIND_CHECK + VALGRIND_MAKE_MEM_DEFINED(ss, CRYPTO_BYTES); + VALGRIND_MAKE_MEM_DEFINED(ss_, CRYPTO_BYTES); +#endif if (memcmp(ss, ss_, CRYPTO_BYTES) != 0) { passed = false; @@ -48,6 +70,10 @@ int cryptotest_kem() *pos %= CRYPTO_CIPHERTEXTBYTES; ct[*pos] ^= 1; crypto_kem_dec(ss_, ct, sk); +#ifdef DO_VALGRIND_CHECK + VALGRIND_MAKE_MEM_DEFINED(ss, CRYPTO_BYTES); + VALGRIND_MAKE_MEM_DEFINED(ss_, CRYPTO_BYTES); +#endif if (memcmp(ss, ss_, CRYPTO_BYTES) == 0) { passed = false; @@ -108,21 +134,24 @@ int cryptorun_kem() } -int main() +int main(int argc, char **argv) { int Status = PASSED; - Status = cryptotest_kem(); // Test key encapsulation mechanism + Status = cryptotest_kem(); // Test key encapsulation mechanism if (Status != PASSED) { printf("\n\n Error detected: KEM_ERROR_SHARED_KEY \n\n"); return FAILED; } - - Status = cryptorun_kem(); // Benchmark key encapsulation mechanism - if (Status != PASSED) { - printf("\n\n Error detected: KEM_ERROR_SHARED_KEY \n\n"); - return FAILED; + + if ((argc > 1) && (strcmp("nobench", argv[1]) == 0)) {} + else { + Status = cryptorun_kem(); // Benchmark key encapsulation mechanism + if (Status != PASSED) { + printf("\n\n Error detected: KEM_ERROR_SHARED_KEY \n\n"); + return FAILED; + } } return Status; -} \ No newline at end of file +}