diff --git a/CHANGES.txt b/CHANGES.txt index 170e51a..93cf4ee 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,7 +1,8 @@ -Pre-release +Version 0.3.0 - June 10, 2020 - Removed the Visual Studio solution (since it can be automatically generated by CMake), as we prefer to use CMake uniformly across all platforms + - Minor fixes Version 0.2.2 - January 16, 2020 - Added additional RNG example project to Visual Studio solution diff --git a/CMakeLists.txt b/CMakeLists.txt index 58dcab0..f46bd85 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.2) -project(oqs_cpp) +project(oqs_cpp VERSION 0.3.0 LANGUAGES CXX) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) diff --git a/Doxyfile b/Doxyfile index a1d7d87..5a0f37d 100644 --- a/Doxyfile +++ b/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = "liboqs-cpp" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 0.2.1 +PROJECT_NUMBER = 0.3.0 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/RELEASE.md b/RELEASE.md index a2ff1c9..ee8f70b 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1,4 +1,4 @@ -liboqs-cpp version 0.2.2 +liboqs-cpp version 0.3.0 ======================== About @@ -13,9 +13,9 @@ The **Open Quantum Safe (OQS) project** has the goal of developing and prototypi Release notes ============= -This release of liboqs-cpp was released on January 16, 2020. Its release page on GitHub is https://github.com/open-quantum-safe/liboqs-cpp/releases/tag/0.2.2. +This release of liboqs-cpp was released on June 10, 2020. Its release page on GitHub is https://github.com/open-quantum-safe/liboqs-cpp/releases/tag/0.3.0. What's New ---------- -This is the sixth release of liboqs-cpp. For a list of changes see [CHANGES.txt](https://github.com/open-quantum-safe/liboqs-cpp/blob/master/CHANGES.txt). +This is the seventh release of liboqs-cpp. For a list of changes see [CHANGES.txt](https://github.com/open-quantum-safe/liboqs-cpp/blob/master/CHANGES.txt). diff --git a/unit_tests/tests/test_kem.cpp b/unit_tests/tests/test_kem.cpp index 1ee01c8..6ba4749 100644 --- a/unit_tests/tests/test_kem.cpp +++ b/unit_tests/tests/test_kem.cpp @@ -9,6 +9,7 @@ #include #include "oqs_cpp.h" +#include "rand/rand.h" // no_thread_KEM_patterns lists KEM patterns that have issues running in a // separate thread @@ -18,10 +19,10 @@ static std::vector no_thread_KEM_patterns{"Classic-McEliece", // used for thread-safe console output static std::mutex mu; -void test_kem(const std::string& kem_name) { +void test_kem_correctness(const std::string& kem_name) { { std::lock_guard lg{mu}; - std::cout << kem_name << std::endl; + std::cout << "Correctness - " << kem_name << std::endl; } oqs::KeyEncapsulation client{kem_name}; oqs::bytes client_public_key = client.generate_keypair(); @@ -37,7 +38,65 @@ void test_kem(const std::string& kem_name) { EXPECT_TRUE(is_valid); } -TEST(oqs_KeyEncapsulation, Enabled) { +void test_kem_wrong_ciphertext(const std::string& kem_name) { + { + std::lock_guard lg{mu}; + std::cout << "Wrong ciphertext - " << kem_name << std::endl; + } + oqs::KeyEncapsulation client{kem_name}; + oqs::bytes client_public_key = client.generate_keypair(); + oqs::KeyEncapsulation server{kem_name}; + oqs::bytes ciphertext, shared_secret_server; + std::tie(ciphertext, shared_secret_server) = + server.encap_secret(client_public_key); + oqs::bytes wrong_ciphertext = oqs::rand::randombytes(ciphertext.size()); + oqs::bytes shared_secret_client; + try { + shared_secret_client = client.decap_secret(wrong_ciphertext); + } catch (std::exception& e) { + if (e.what() == std::string{"Can not decapsulate secret"}) + return; + else + throw; // this is another un-expected exception + } + bool is_valid = (shared_secret_client == shared_secret_server); + if (is_valid) + std::cerr << kem_name << ": shared secrets should not coincide" + << std::endl; + EXPECT_FALSE(is_valid); +} + +TEST(oqs_KeyEncapsulation, Correctness) { + std::vector thread_pool; + std::vector enabled_KEMs = oqs::KEMs::get_enabled_KEMs(); + // first test KEMs that belong to no_thread_KEM_patterns[] in the main + // thread (stack size is 8Mb on macOS), due to issues with stack size being + // too small in macOS (512Kb for threads) + for (auto&& kem_name : enabled_KEMs) { + for (auto&& no_thread_kem : no_thread_KEM_patterns) { + if (kem_name.find(no_thread_kem) != std::string::npos) { + test_kem_correctness(kem_name); + } + } + } + // test the remaining KEMs in separate threads + for (auto&& kem_name : enabled_KEMs) { + bool test_in_thread = true; + for (auto&& no_thread_kem : no_thread_KEM_patterns) { + if (kem_name.find(no_thread_kem) != std::string::npos) { + test_in_thread = false; + break; + } + } + if (test_in_thread) + thread_pool.emplace_back(test_kem_correctness, kem_name); + } + // join the rest of the threads + for (auto&& elem : thread_pool) + elem.join(); +} + +TEST(oqs_KeyEncapsulation, WrongCiphertext) { std::vector thread_pool; std::vector enabled_KEMs = oqs::KEMs::get_enabled_KEMs(); // first test KEMs that belong to no_thread_KEM_patterns[] in the main @@ -46,7 +105,7 @@ TEST(oqs_KeyEncapsulation, Enabled) { for (auto&& kem_name : enabled_KEMs) { for (auto&& no_thread_kem : no_thread_KEM_patterns) { if (kem_name.find(no_thread_kem) != std::string::npos) { - test_kem(kem_name); + test_kem_wrong_ciphertext(kem_name); } } } @@ -60,7 +119,7 @@ TEST(oqs_KeyEncapsulation, Enabled) { } } if (test_in_thread) - thread_pool.emplace_back(test_kem, kem_name); + thread_pool.emplace_back(test_kem_wrong_ciphertext, kem_name); } // join the rest of the threads for (auto&& elem : thread_pool) diff --git a/unit_tests/tests/test_sig.cpp b/unit_tests/tests/test_sig.cpp index ce4f0fc..358a42f 100644 --- a/unit_tests/tests/test_sig.cpp +++ b/unit_tests/tests/test_sig.cpp @@ -8,6 +8,7 @@ #include #include "oqs_cpp.h" +#include "rand/rand.h" // no_thread_sig_patterns lists sig patterns that have issues running in a // separate thread @@ -17,10 +18,10 @@ static std::vector no_thread_sig_patterns{"Rainbow-IIIc", // used for thread-safe console output static std::mutex mu; -void test_sig(const std::string& sig_name, const oqs::bytes& msg) { +void test_sig_correctness(const std::string& sig_name, const oqs::bytes& msg) { { std::lock_guard lg{mu}; - std::cout << sig_name << std::endl; + std::cout << "Correctness - " << sig_name << std::endl; } oqs::Signature signer{sig_name}; oqs::bytes signer_public_key = signer.generate_keypair(); @@ -32,7 +33,107 @@ void test_sig(const std::string& sig_name, const oqs::bytes& msg) { EXPECT_TRUE(is_valid); } -TEST(oqs_Signature, Enabled) { +void test_sig_wrong_signature(const std::string& sig_name, + const oqs::bytes& msg) { + { + std::lock_guard lg{mu}; + std::cout << "Wrong signature - " << sig_name << std::endl; + } + oqs::Signature signer{sig_name}; + oqs::bytes signer_public_key = signer.generate_keypair(); + oqs::bytes signature = signer.sign(msg); + oqs::bytes wrong_signature = oqs::rand::randombytes(signature.size()); + oqs::Signature verifier{sig_name}; + bool is_valid = verifier.verify(msg, wrong_signature, signer_public_key); + if (is_valid) + std::cerr << sig_name << ": signature verification should have failed" + << std::endl; + EXPECT_FALSE(is_valid); +} + +void test_sig_wrong_public_key(const std::string& sig_name, + const oqs::bytes& msg) { + { + std::lock_guard lg{mu}; + std::cout << "Wrong public key - " << sig_name << std::endl; + } + oqs::Signature signer{sig_name}; + oqs::bytes signer_public_key = signer.generate_keypair(); + oqs::bytes wrong_public_key = + oqs::rand::randombytes(signer_public_key.size()); + oqs::bytes signature = signer.sign(msg); + oqs::Signature verifier{sig_name}; + bool is_valid = verifier.verify(msg, signature, wrong_public_key); + if (is_valid) + std::cerr << sig_name << ": signature verification should have failed" + << std::endl; + EXPECT_FALSE(is_valid); +} + +TEST(oqs_Signature, Correctness) { + oqs::bytes message = "This is our favourite message to sign"_bytes; + std::vector thread_pool; + std::vector enabled_sigs = oqs::Sigs::get_enabled_sigs(); + // first test sigs that belong to no_thread_sig_patterns[] in the main + // thread (stack size is 8Mb on macOS), due to issues with stack size being + // too small in macOS (512Kb for threads) + for (auto&& sig_name : enabled_sigs) { + for (auto&& no_thread_sig : no_thread_sig_patterns) { + if (sig_name.find(no_thread_sig) != std::string::npos) { + test_sig_correctness(sig_name, message); + } + } + } + // test the remaining sigs in separate threads + for (auto&& sig_name : enabled_sigs) { + bool test_in_thread = true; + for (auto&& no_thread_sig : no_thread_sig_patterns) { + if (sig_name.find(no_thread_sig) != std::string::npos) { + test_in_thread = false; + break; + } + } + if (test_in_thread) + thread_pool.emplace_back(test_sig_correctness, sig_name, message); + } + // join the rest of the threads + for (auto&& elem : thread_pool) + elem.join(); +} + +TEST(oqs_Signature, WrongSignature) { + oqs::bytes message = "This is our favourite message to sign"_bytes; + std::vector thread_pool; + std::vector enabled_sigs = oqs::Sigs::get_enabled_sigs(); + // first test sigs that belong to no_thread_sig_patterns[] in the main + // thread (stack size is 8Mb on macOS), due to issues with stack size being + // too small in macOS (512Kb for threads) + for (auto&& sig_name : enabled_sigs) { + for (auto&& no_thread_sig : no_thread_sig_patterns) { + if (sig_name.find(no_thread_sig) != std::string::npos) { + test_sig_wrong_signature(sig_name, message); + } + } + } + // test the remaining sigs in separate threads + for (auto&& sig_name : enabled_sigs) { + bool test_in_thread = true; + for (auto&& no_thread_sig : no_thread_sig_patterns) { + if (sig_name.find(no_thread_sig) != std::string::npos) { + test_in_thread = false; + break; + } + } + if (test_in_thread) + thread_pool.emplace_back(test_sig_wrong_signature, sig_name, + message); + } + // join the rest of the threads + for (auto&& elem : thread_pool) + elem.join(); +} + +TEST(oqs_Signature, WrongPublicKey) { oqs::bytes message = "This is our favourite message to sign"_bytes; std::vector thread_pool; std::vector enabled_sigs = oqs::Sigs::get_enabled_sigs(); @@ -42,7 +143,7 @@ TEST(oqs_Signature, Enabled) { for (auto&& sig_name : enabled_sigs) { for (auto&& no_thread_sig : no_thread_sig_patterns) { if (sig_name.find(no_thread_sig) != std::string::npos) { - test_sig(sig_name, message); + test_sig_wrong_public_key(sig_name, message); } } } @@ -56,7 +157,8 @@ TEST(oqs_Signature, Enabled) { } } if (test_in_thread) - thread_pool.emplace_back(test_sig, sig_name, message); + thread_pool.emplace_back(test_sig_wrong_public_key, sig_name, + message); } // join the rest of the threads for (auto&& elem : thread_pool)