diff --git a/CMakeLists.txt b/CMakeLists.txt index 5fdba01a..4ff260b9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -610,6 +610,7 @@ if(WITH_TESTS) badfs_test block_cache_test block_merger_test + checksum_test chmod_transformer_test compat_test dwarfs_test diff --git a/include/dwarfs/checksum.h b/include/dwarfs/checksum.h index f93b35be..0a80218f 100644 --- a/include/dwarfs/checksum.h +++ b/include/dwarfs/checksum.h @@ -22,6 +22,7 @@ #pragma once #include +#include #include #include #include @@ -44,6 +45,8 @@ class checksum { static bool verify(algorithm alg, void const* data, size_t size, void const* digest, size_t digest_size); + static bool verify(std::string const& alg, void const* data, size_t size, + void const* digest, size_t digest_size); checksum(algorithm alg); checksum(std::string const& alg); @@ -70,4 +73,6 @@ class checksum { std::unique_ptr impl_; }; +std::ostream& operator<<(std::ostream& os, checksum::algorithm alg); + } // namespace dwarfs diff --git a/src/dwarfs/checksum.cpp b/src/dwarfs/checksum.cpp index 37f72537..f46b9fd1 100644 --- a/src/dwarfs/checksum.cpp +++ b/src/dwarfs/checksum.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -165,6 +166,17 @@ class checksum_xxh3_128 : public checksum::impl { XXH3_state_t* state_; }; +template +bool verify_impl(T&& alg, void const* data, size_t size, const void* digest, + size_t digest_size) { + std::array tmp; + checksum cs(std::forward(alg)); + DWARFS_CHECK(digest_size == cs.digest_size(), "digest size mismatch"); + cs.update(data, size); + return cs.finalize(tmp.data()) && + ::memcmp(digest, tmp.data(), digest_size) == 0; +} + } // namespace bool checksum::is_available(std::string const& algo) { @@ -183,12 +195,12 @@ std::vector checksum::available_algorithms() { bool checksum::verify(algorithm alg, void const* data, size_t size, const void* digest, size_t digest_size) { - std::array tmp; - checksum cs(alg); - DWARFS_CHECK(digest_size == cs.digest_size(), "digest size mismatch"); - cs.update(data, size); - return cs.finalize(tmp.data()) && - ::memcmp(digest, tmp.data(), digest_size) == 0; + return verify_impl(alg, data, size, digest, digest_size); +} + +bool checksum::verify(std::string const& alg, void const* data, size_t size, + const void* digest, size_t digest_size) { + return verify_impl(alg, data, size, digest, digest_size); } checksum::checksum(algorithm alg) { @@ -220,4 +232,22 @@ checksum::checksum(std::string const& alg) { } } +std::ostream& operator<<(std::ostream& os, checksum::algorithm alg) { + switch (alg) { + case checksum::algorithm::SHA2_512_256: + os << "SHA2_512_256"; + break; + case checksum::algorithm::XXH3_64: + os << "XXH3_64"; + break; + case checksum::algorithm::XXH3_128: + os << "XXH3_128"; + break; + default: + os << ""; + break; + } + return os; +} + } // namespace dwarfs diff --git a/test/checksum_test.cpp b/test/checksum_test.cpp new file mode 100644 index 00000000..87fd9db8 --- /dev/null +++ b/test/checksum_test.cpp @@ -0,0 +1,145 @@ +/* vim:set ts=2 sw=2 sts=2 et: */ +/** + * \author Marcus Holland-Moritz (github@mhxnet.de) + * \copyright Copyright (c) Marcus Holland-Moritz + * + * This file is part of dwarfs. + * + * dwarfs is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * dwarfs is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with dwarfs. If not, see . + */ + +#include +#include + +#include +#include +#include + +#include + +#include "dwarfs/checksum.h" + +using namespace dwarfs; + +namespace { + +constexpr std::string_view const payload{"Hello, World!"}; + +std::unordered_map ref_digests_enum{ + {checksum::algorithm::SHA2_512_256, + "0686F0A605973DC1BF035D1E2B9BAD1985A0BFF712DDD88ABD8D2593E5F99030"}, + {checksum::algorithm::XXH3_64, "AA0266615F5D4160"}, + {checksum::algorithm::XXH3_128, "9553D72C8403DB7750DD474484F21D53"}, +}; + +std::unordered_map ref_digests_str{ + {"blake2b512", + "7DFDB888AF71EAE0E6A6B751E8E3413D767EF4FA52A7993DAA9EF097F7AA3D949199C113C" + "AA37C94F80CF3B22F7D9D6E4F5DEF4FF927830CFFE4857C34BE3D89"}, + {"blake2s256", + "EC9DB904D636EF61F1421B2BA47112A4FA6B8964FD4A0A514834455C21DF7812"}, + {"md5", "65A8E27D8879283831B664BD8B7F0AD4"}, + {"md5-sha1", "65A8E27D8879283831B664BD8B7F0AD40A0A9F2A6772942557AB5355D76AF" + "442F8F65E01"}, + {"ripemd160", "527A6A4B9A6DA75607546842E0E00105350B1AAF"}, + {"sha1", "0A0A9F2A6772942557AB5355D76AF442F8F65E01"}, + {"sha224", "72A23DFA411BA6FDE01DBFABF3B00A709C93EBF273DC29E2D8B261FF"}, + {"sha256", + "DFFD6021BB2BD5B0AF676290809EC3A53191DD81C7F70A4B28688A362182986F"}, + {"sha3-224", "853048FB8B11462B6100385633C0CC8DCDC6E2B8E376C28102BC84F2"}, + {"sha3-256", + "1AF17A664E3FA8E419B8BA05C2A173169DF76162A5A286E0C405B460D478F7EF"}, + {"sha3-384", "AA9AD8A49F31D2DDCABBB7010A1566417CFF803FEF50EBA239558826F872E" + "468C5743E7F026B0A8E5B2D7A1CC465CDBE"}, + {"sha3-512", + "38E05C33D7B067127F217D8C856E554FCFF09C9320B8A5979CE2FF5D95DD27BA35D1FBA50" + "C562DFD1D6CC48BC9C5BAA4390894418CC942D968F97BCB659419ED"}, + {"sha384", "5485CC9B3365B4305DFB4E8337E0A598A574F8242BF17289E0DD6C20A3CD44A" + "089DE16AB4AB308F63E44B1170EB5F515"}, + {"sha512", + "374D794A95CDCFD8B35993185FEF9BA368F160D8DAF432D08BA9F1ED1E5ABE6CC69291E0F" + "A2FE0006A52570EF18C19DEF4E617C33CE52EF0A6E5FBE318CB0387"}, + {"sha512-224", "766745F058E8A0438F19DE48AE56EA5F123FE738AF39BCA050A7547A"}, + {"sha512-256", + "0686F0A605973DC1BF035D1E2B9BAD1985A0BFF712DDD88ABD8D2593E5F99030"}, + {"shake128", "2BF5E6DEE6079FAD604F573194BA8426"}, + {"shake256", + "B3BE97BFD978833A65588CEAE8A34CF59E95585AF62063E6B89D0789F372424E"}, + {"sm3", "7ED26CBF0BEE4CA7D55C1E64714C4AA7D1F163089EF5CEB603CD102C81FBCBC5"}, + {"xxh3-128", "9553D72C8403DB7750DD474484F21D53"}, + {"xxh3-64", "AA0266615F5D4160"}, +}; + +} // namespace + +class checksum_test_str : public ::testing::TestWithParam {}; + +TEST_P(checksum_test_str, end_to_end) { + auto alg = GetParam(); + + std::vector digest; + + { + checksum cs(alg); + cs.update(payload.data(), payload.size()); + digest.resize(cs.digest_size()); + cs.finalize(digest.data()); + } + + auto hexdigest = + boost::algorithm::hex(std::string(digest.begin(), digest.end())); + + EXPECT_TRUE(checksum::verify(alg, payload.data(), payload.size(), + digest.data(), digest.size())); + + if (auto it = ref_digests_str.find(alg); it != ref_digests_str.end()) { + EXPECT_EQ(it->second, hexdigest) << alg; + } +} + +INSTANTIATE_TEST_SUITE_P(checksum_test, checksum_test_str, + ::testing::ValuesIn(checksum::available_algorithms())); + +class checksum_test_enum + : public ::testing::TestWithParam {}; + +TEST_P(checksum_test_enum, end_to_end) { + auto alg = GetParam(); + + std::vector digest; + + { + checksum cs(alg); + cs.update(payload.data(), payload.size()); + digest.resize(cs.digest_size()); + cs.finalize(digest.data()); + } + + auto hexdigest = + boost::algorithm::hex(std::string(digest.begin(), digest.end())); + + auto it = ref_digests_enum.find(alg); + + ASSERT_FALSE(it == ref_digests_enum.end()); + + EXPECT_TRUE(checksum::verify(alg, payload.data(), payload.size(), + digest.data(), digest.size())); + + EXPECT_EQ(it->second, hexdigest) << alg; +} + +INSTANTIATE_TEST_SUITE_P(checksum_test, checksum_test_enum, + ::testing::ValuesIn({checksum::algorithm::SHA2_512_256, + checksum::algorithm::XXH3_64, + checksum::algorithm::XXH3_128}));