From dbea1356853268fac5763b977304d8d3c67c10bb Mon Sep 17 00:00:00 2001 From: Kris Kwiatkowski Date: Wed, 24 Mar 2021 10:25:45 +0000 Subject: [PATCH] KEM and Sign C-API --- .cmake/common.mk | 36 ++------- CMakeLists.txt | 26 ++++--- src/capi/pqapi.c | 189 ++++++++++++++++++++++++++++++++++++++++++++--- src/capi/pqapi.h | 88 ++++++++++++++++++++++ test/mytest.cpp | 9 --- test/ut.cpp | 49 ++++++++++++ 6 files changed, 335 insertions(+), 62 deletions(-) create mode 100644 src/capi/pqapi.h delete mode 100644 test/mytest.cpp create mode 100644 test/ut.cpp diff --git a/.cmake/common.mk b/.cmake/common.mk index beacaef1..89c166e2 100644 --- a/.cmake/common.mk +++ b/.cmake/common.mk @@ -1,5 +1,8 @@ # Common function for defining algorithm component -function(define_crypto_alg name namespace src inc test_src) +function(define_crypto_alg name namespace src inc) + get_property(OBJ_LIBS GLOBAL PROPERTY obj_libs) + set_property(GLOBAL PROPERTY obj_libs ${OBJ_LIBS} pqclean_${name}) + add_library( pqclean_${name} OBJECT @@ -17,38 +20,11 @@ function(define_crypto_alg name namespace src inc test_src) -DPQCLEAN_NAMESPACE=${namespace} ) - add_library( - pqclean_test_${name} - OBJECT - ${test_src} - ) - - target_compile_definitions( - pqclean_test_${name} PRIVATE - -DPQCLEAN_NAMESPACE=${namespace} - ) - - target_include_directories( - pqclean_test_${name} PRIVATE - src/common - ${inc} - ) - - add_executable( - test_runner_${name} - ) - target_link_libraries( - test_runner_${name} - - common - pqclean_${name} - pqclean_test_${name} - ) endfunction() function(define_kem_alg name namespace src inc) - define_crypto_alg(${name} ${namespace} "${src}" "${inc}" ${PROJECT_SOURCE_DIR}/test/kem/testvectors.c) + define_crypto_alg(${name} ${namespace} "${src}" "${inc}") endfunction() function(define_sig_alg name namespace src inc) - define_crypto_alg(${name} ${namespace} "${src}" "${inc}" ${PROJECT_SOURCE_DIR}/test/sign/testvectors.c) + define_crypto_alg(${name} ${namespace} "${src}" "${inc}") endfunction() diff --git a/CMakeLists.txt b/CMakeLists.txt index 4b743ecf..cbeee123 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,7 @@ set(CMAKE_VERBOSE_MAKEFILE ON) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "~/.cmake/Modules") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "3rd/cmake-modules") set(CMAKE_CXX_STANDARD 11) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_LOWER) @@ -81,6 +82,9 @@ include_directories( src ) +set_property(GLOBAL PROPERTY obj_libs "") + + # Set CPU architecture set(CMAKE_C_FLAGS "${C_CXX_FLAGS} -D${ARCH}") set(CMAKE_CXX_FLAGS "${C_CXX_FLAGS} -D${ARCH}") @@ -118,6 +122,7 @@ add_subdirectory(src/sign/sphincs/sphincs-sha256-256s-robust/clean) add_subdirectory(src/sign/sphincs/sphincs-sha256-128s-robust/clean) add_subdirectory(src/sign/sphincs/sphincs-sha256-128f-simple/clean) add_subdirectory(src/sign/sphincs/sphincs-sha256-192f-robust/clean) + add_subdirectory(src/kem/kyber/kyber512/clean) add_subdirectory(src/kem/kyber/kyber768/clean) add_subdirectory(src/kem/kyber/kyber1024/clean) @@ -217,37 +222,34 @@ add_library( pqclean_s STATIC ) +get_property(OBJ_LIBS GLOBAL PROPERTY obj_libs) target_link_libraries( pqclean common - pqclean_dilithium2_clean - pqclean_dilithium3_clean - pqclean_dilithium5_clean + ${OBJ_LIBS} ) target_link_libraries( pqclean_s common - pqclean_dilithium2_clean - pqclean_dilithium3_clean - pqclean_dilithium5_clean + ${OBJ_LIBS} ) add_executable( - mytest + ut - test/mytest.cpp + test/ut.cpp ) target_link_libraries( - mytest + ut gtest - pqclean_s - gtest_main) + gtest_main + pqclean_s) target_include_directories( - mytest PRIVATE + ut PRIVATE ${CMAKE_SOURCE_DIR}) diff --git a/src/capi/pqapi.c b/src/capi/pqapi.c index ee08b9b7..76ef8be8 100644 --- a/src/capi/pqapi.c +++ b/src/capi/pqapi.c @@ -1,11 +1,122 @@ #include +#include #include "pqapi.h" + +// PQClean include +#include "sign/rainbow/rainbowV-classic/clean/api.h" +#include "sign/rainbow/rainbowI-classic/clean/api.h" +#include "sign/rainbow/rainbowIII-classic/clean/api.h" +#include "sign/sphincs/sphincs-sha256-192f-simple/clean/api.h" +#include "sign/sphincs/sphincs-sha256-192f-simple/avx2/api.h" +#include "sign/sphincs/sphincs-shake256-256f-simple/clean/api.h" +#include "sign/sphincs/sphincs-shake256-256f-simple/avx2/api.h" +#include "sign/sphincs/sphincs-shake256-192f-robust/clean/api.h" +#include "sign/sphincs/sphincs-shake256-192f-robust/avx2/api.h" +#include "sign/sphincs/sphincs-shake256-128f-simple/clean/api.h" +#include "sign/sphincs/sphincs-shake256-128f-simple/avx2/api.h" +#include "sign/sphincs/sphincs-shake256-256s-simple/clean/api.h" +#include "sign/sphincs/sphincs-shake256-256s-simple/avx2/api.h" +#include "sign/sphincs/sphincs-shake256-128s-simple/clean/api.h" +#include "sign/sphincs/sphincs-shake256-128s-simple/avx2/api.h" +#include "sign/sphincs/sphincs-sha256-128f-robust/clean/api.h" +#include "sign/sphincs/sphincs-sha256-128f-robust/avx2/api.h" +#include "sign/sphincs/sphincs-sha256-192s-robust/clean/api.h" +#include "sign/sphincs/sphincs-sha256-192s-robust/avx2/api.h" +#include "sign/sphincs/sphincs-shake256-128f-robust/clean/api.h" +#include "sign/sphincs/sphincs-shake256-128f-robust/avx2/api.h" +#include "sign/sphincs/sphincs-shake256-128s-robust/clean/api.h" +#include "sign/sphincs/sphincs-shake256-128s-robust/avx2/api.h" +#include "sign/sphincs/sphincs-shake256-256s-robust/clean/api.h" +#include "sign/sphincs/sphincs-shake256-256s-robust/avx2/api.h" +#include "sign/sphincs/sphincs-sha256-192s-simple/clean/api.h" +#include "sign/sphincs/sphincs-sha256-192s-simple/avx2/api.h" +#include "sign/sphincs/sphincs-shake256-192s-simple/clean/api.h" +#include "sign/sphincs/sphincs-shake256-192s-simple/avx2/api.h" +#include "sign/sphincs/sphincs-shake256-192s-robust/clean/api.h" +#include "sign/sphincs/sphincs-shake256-192s-robust/avx2/api.h" +#include "sign/sphincs/sphincs-shake256-192f-simple/clean/api.h" +#include "sign/sphincs/sphincs-shake256-192f-simple/avx2/api.h" +#include "sign/sphincs/sphincs-sha256-256s-simple/clean/api.h" +#include "sign/sphincs/sphincs-sha256-256s-simple/avx2/api.h" +#include "sign/sphincs/sphincs-sha256-128s-simple/clean/api.h" +#include "sign/sphincs/sphincs-sha256-128s-simple/avx2/api.h" +#include "sign/sphincs/sphincs-shake256-256f-robust/clean/api.h" +#include "sign/sphincs/sphincs-shake256-256f-robust/avx2/api.h" +#include "sign/sphincs/sphincs-sha256-256f-robust/clean/api.h" +#include "sign/sphincs/sphincs-sha256-256f-robust/avx2/api.h" +#include "sign/sphincs/sphincs-sha256-256f-simple/clean/api.h" +#include "sign/sphincs/sphincs-sha256-256f-simple/avx2/api.h" +#include "sign/sphincs/sphincs-sha256-256s-robust/clean/api.h" +#include "sign/sphincs/sphincs-sha256-256s-robust/avx2/api.h" +#include "sign/sphincs/sphincs-sha256-128s-robust/clean/api.h" +#include "sign/sphincs/sphincs-sha256-128s-robust/avx2/api.h" +#include "sign/sphincs/sphincs-sha256-128f-simple/clean/api.h" +#include "sign/sphincs/sphincs-sha256-128f-simple/avx2/api.h" +#include "sign/sphincs/sphincs-sha256-192f-robust/clean/api.h" +#include "sign/sphincs/sphincs-sha256-192f-robust/avx2/api.h" +#include "sign/falcon/falcon-1024/clean/api.h" +#include "sign/falcon/falcon-1024/avx2/api.h" +#include "sign/falcon/falcon-512/clean/api.h" +#include "sign/falcon/falcon-512/avx2/api.h" +#include "sign/dilithium/dilithium2/clean/api.h" +#include "sign/dilithium/dilithium2/avx2/api.h" +#include "sign/dilithium/dilithium3/clean/api.h" +#include "sign/dilithium/dilithium3/avx2/api.h" +#include "sign/dilithium/dilithium5/clean/api.h" +#include "sign/dilithium/dilithium5/avx2/api.h" +#include "kem/ntru/ntruhps4096821/clean/api.h" +#include "kem/ntru/ntruhps4096821/avx2/api.h" +#include "kem/ntru/ntruhps2048509/clean/api.h" +#include "kem/ntru/ntruhps2048509/avx2/api.h" +#include "kem/ntru/ntruhrss701/clean/api.h" +#include "kem/ntru/ntruhrss701/avx2/api.h" +#include "kem/ntru/ntruhps2048677/clean/api.h" +#include "kem/ntru/ntruhps2048677/avx2/api.h" +#include "kem/ntru_prime/ntrulpr761/clean/api.h" +#include "kem/ntru_prime/ntrulpr761/avx2/api.h" +#include "kem/ntru_prime/ntrulpr653/clean/api.h" +#include "kem/ntru_prime/ntrulpr653/avx2/api.h" +#include "kem/ntru_prime/ntrulpr857/clean/api.h" +#include "kem/ntru_prime/ntrulpr857/avx2/api.h" +#include "kem/kyber/kyber768/clean/api.h" +#include "kem/kyber/kyber768/avx2/api.h" +#include "kem/kyber/kyber1024/clean/api.h" +#include "kem/kyber/kyber1024/avx2/api.h" #include "kem/kyber/kyber512/clean/api.h" +#include "kem/kyber/kyber512/avx2/api.h" +#include "kem/mceliece/mceliece460896f/avx/api.h" +#include "kem/mceliece/mceliece460896f/clean/api.h" +#include "kem/mceliece/mceliece8192128/avx/api.h" +#include "kem/mceliece/mceliece8192128/clean/api.h" +#include "kem/mceliece/mceliece6688128f/avx/api.h" +#include "kem/mceliece/mceliece6688128f/clean/api.h" +#include "kem/mceliece/mceliece8192128f/avx/api.h" +#include "kem/mceliece/mceliece8192128f/clean/api.h" +#include "kem/mceliece/mceliece6960119f/avx/api.h" +#include "kem/mceliece/mceliece6960119f/clean/api.h" +#include "kem/mceliece/mceliece460896/avx/api.h" +#include "kem/mceliece/mceliece460896/clean/api.h" +#include "kem/mceliece/mceliece6688128/avx/api.h" +#include "kem/mceliece/mceliece6688128/clean/api.h" +#include "kem/mceliece/mceliece348864f/avx/api.h" +#include "kem/mceliece/mceliece348864f/clean/api.h" +#include "kem/mceliece/mceliece6960119/avx/api.h" +#include "kem/mceliece/mceliece6960119/clean/api.h" +#include "kem/mceliece/mceliece348864/avx/api.h" +#include "kem/mceliece/mceliece348864/clean/api.h" +#include "kem/frodo/frodokem976shake/clean/api.h" +#include "kem/frodo/frodokem1344shake/clean/api.h" +#include "kem/frodo/frodokem640shake/clean/api.h" +#include "kem/saber/lightsaber/clean/api.h" +#include "kem/saber/lightsaber/avx2/api.h" +#include "kem/saber/firesaber/clean/api.h" +#include "kem/saber/firesaber/avx2/api.h" +#include "kem/saber/saber/clean/api.h" +#include "kem/saber/saber/avx2/api.h" // helpers #define OPT_VERSION _CLEAN_ - // Helper to stringify constants #define STR(x) STR_(x) #define STR_(x) #x @@ -29,23 +140,79 @@ #define PQC_SIGN_BSZ(x) GLUE(A(x), CRYPTO_BYTES) #define PQC_CT_BSZ(x) GLUE(A(x), CRYPTO_CIPHERTEXTBYTES) #define PQC_NAME(x) GLUE(A(x), CRYPTO_ALGNAME) +#define PQC_FN_KEM_KEYGEN(x) GLUE(A(x), crypto_kem_keypair) +#define PQC_FN_SIG_KEYGEN(x) GLUE(A(x), crypto_sign_keypair) +#define PQC_FN_ENCAPS(x) GLUE(A(x), crypto_kem_enc) +#define PQC_FN_DECAPS(x) GLUE(A(x), crypto_kem_dec) +#define PQC_FN_SIGN(x) GLUE(A(x), crypto_sign_signature) +#define PQC_FN_VERIFY(x) GLUE(A(x), crypto_sign_verify) +#define REG_ALG(ID) \ +{ \ + .alg_id = ID, \ + .alg_name = STR(ID), \ + .prv_key_bsz = PQC_PRV_KEY_BSZ(ID), \ + .pub_key_bsz = PQC_PUB_KEY_BSZ(ID), \ +} // Macro magic needed to initialize parameters for a scheme -#define REG_KEM(ID) \ -{ \ - .p.alg_id = ID, \ - .p.alg_name = STR(ID), \ - .p.prv_key_bsz = PQC_PRV_KEY_BSZ(ID), \ - .p.pub_key_bsz = PQC_PUB_KEY_BSZ(ID), \ - .ciphertext_bsz = PQC_CT_BSZ(ID), \ - .secret_bsz = PQC_KEM_BSZ(ID) \ +#define REG_KEM(ID) \ +{ \ + .p = REG_ALG(ID), \ + .p.keygen = PQC_FN_KEM_KEYGEN(ID),\ + .ciphertext_bsz = PQC_CT_BSZ(ID), \ + .secret_bsz = PQC_KEM_BSZ(ID), \ + .encapsulate = PQC_FN_ENCAPS(ID), \ + .decapsulate = PQC_FN_DECAPS(ID), \ +} + +// Macro magic needed to initialize parameters for a scheme +#define REG_SIG(ID) \ +{ \ + .p = REG_ALG(ID), \ + .p.keygen = PQC_FN_SIG_KEYGEN(ID),\ + .sign_bsz = PQC_SIGN_BSZ(ID), \ + .sign = PQC_FN_SIGN(ID), \ + .verify = PQC_FN_VERIFY(ID), \ } enum { - KYBER512 + KYBER512, + KYBER768, + KYBER1024, + FALCON512, + DILITHIUM3, }; const kem_params_t kems[] = { - REG_KEM(KYBER512) + REG_KEM(KYBER512), + REG_KEM(KYBER768), + REG_KEM(KYBER1024), }; + +const sig_params_t sigs[] = { + REG_SIG(FALCON512), + REG_SIG(DILITHIUM3), +}; + +bool pqc_keygen(const params_t *p, uint8_t *sk, uint8_t *pk) { + return !p->keygen(sk, pk); +} + +bool pqc_kem_encapsulate(const params_t *p, uint8_t *ct, uint8_t *ss, const uint8_t *pk) { + return !((kem_params_t*)p)->encapsulate(ct, ss, pk); +} + +bool pqc_kem_decapsulate(const params_t *p, uint8_t *ss, const uint8_t *ct, const uint8_t *sk) { + return !((kem_params_t*)p)->decapsulate(ss, ct, sk); +} + +bool pqc_sig_create( + const params_t *p, uint8_t *sig, uint64_t *siglen, const uint8_t *m, uint64_t mlen, const uint8_t *sk) { + return !((sig_params_t *)p)->sign(sig, siglen, m, mlen, sk); +} + +bool pqc_sig_verify( + const params_t *p, const uint8_t *sig, uint64_t siglen, const uint8_t *m, uint64_t mlen, const uint8_t *pk) { + return !((sig_params_t *)p)->verify(sig, siglen, m, mlen, pk); +} diff --git a/src/capi/pqapi.h b/src/capi/pqapi.h new file mode 100644 index 00000000..030e8ba0 --- /dev/null +++ b/src/capi/pqapi.h @@ -0,0 +1,88 @@ +#ifndef PQAPI_H_ +#define PQAPI_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +// Parameters of the scheme +typedef struct params_t { + const uint8_t alg_id; + const char* alg_name; + const uint32_t prv_key_bsz; + const uint32_t pub_key_bsz; + const bool is_kem; + + int (*keygen)(uint8_t *sk, uint8_t *pk); +} params_t; + +typedef struct kem_params_t { + params_t p; + const uint32_t ciphertext_bsz; + const uint32_t secret_bsz; + + int (*encapsulate)(uint8_t *ct, uint8_t *ss, const uint8_t *pk); + int (*decapsulate)(uint8_t *ss, const uint8_t *ct, const uint8_t *sk); +} kem_params_t; + +typedef struct sig_params_t { + params_t p; + const uint32_t sign_bsz; + int (*sign)(uint8_t *sig, uint64_t *siglen, const uint8_t *m, uint64_t mlen, const uint8_t *sk); + int (*verify)(const uint8_t *sig, uint64_t siglen, const uint8_t *m, uint64_t mlen, const uint8_t *pk); +} sig_params_t; + +inline uint32_t ciphertext_bsz(const params_t *p) { + return ((kem_params_t *)p)->ciphertext_bsz; +} + +inline uint32_t shared_secret_bsz(const params_t *p) { + return ((kem_params_t *)p)->secret_bsz; +} + +inline uint32_t signature_bsz(const params_t *p) { + return ((sig_params_t *)p)->sign_bsz; +} + +inline uint32_t public_key_bsz(const params_t *p) { + return p->pub_key_bsz; +} + +inline uint32_t private_key_bsz(const params_t *p) { + return p->prv_key_bsz; +} + +bool pqc_keygen( + const params_t *p, + uint8_t *sk, uint8_t *pk); + +bool pqc_kem_encapsulate( + const params_t *p, + uint8_t *ct, uint8_t *ss, + const uint8_t *pk); + +bool pqc_kem_decapsulate( + const params_t *p, + uint8_t *ss, const uint8_t *ct, + const uint8_t *sk); + +bool pqc_sig_create( + const params_t *p, + uint8_t *sig, uint64_t *siglen, + const uint8_t *m, uint64_t mlen, + const uint8_t *sk); + +bool pqc_sig_verify( + const params_t *p, + const uint8_t *sig, uint64_t siglen, + const uint8_t *m, uint64_t mlen, + const uint8_t *pk); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/test/mytest.cpp b/test/mytest.cpp deleted file mode 100644 index a2f38ce5..00000000 --- a/test/mytest.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include -#include "capi/pqapi.h" - -extern const kem_params_t kems[]; - -// TODO: change - just to see if function registration works OK. -TEST(Kyber,XXX) { - ASSERT_EQ(kems[0].p.prv_key_bsz, 1632); -} \ No newline at end of file diff --git a/test/ut.cpp b/test/ut.cpp new file mode 100644 index 00000000..a9228206 --- /dev/null +++ b/test/ut.cpp @@ -0,0 +1,49 @@ +#include +#include +#include +#include "capi/pqapi.h" + +extern const kem_params_t kems[]; +extern const sig_params_t sigs[]; + +TEST(Kyber,KEMOneOff) { + + for (int i=0; i<3; i++) { + const params_t *p = (params_t*)&kems[i]; + + std::vector ct(ciphertext_bsz(p)); + std::vector ss1(shared_secret_bsz(p)); + std::vector ss2(shared_secret_bsz(p)); + std::vector sk(private_key_bsz(p)); + std::vector pk(public_key_bsz(p)); + + ASSERT_TRUE( + pqc_keygen(p, pk.data(), sk.data())); + ASSERT_TRUE( + pqc_kem_encapsulate(p, ct.data(), ss1.data(), pk.data())); + ASSERT_TRUE( + pqc_kem_decapsulate(p, ss2.data(), ct.data(), sk.data())); + ASSERT_TRUE( + std::equal(ss1.begin(), ss1.end(), ss2.begin())); + } +} + +TEST(Kyber,SIGNOneOff) { + + for (int i=0; i<2; i++) { + const params_t *p = (params_t*)&sigs[i]; + + uint8_t msg[1234]; + std::vector sig(signature_bsz(p)); + std::vector sk(private_key_bsz(p)); + std::vector pk(public_key_bsz(p)); + + ASSERT_TRUE( + pqc_keygen(p, pk.data(), sk.data())); + uint64_t sigsz = sig.size(); + ASSERT_TRUE( + pqc_sig_create(p, sig.data(), &sigsz, msg, 1234, sk.data())); + ASSERT_TRUE( + pqc_sig_verify(p, sig.data(), sigsz, msg, 1234, pk.data())); + } +}