From 82bc552e4ee2ebb4703142c666b8fa768b54d974 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Tue, 23 Sep 2025 09:25:57 +0530 Subject: [PATCH] Add tests for checking, bad secret-key must fail to successfully decapsulate shared secret, against ACVP KATs Signed-off-by: Anjan Roy --- .../test_ml_kem_1024_seckeyCheck_acvp_kat.cpp | 64 +++++++++++++++++++ .../test_ml_kem_512_seckeyCheck_acvp_kat.cpp | 64 +++++++++++++++++++ .../test_ml_kem_768_seckeyCheck_acvp_kat.cpp | 64 +++++++++++++++++++ 3 files changed, 192 insertions(+) create mode 100644 tests/test_ml_kem_1024_seckeyCheck_acvp_kat.cpp create mode 100644 tests/test_ml_kem_512_seckeyCheck_acvp_kat.cpp create mode 100644 tests/test_ml_kem_768_seckeyCheck_acvp_kat.cpp diff --git a/tests/test_ml_kem_1024_seckeyCheck_acvp_kat.cpp b/tests/test_ml_kem_1024_seckeyCheck_acvp_kat.cpp new file mode 100644 index 0000000..ae4995b --- /dev/null +++ b/tests/test_ml_kem_1024_seckeyCheck_acvp_kat.cpp @@ -0,0 +1,64 @@ +#include "ml_kem/ml_kem_1024.hpp" +#include "randomshake/randomshake.hpp" +#include "test_helper.hpp" +#include +#include +#include + +// Test +// +// - Given bad ML-KEM-1024 secret key, derived shared secret should not match. +// - Is it conformant with the specification https://doi.org/10.6028/NIST.FIPS.203 ? +// +// using ACVP Known Answer Tests, from +// https://github.com/usnistgov/ACVP-Server/blob/d98cad66639bf9d0822129c4bcae7a169fcf9ca6/gen-val/json-files/ML-KEM-encapDecap-FIPS203/internalProjection.json. +TEST(ML_KEM, ML_KEM_1024_SeckeyCheck_ACVP_KnownAnswerTests) +{ + using namespace std::literals; + + const std::string kat_file = "./kats/ml_kem_1024_seckeyCheck.acvp.kat"; + std::fstream file(kat_file); + + while (true) { + std::string pk_line; + + if (!std::getline(file, pk_line).eof()) { + std::string sk_line; + std::string tp_line; + std::string reason_line; + + std::getline(file, sk_line); + std::getline(file, tp_line); + std::getline(file, reason_line); + + const auto pk = extract_and_parse_hex_string(pk_line); + const auto sk = extract_and_parse_hex_string(sk_line); + + const auto test_passed = tp_line.substr(tp_line.find("="sv) + 2, tp_line.size()) == "True"; + + std::array random_m{}; + std::array computed_ctxt{}; + std::array computed_shared_secret_sender{}; + std::array computed_shared_secret_receiver{}; + + randomshake::randomshake_t<256> csprng; + csprng.generate(random_m); + + EXPECT_TRUE(ml_kem_1024::encapsulate(random_m, pk, computed_ctxt, computed_shared_secret_sender)); + ml_kem_1024::decapsulate(sk, computed_ctxt, computed_shared_secret_receiver); + + if (test_passed) { + EXPECT_EQ(computed_shared_secret_sender, computed_shared_secret_receiver); + } else { + EXPECT_NE(computed_shared_secret_sender, computed_shared_secret_receiver); + } + + std::string empty_line; + std::getline(file, empty_line); + } else { + break; + } + } + + file.close(); +} diff --git a/tests/test_ml_kem_512_seckeyCheck_acvp_kat.cpp b/tests/test_ml_kem_512_seckeyCheck_acvp_kat.cpp new file mode 100644 index 0000000..ff140bf --- /dev/null +++ b/tests/test_ml_kem_512_seckeyCheck_acvp_kat.cpp @@ -0,0 +1,64 @@ +#include "ml_kem/ml_kem_512.hpp" +#include "randomshake/randomshake.hpp" +#include "test_helper.hpp" +#include +#include +#include + +// Test +// +// - Given bad ML-KEM-512 secret key, derived shared secret should not match. +// - Is it conformant with the specification https://doi.org/10.6028/NIST.FIPS.203 ? +// +// using ACVP Known Answer Tests, from +// https://github.com/usnistgov/ACVP-Server/blob/d98cad66639bf9d0822129c4bcae7a169fcf9ca6/gen-val/json-files/ML-KEM-encapDecap-FIPS203/internalProjection.json. +TEST(ML_KEM, ML_KEM_512_SeckeyCheck_ACVP_KnownAnswerTests) +{ + using namespace std::literals; + + const std::string kat_file = "./kats/ml_kem_512_seckeyCheck.acvp.kat"; + std::fstream file(kat_file); + + while (true) { + std::string pk_line; + + if (!std::getline(file, pk_line).eof()) { + std::string sk_line; + std::string tp_line; + std::string reason_line; + + std::getline(file, sk_line); + std::getline(file, tp_line); + std::getline(file, reason_line); + + const auto pk = extract_and_parse_hex_string(pk_line); + const auto sk = extract_and_parse_hex_string(sk_line); + + const auto test_passed = tp_line.substr(tp_line.find("="sv) + 2, tp_line.size()) == "True"; + + std::array random_m{}; + std::array computed_ctxt{}; + std::array computed_shared_secret_sender{}; + std::array computed_shared_secret_receiver{}; + + randomshake::randomshake_t<128> csprng; + csprng.generate(random_m); + + EXPECT_TRUE(ml_kem_512::encapsulate(random_m, pk, computed_ctxt, computed_shared_secret_sender)); + ml_kem_512::decapsulate(sk, computed_ctxt, computed_shared_secret_receiver); + + if (test_passed) { + EXPECT_EQ(computed_shared_secret_sender, computed_shared_secret_receiver); + } else { + EXPECT_NE(computed_shared_secret_sender, computed_shared_secret_receiver); + } + + std::string empty_line; + std::getline(file, empty_line); + } else { + break; + } + } + + file.close(); +} diff --git a/tests/test_ml_kem_768_seckeyCheck_acvp_kat.cpp b/tests/test_ml_kem_768_seckeyCheck_acvp_kat.cpp new file mode 100644 index 0000000..3eae790 --- /dev/null +++ b/tests/test_ml_kem_768_seckeyCheck_acvp_kat.cpp @@ -0,0 +1,64 @@ +#include "ml_kem/ml_kem_768.hpp" +#include "randomshake/randomshake.hpp" +#include "test_helper.hpp" +#include +#include +#include + +// Test +// +// - Given bad ML-KEM-768 secret key, derived shared secret should not match. +// - Is it conformant with the specification https://doi.org/10.6028/NIST.FIPS.203 ? +// +// using ACVP Known Answer Tests, from +// https://github.com/usnistgov/ACVP-Server/blob/d98cad66639bf9d0822129c4bcae7a169fcf9ca6/gen-val/json-files/ML-KEM-encapDecap-FIPS203/internalProjection.json. +TEST(ML_KEM, ML_KEM_768_SeckeyCheck_ACVP_KnownAnswerTests) +{ + using namespace std::literals; + + const std::string kat_file = "./kats/ml_kem_768_seckeyCheck.acvp.kat"; + std::fstream file(kat_file); + + while (true) { + std::string pk_line; + + if (!std::getline(file, pk_line).eof()) { + std::string sk_line; + std::string tp_line; + std::string reason_line; + + std::getline(file, sk_line); + std::getline(file, tp_line); + std::getline(file, reason_line); + + const auto pk = extract_and_parse_hex_string(pk_line); + const auto sk = extract_and_parse_hex_string(sk_line); + + const auto test_passed = tp_line.substr(tp_line.find("="sv) + 2, tp_line.size()) == "True"; + + std::array random_m{}; + std::array computed_ctxt{}; + std::array computed_shared_secret_sender{}; + std::array computed_shared_secret_receiver{}; + + randomshake::randomshake_t<192> csprng; + csprng.generate(random_m); + + EXPECT_TRUE(ml_kem_768::encapsulate(random_m, pk, computed_ctxt, computed_shared_secret_sender)); + ml_kem_768::decapsulate(sk, computed_ctxt, computed_shared_secret_receiver); + + if (test_passed) { + EXPECT_EQ(computed_shared_secret_sender, computed_shared_secret_receiver); + } else { + EXPECT_NE(computed_shared_secret_sender, computed_shared_secret_receiver); + } + + std::string empty_line; + std::getline(file, empty_line); + } else { + break; + } + } + + file.close(); +}