From db73390eff8b908cf9376d42a3df7c1c72d839bc Mon Sep 17 00:00:00 2001 From: Pratik Mankawde <3397372+pratikmankawde@users.noreply.github.com> Date: Thu, 11 Dec 2025 19:04:11 +0000 Subject: [PATCH] test commit --- .../scripts/levelization/results/ordering.txt | 10 ++ src/doctest/CMakeLists.txt | 55 ++++-- src/doctest/basics/hardened_hash.cpp | 1 - src/doctest/basics/join.cpp | 1 - src/doctest/{ => basics}/main.cpp | 1 - src/doctest/beast/CurrentThreadName.cpp | 1 - src/doctest/beast/Journal.cpp | 1 - src/doctest/beast/basic_seconds_clock.cpp | 1 - src/doctest/beast/beast_Zero.cpp | 1 - src/doctest/beast/main.cpp | 2 + src/doctest/core/Workers.cpp | 1 - src/doctest/core/main.cpp | 2 + src/doctest/csf/BasicNetwork.cpp | 1 - src/doctest/csf/Digraph.cpp | 1 - src/doctest/csf/Histogram.cpp | 1 - src/doctest/csf/Scheduler.cpp | 1 - src/doctest/csf/main.cpp | 2 + src/doctest/nodestore/main.cpp | 2 + src/doctest/nodestore/varint.cpp | 1 - src/doctest/protocol/ApiVersion.cpp | 1 - src/doctest/protocol/STAccount.cpp | 4 +- src/doctest/protocol/STInteger.cpp | 1 - src/doctest/protocol/SecretKey.cpp | 160 ++++++++++++++++++ src/doctest/protocol/SeqProxy.cpp | 1 - src/doctest/protocol/Serializer.cpp | 1 - src/doctest/protocol/main.cpp | 2 + 26 files changed, 222 insertions(+), 34 deletions(-) rename src/doctest/{ => basics}/main.cpp (98%) create mode 100644 src/doctest/beast/main.cpp create mode 100644 src/doctest/core/main.cpp create mode 100644 src/doctest/csf/main.cpp create mode 100644 src/doctest/nodestore/main.cpp create mode 100644 src/doctest/protocol/SecretKey.cpp create mode 100644 src/doctest/protocol/main.cpp diff --git a/.github/scripts/levelization/results/ordering.txt b/.github/scripts/levelization/results/ordering.txt index c9c65fb0dd..5362fe5f01 100644 --- a/.github/scripts/levelization/results/ordering.txt +++ b/.github/scripts/levelization/results/ordering.txt @@ -1,3 +1,13 @@ +doctest.basics > xrpl.basics +doctest.basics > xrpl.protocol +doctest.beast > xrpl.basics +doctest.core > xrpl.core +doctest.core > xrpl.json +doctest.csf > test.csf +doctest.nodestore > xrpl.nodestore +doctest.protocol > xrpl.basics +doctest.protocol > xrpl.json +doctest.protocol > xrpl.protocol libxrpl.basics > xrpl.basics libxrpl.core > xrpl.basics libxrpl.core > xrpl.core diff --git a/src/doctest/CMakeLists.txt b/src/doctest/CMakeLists.txt index 81449b6e43..c6f34cac6e 100644 --- a/src/doctest/CMakeLists.txt +++ b/src/doctest/CMakeLists.txt @@ -1,6 +1,8 @@ # CMake configuration for doctest-based tests # These are converted from the beast unit_test framework +include(XrplAddTest) + find_package(doctest REQUIRED) # Custom target for all doctest tests defined in this file @@ -19,30 +21,53 @@ target_include_directories(xrpl.imports.doctest INTERFACE ) # Link against xrpld libraries for tests that need app-level functionality -# Tests like LoadFeeTrack, PendingSaves need xrpld components target_link_libraries(xrpl.imports.doctest INTERFACE Xrpl::boost Xrpl::opts Xrpl::libs ) -# Collect all doctest source files -file(GLOB_RECURSE doctest_sources CONFIGURE_DEPENDS - "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp" +# Compiler flags for strict checking +set(DOCTEST_COMPILE_FLAGS + -m64 + -g + -fPIE + -Wno-unknown-warning-option + -Wall + -Wdeprecated + -Wno-deprecated-declarations + -Wextra + -Wno-unused-parameter + -Werror + -fstack-protector + -Wno-sign-compare + -Wno-unused-but-set-variable ) -# Create the main test executable -add_executable(xrpl.doctest ${doctest_sources}) -target_link_libraries(xrpl.doctest PRIVATE xrpl.imports.doctest) +# Helper function to add a doctest module +function(xrpl_add_doctest name) + file(GLOB_RECURSE sources CONFIGURE_DEPENDS + "${CMAKE_CURRENT_SOURCE_DIR}/${name}/*.cpp" + ) -# Make sure the test isn't optimized away in unity builds -set_target_properties(xrpl.doctest PROPERTIES - UNITY_BUILD_MODE GROUP - UNITY_BUILD_BATCH_SIZE 0 -) + set(target xrpl.doctest.${name}) + add_executable(${target} ${sources}) + target_link_libraries(${target} PRIVATE xrpl.imports.doctest) + target_compile_options(${target} PRIVATE ${DOCTEST_COMPILE_FLAGS}) -# Add as a CTest test -add_test(NAME xrpl.doctest COMMAND xrpl.doctest) + set_target_properties(${target} PROPERTIES + UNITY_BUILD_MODE GROUP + UNITY_BUILD_BATCH_SIZE 0 + ) -add_dependencies(xrpl.doctests xrpl.doctest) + add_test(NAME ${target} COMMAND ${target}) + add_dependencies(xrpl.doctests ${target}) +endfunction() +# One test executable for each module +xrpl_add_doctest(basics) +xrpl_add_doctest(beast) +xrpl_add_doctest(core) +xrpl_add_doctest(csf) +xrpl_add_doctest(nodestore) +xrpl_add_doctest(protocol) diff --git a/src/doctest/basics/hardened_hash.cpp b/src/doctest/basics/hardened_hash.cpp index a443da3844..b87f0e59c2 100644 --- a/src/doctest/basics/hardened_hash.cpp +++ b/src/doctest/basics/hardened_hash.cpp @@ -130,4 +130,3 @@ TEST_CASE("containers") } TEST_SUITE_END(); - diff --git a/src/doctest/basics/join.cpp b/src/doctest/basics/join.cpp index b9f61cdfc3..3f0bd457de 100644 --- a/src/doctest/basics/join.cpp +++ b/src/doctest/basics/join.cpp @@ -75,4 +75,3 @@ TEST_CASE("CollectionAndDelimiter") } TEST_SUITE_END(); - diff --git a/src/doctest/main.cpp b/src/doctest/basics/main.cpp similarity index 98% rename from src/doctest/main.cpp rename to src/doctest/basics/main.cpp index f78f4e2cfb..0a3f254ea8 100644 --- a/src/doctest/main.cpp +++ b/src/doctest/basics/main.cpp @@ -1,3 +1,2 @@ #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN #include - diff --git a/src/doctest/beast/CurrentThreadName.cpp b/src/doctest/beast/CurrentThreadName.cpp index 29c570ce50..13206db80d 100644 --- a/src/doctest/beast/CurrentThreadName.cpp +++ b/src/doctest/beast/CurrentThreadName.cpp @@ -67,4 +67,3 @@ TEST_CASE("Thread names are preserved") } TEST_SUITE_END(); - diff --git a/src/doctest/beast/Journal.cpp b/src/doctest/beast/Journal.cpp index 1a17d1d2a9..70ce35f7dd 100644 --- a/src/doctest/beast/Journal.cpp +++ b/src/doctest/beast/Journal.cpp @@ -93,4 +93,3 @@ TEST_CASE("Journal threshold kDebug") } TEST_SUITE_END(); - diff --git a/src/doctest/beast/basic_seconds_clock.cpp b/src/doctest/beast/basic_seconds_clock.cpp index ba7df90215..4cfec78c3b 100644 --- a/src/doctest/beast/basic_seconds_clock.cpp +++ b/src/doctest/beast/basic_seconds_clock.cpp @@ -15,4 +15,3 @@ TEST_CASE("basic_seconds_clock::now() works") } TEST_SUITE_END(); - diff --git a/src/doctest/beast/beast_Zero.cpp b/src/doctest/beast/beast_Zero.cpp index 358e04546e..d5151be293 100644 --- a/src/doctest/beast/beast_Zero.cpp +++ b/src/doctest/beast/beast_Zero.cpp @@ -96,4 +96,3 @@ TEST_CASE("ADL") } TEST_SUITE_END(); - diff --git a/src/doctest/beast/main.cpp b/src/doctest/beast/main.cpp new file mode 100644 index 0000000000..0a3f254ea8 --- /dev/null +++ b/src/doctest/beast/main.cpp @@ -0,0 +1,2 @@ +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include diff --git a/src/doctest/core/Workers.cpp b/src/doctest/core/Workers.cpp index c117778280..de8e3516d2 100644 --- a/src/doctest/core/Workers.cpp +++ b/src/doctest/core/Workers.cpp @@ -166,4 +166,3 @@ TEST_CASE("threadCounts: 64 -> 3 -> 65") TEST_SUITE_END(); } // namespace xrpl - diff --git a/src/doctest/core/main.cpp b/src/doctest/core/main.cpp new file mode 100644 index 0000000000..0a3f254ea8 --- /dev/null +++ b/src/doctest/core/main.cpp @@ -0,0 +1,2 @@ +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include diff --git a/src/doctest/csf/BasicNetwork.cpp b/src/doctest/csf/BasicNetwork.cpp index f52cfe2853..e2e5914cc5 100644 --- a/src/doctest/csf/BasicNetwork.cpp +++ b/src/doctest/csf/BasicNetwork.cpp @@ -120,4 +120,3 @@ TEST_CASE("BasicNetwork disconnect") } TEST_SUITE_END(); - diff --git a/src/doctest/csf/Digraph.cpp b/src/doctest/csf/Digraph.cpp index d29b8cb620..1f8adda30f 100644 --- a/src/doctest/csf/Digraph.cpp +++ b/src/doctest/csf/Digraph.cpp @@ -70,4 +70,3 @@ TEST_CASE("Digraph basic operations") } TEST_SUITE_END(); - diff --git a/src/doctest/csf/Histogram.cpp b/src/doctest/csf/Histogram.cpp index 6c62fdb7eb..0ed423e3b2 100644 --- a/src/doctest/csf/Histogram.cpp +++ b/src/doctest/csf/Histogram.cpp @@ -73,4 +73,3 @@ TEST_CASE("Histogram duplicate elements") } TEST_SUITE_END(); - diff --git a/src/doctest/csf/Scheduler.cpp b/src/doctest/csf/Scheduler.cpp index 74505d79f5..c017b016b2 100644 --- a/src/doctest/csf/Scheduler.cpp +++ b/src/doctest/csf/Scheduler.cpp @@ -61,4 +61,3 @@ TEST_CASE("Scheduler basic operations") } TEST_SUITE_END(); - diff --git a/src/doctest/csf/main.cpp b/src/doctest/csf/main.cpp new file mode 100644 index 0000000000..0a3f254ea8 --- /dev/null +++ b/src/doctest/csf/main.cpp @@ -0,0 +1,2 @@ +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include diff --git a/src/doctest/nodestore/main.cpp b/src/doctest/nodestore/main.cpp new file mode 100644 index 0000000000..0a3f254ea8 --- /dev/null +++ b/src/doctest/nodestore/main.cpp @@ -0,0 +1,2 @@ +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include diff --git a/src/doctest/nodestore/varint.cpp b/src/doctest/nodestore/varint.cpp index 7cff212ef2..954d8dbab5 100644 --- a/src/doctest/nodestore/varint.cpp +++ b/src/doctest/nodestore/varint.cpp @@ -44,4 +44,3 @@ TEST_CASE("encode, decode") } TEST_SUITE_END(); - diff --git a/src/doctest/protocol/ApiVersion.cpp b/src/doctest/protocol/ApiVersion.cpp index fd758ea7c1..cd6740cd1f 100644 --- a/src/doctest/protocol/ApiVersion.cpp +++ b/src/doctest/protocol/ApiVersion.cpp @@ -35,4 +35,3 @@ TEST_CASE("API versions") } TEST_SUITE_END(); - diff --git a/src/doctest/protocol/STAccount.cpp b/src/doctest/protocol/STAccount.cpp index ceb1535831..2f87f42773 100644 --- a/src/doctest/protocol/STAccount.cpp +++ b/src/doctest/protocol/STAccount.cpp @@ -69,7 +69,8 @@ TEST_CASE("STAccount bad size throws") { // Construct from a VL that is not exactly 160 bits. Serializer s; - std::uint8_t const bits128[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + std::uint8_t const bits128[]{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; s.addVL(bits128, sizeof(bits128)); SerialIter sit(s.slice()); CHECK_THROWS_AS(STAccount(sit, sfAccount), std::runtime_error); @@ -113,4 +114,3 @@ TEST_CASE("AccountID invalid parsing") } TEST_SUITE_END(); - diff --git a/src/doctest/protocol/STInteger.cpp b/src/doctest/protocol/STInteger.cpp index 22a69aa907..bb3ba8e4ce 100644 --- a/src/doctest/protocol/STInteger.cpp +++ b/src/doctest/protocol/STInteger.cpp @@ -121,4 +121,3 @@ TEST_CASE("Int32") } TEST_SUITE_END(); - diff --git a/src/doctest/protocol/SecretKey.cpp b/src/doctest/protocol/SecretKey.cpp new file mode 100644 index 0000000000..641cd47c81 --- /dev/null +++ b/src/doctest/protocol/SecretKey.cpp @@ -0,0 +1,160 @@ +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +namespace xrpl { + +struct TestKeyData +{ + std::array seed; + std::array pubkey; + std::array seckey; + char const* addr; +}; + +using blob = std::vector; + +TEST_SUITE_BEGIN("SecretKey"); + +TEST_CASE("secp256k1: canonicality") +{ + std::array const digestData{ + 0x34, 0xC1, 0x90, 0x28, 0xC8, 0x0D, 0x21, 0xF3, 0xF4, 0x8C, 0x93, + 0x54, 0x89, 0x5F, 0x8D, 0x5B, 0xF0, 0xD5, 0xEE, 0x7F, 0xF4, 0x57, + 0x64, 0x7C, 0xF6, 0x55, 0xF5, 0x53, 0x0A, 0x30, 0x22, 0xA7}; + + std::array const pkData{ + 0x02, 0x50, 0x96, 0xEB, 0x12, 0xD3, 0xE9, 0x24, 0x23, 0x4E, 0x71, + 0x62, 0x36, 0x9C, 0x11, 0xD8, 0xBF, 0x87, 0x7E, 0xDA, 0x23, 0x87, + 0x78, 0xE7, 0xA3, 0x1F, 0xF0, 0xAA, 0xC5, 0xD0, 0xDB, 0xCF, 0x37}; + + std::array const skData{ + 0xAA, 0x92, 0x14, 0x17, 0xE7, 0xE5, 0xC2, 0x99, 0xDA, 0x4E, 0xEC, + 0x16, 0xD1, 0xCA, 0xA9, 0x2F, 0x19, 0xB1, 0x9F, 0x2A, 0x68, 0x51, + 0x1F, 0x68, 0xEC, 0x73, 0xBB, 0xB2, 0xF5, 0x23, 0x6F, 0x3D}; + + std::array const sig{ + 0x30, 0x45, 0x02, 0x21, 0x00, 0xB4, 0x9D, 0x07, 0xF0, 0xE9, 0x34, 0xBA, + 0x46, 0x8C, 0x0E, 0xFC, 0x78, 0x11, 0x77, 0x91, 0x40, 0x8D, 0x1F, 0xB8, + 0xB6, 0x3A, 0x64, 0x92, 0xAD, 0x39, 0x5A, 0xC2, 0xF3, 0x60, 0xF2, 0x46, + 0x60, 0x02, 0x20, 0x50, 0x87, 0x39, 0xDB, 0x0A, 0x2E, 0xF8, 0x16, 0x76, + 0xE3, 0x9F, 0x45, 0x9C, 0x8B, 0xBB, 0x07, 0xA0, 0x9C, 0x3E, 0x9F, 0x9B, + 0xEB, 0x69, 0x62, 0x94, 0xD5, 0x24, 0xD4, 0x79, 0xD6, 0x27, 0x40}; + + std::array const non{ + 0x30, 0x46, 0x02, 0x21, 0x00, 0xB4, 0x9D, 0x07, 0xF0, 0xE9, 0x34, 0xBA, + 0x46, 0x8C, 0x0E, 0xFC, 0x78, 0x11, 0x77, 0x91, 0x40, 0x8D, 0x1F, 0xB8, + 0xB6, 0x3A, 0x64, 0x92, 0xAD, 0x39, 0x5A, 0xC2, 0xF3, 0x60, 0xF2, 0x46, + 0x60, 0x02, 0x21, 0x00, 0xAF, 0x78, 0xC6, 0x24, 0xF5, 0xD1, 0x07, 0xE9, + 0x89, 0x1C, 0x60, 0xBA, 0x63, 0x74, 0x44, 0xF7, 0x1A, 0x12, 0x9E, 0x47, + 0x13, 0x5D, 0x36, 0xD9, 0x2A, 0xFD, 0x39, 0xB8, 0x56, 0x60, 0x1A, 0x01}; + + auto const digest = uint256::fromVoid(digestData.data()); + + PublicKey const pk{makeSlice(pkData)}; + SecretKey const sk{makeSlice(skData)}; + + { + auto const canonicality = ecdsaCanonicality(makeSlice(sig)); + CHECK(canonicality); + CHECK(*canonicality == ECDSACanonicality::fullyCanonical); + } + + { + auto const canonicality = ecdsaCanonicality(makeSlice(non)); + CHECK(canonicality); + CHECK(*canonicality != ECDSACanonicality::fullyCanonical); + } + + CHECK(verifyDigest(pk, digest, makeSlice(sig), false)); + CHECK(verifyDigest(pk, digest, makeSlice(sig), true)); + CHECK(verifyDigest(pk, digest, makeSlice(non), false)); + CHECK(!verifyDigest(pk, digest, makeSlice(non), true)); +} + +TEST_CASE("secp256k1: digest signing & verification") +{ + for (std::size_t i = 0; i < 32; i++) + { + auto const [pk, sk] = randomKeyPair(KeyType::secp256k1); + + CHECK(pk == derivePublicKey(KeyType::secp256k1, sk)); + CHECK(*publicKeyType(pk) == KeyType::secp256k1); + + for (std::size_t j = 0; j < 32; j++) + { + uint256 digest; + beast::rngfill(digest.data(), digest.size(), crypto_prng()); + + auto sig = signDigest(pk, sk, digest); + + CHECK(sig.size() != 0); + CHECK(verifyDigest(pk, digest, sig, true)); + + // Wrong digest: + CHECK(!verifyDigest(pk, ~digest, sig, true)); + + // Slightly change the signature: + if (auto ptr = sig.data()) + ptr[j % sig.size()]++; + + // Wrong signature: + CHECK(!verifyDigest(pk, digest, sig, true)); + + // Wrong digest and signature: + CHECK(!verifyDigest(pk, ~digest, sig, true)); + } + } +} + +void +testSigning(KeyType type) +{ + for (std::size_t i = 0; i < 32; i++) + { + auto const [pk, sk] = randomKeyPair(type); + + CHECK(pk == derivePublicKey(type, sk)); + CHECK(*publicKeyType(pk) == type); + + for (std::size_t j = 0; j < 32; j++) + { + std::vector data(64 + (8 * i) + j); + beast::rngfill(data.data(), data.size(), crypto_prng()); + + auto sig = sign(pk, sk, makeSlice(data)); + + CHECK(sig.size() != 0); + CHECK(verify(pk, makeSlice(data), sig)); + + // Construct wrong data: + auto badData = data; + + // swaps the smallest and largest elements in buffer + std::iter_swap( + std::min_element(badData.begin(), badData.end()), + std::max_element(badData.begin(), badData.end())); + + // Wrong data: should fail + CHECK(!verify(pk, makeSlice(badData), sig)); + + // Slightly change the signature: + if (auto ptr = sig.data()) + ptr[j % sig.size()]++; + + // Wrong signature: should fail + CHECK(!verify(pk, makeSlice(data), sig)); + + // Wrong data and signature: should fail + CHECK(!verify(pk, makeSlice(badData), sig)); + } + } +} diff --git a/src/doctest/protocol/SeqProxy.cpp b/src/doctest/protocol/SeqProxy.cpp index 00d361a201..a73797d9c9 100644 --- a/src/doctest/protocol/SeqProxy.cpp +++ b/src/doctest/protocol/SeqProxy.cpp @@ -153,4 +153,3 @@ TEST_CASE("SeqProxy operations") } TEST_SUITE_END(); - diff --git a/src/doctest/protocol/Serializer.cpp b/src/doctest/protocol/Serializer.cpp index 8b7a0c1cdb..1fffbee68f 100644 --- a/src/doctest/protocol/Serializer.cpp +++ b/src/doctest/protocol/Serializer.cpp @@ -45,4 +45,3 @@ TEST_CASE("Serializer add64/geti64") } TEST_SUITE_END(); - diff --git a/src/doctest/protocol/main.cpp b/src/doctest/protocol/main.cpp new file mode 100644 index 0000000000..0a3f254ea8 --- /dev/null +++ b/src/doctest/protocol/main.cpp @@ -0,0 +1,2 @@ +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include