diff --git a/doc/crypt.adoc b/doc/crypt.adoc index cc31a0bb..551f63fa 100644 --- a/doc/crypt.adoc +++ b/doc/crypt.adoc @@ -32,9 +32,9 @@ include::crypt/sha384.adoc[] include::crypt/sha512.adoc[] include::crypt/sha512_224.adoc[] -//// -include::crypt/sha512_256.adoc[] +include::crypt/sha512_256.adoc[] +//// include::crypt/sha3_224.adoc[] include::crypt/sha3_256.adoc[] diff --git a/doc/crypt/sha512_256.adoc b/doc/crypt/sha512_256.adoc index 30bc3465..dbe1ec8c 100644 --- a/doc/crypt/sha512_256.adoc +++ b/doc/crypt/sha512_256.adoc @@ -12,94 +12,6 @@ https://www.boost.org/LICENSE_1_0.txt This library supports sha512_256 as described in https://datatracker.ietf.org/doc/html/rfc6234[RFC 6234]. There is a wide range of acceptable inputs for the base sha512_256 function: -== Hashing Functions - -[source, c++] ----- -namespace boost { -namespace crypt { - -uisng return_type = boost::crypt::array; - -BOOST_CRYPT_GPU_ENABLED inline auto sha512_256(const char* str) noexcept -> return_type; - -BOOST_CRYPT_GPU_ENABLED inline auto sha512_256(const char* str, size_t len) noexcept -> return_type; - -BOOST_CRYPT_GPU_ENABLED inline auto sha512_256(const unsigned char* str) noexcept -> return_type; - -BOOST_CRYPT_GPU_ENABLED inline auto sha512_256(const unsigned char* str, size_t len) noexcept -> return_type; - -BOOST_CRYPT_GPU_ENABLED inline auto sha512_256(const char16_t* str) noexcept -> return_type; - -BOOST_CRYPT_GPU_ENABLED inline auto sha512_256(const char16_t* str, size_t len) noexcept -> return_type; - -BOOST_CRYPT_GPU_ENABLED inline auto sha512_256(const char32_t* str) noexcept -> return_type; - -BOOST_CRYPT_GPU_ENABLED inline auto sha512_256(const char32_t* str, size_t len) noexcept -> return_type; - -BOOST_CRYPT_GPU_ENABLED inline auto sha512_256(const wchar_t* str) noexcept -> return_type; - -BOOST_CRYPT_GPU_ENABLED inline auto sha512_256(const wchar_t* str, size_t len) noexcept -> return_type; - -inline auto sha512_256(const std::string& str) noexcept -> return_type; - -inline auto sha512_256(const std::u16string& str) noexcept -> return_type; - -inline auto sha512_256(const std::u32string& str) noexcept -> return_type; - -inline auto sha512_256(const std::wstring& str) noexcept -> return_type; - -#ifdef BOOST_CRYPT_HAS_STRING_VIEW - -inline auto sha512_256(std::string_view str) noexcept -> return_type; - -inline auto sha512_256(std::u16string_view str) noexcept -> return_type; - -inline auto sha512_256(std::u32string_view str) noexcept -> return_type; - -inline auto sha512_256(std::wstring_view str) noexcept -> return_type; - -#endif // BOOST_CRYPT_HAS_STRING_VIEW - -#ifdef BOOST_CRYPT_HAS_SPAN - -template -inline auto md5(std::span data) noexcept -> return_type; - -#endif // BOOST_CRYPT_HAS_SPAN - -#ifdef BOOST_CRYPT_HAS_CUDA - -template -BOOST_CRYPT_GPU_ENABLED inline auto md5(cuda::std::span data) noexcept -> return_type; - -#endif // BOOST_CRYPT_HAS_CUDA - -} //namespace crypt -} //namespace boost ----- - -== File Hashing Functions - -We also have the ability to scan files and return the sha512_256 value: - -[source, c++] ----- -namespace boost { -namespace crypt { - -uisng return_type = boost::crypt::array; - -inline auto sha512_256_file(const char* filepath) noexcept -> return_type; - -inline auto sha512_256_file(const std::string& filepath) noexcept -> return_type; - -inline auto sha512_256_file(std::string_view filepath) noexcept -> return_type; - -} // namespace crypt -} // namespace boost ----- - == Hashing Object [#sha512_256_hasher] @@ -108,50 +20,61 @@ This class does not use any dynamic memory allocation. [source, c++] ---- -namespace boost { -namespace crypt { +namespace boost::crypt { class sha512_256_hasher { - uisng return_type = boost::crypt::array; +public: + uisng return_type = compat::array; - void init(); + // Initialize the hasher + BOOST_CRYPT_GPU_ENABLED constexpr void init() noexcept; - template - BOOST_CRYPT_GPU_ENABLED inline auto process_byte(ByteType byte) noexcept -> state; + // Process bytes piecewise + BOOST_CRYPT_GPU_ENABLED constexpr state process_bytes(compat::span data) noexcept; - template - BOOST_CRYPT_GPU_ENABLED inline auto process_bytes(ForwardIter buffer, size_t byte_count) noexcept -> state; + template + BOOST_CRYPT_GPU_ENABLED constexpr state process_bytes(Range&& data) noexcept; - #ifdef BOOST_CRYPT_HAS_STRING_VIEW + // Finalize the calculation of the hash + BOOST_CRYPT_GPU_ENABLED constexpr state finalize() noexcept; - inline auto process_bytes(std::string_view str) noexcept -> state; + // Get the digest + [[nodiscard]] constexpr expected get_digest() const noexcept; - inline auto process_bytes(std::u16string_view str) noexcept -> state; + [[nodiscard]] BOOST_CRYPT_GPU_ENABLED_CONSTEXPR state get_digest(compat::span data) const noexcept; - inline auto process_bytes(std::u32string_view str) noexcept -> state; + template + [[nodiscard]] BOOST_CRYPT_GPU_ENABLED state get_digest(Range&& data) const noexcept; +}; - inline auto process_bytes(std::wstring_view str) noexcept -> state; +} // namespace boost::crypt +---- + +== One-Shot Hashing Functions - #endif // BOOST_CRYPT_HAS_STRING_VIEW +[source, c++] +---- +namespace boost::crypt { - #ifdef BOOST_CRYPT_HAS_SPAN +[[nodiscard]] BOOST_CRYPT_GPU_ENABLED constexpr auto sha512_256(compat::span data) noexcept -> expected; - template - inline auto process_bytes(std::span data) noexcept -> state; +template +[[nodiscard]] BOOST_CRYPT_GPU_ENABLED auto sha512_256(SizedRange&& data) noexcept -> expected; - #endif // BOOST_CRYPT_HAS_SPAN +} // namespace boost::crypt +---- - #ifdef BOOST_CRYPT_HAS_CUDA +== File Hashing Functions - template - BOOST_CRYPT_GPU_ENABLED inline auto process_bytes(cuda::std::span data) noexcept -> state; +We also have the ability to scan files and return the sha512_256 value: - #endif // BOOST_CRYPT_HAS_CUDA +[source, c++] +---- +namespace boost::crypt { - inline auto get_digest() noexcept -> return_type; -}; +template +[[nodiscard]] inline auto sha512_256_file(const T& filepath) -> expected; -} // namespace crypt -} // namespace boost +} // namespace boost::crypt ---- diff --git a/fuzzing/fuzz_sha512_256.cpp b/fuzzing/fuzz_sha512_256.cpp new file mode 100644 index 00000000..c2057ca7 --- /dev/null +++ b/fuzzing/fuzz_sha512_256.cpp @@ -0,0 +1,41 @@ +// Copyright 2024 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t* data, std::size_t size) +{ + try + { + auto c_data = reinterpret_cast(data); + std::string c_data_str {c_data, size}; // Guarantee null termination since we can't pass the size argument + + boost::crypt::sha512_256(c_data_str); + + std::string_view view {c_data_str}; + boost::crypt::sha512_256(view); + + std::span data_span {c_data, size}; + boost::crypt::sha512_256(data_span); + + // Fuzz the hasher object + boost::crypt::sha512_256_hasher hasher; + hasher.process_bytes(data_span); + hasher.process_bytes(data_span); + hasher.process_bytes(data_span); + hasher.finalize(); + [[maybe_unused]] const auto res = hasher.get_digest(); + hasher.process_bytes(data_span); // State is invalid but should not crash + } + catch(...) + { + std::cerr << "Error with: " << data << std::endl; + std::terminate(); + } + + return 0; +} diff --git a/include/boost/crypt2/hash/sha512_256.hpp b/include/boost/crypt2/hash/sha512_256.hpp new file mode 100644 index 00000000..6ce5374f --- /dev/null +++ b/include/boost/crypt2/hash/sha512_256.hpp @@ -0,0 +1,92 @@ +// Copyright 2024 - 2025 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt +// +// See: https://datatracker.ietf.org/doc/html/rfc4634 +// See: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf + +#ifndef BOOST_CRYPT2_HASH_SHA512_256_HPP +#define BOOST_CRYPT2_HASH_SHA512_256_HPP + +#include +#include +#include +#include + +namespace boost::crypt { + +BOOST_CRYPT_EXPORT using sha512_256_hasher = hash_detail::sha512_base<32U>; + +// One shot functions +[[nodiscard]] BOOST_CRYPT_EXPORT BOOST_CRYPT_GPU_ENABLED_CONSTEXPR +auto sha512_256(compat::span data) noexcept -> compat::expected +{ + sha512_256_hasher hasher; + hasher.process_bytes(data); + hasher.finalize(); + return hasher.get_digest(); +} + +template +[[nodiscard]] BOOST_CRYPT_EXPORT BOOST_CRYPT_GPU_ENABLED +auto sha512_256(SizedRange&& data) noexcept -> compat::expected +{ + sha512_256_hasher hasher; + hasher.process_bytes(data); + hasher.finalize(); + return hasher.get_digest(); +} + +#ifndef BOOST_CRYPT_HAS_CUDA + +// Error: the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information [-Werror,-Wunsafe-buffer-usage-in-container] +// Since this is the way the file streams report sizing information we must use it +// If a bad read occurs an exception is thrown so there's little risk of a bad region +#if defined(__clang__) && __clang_major__ >= 19 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-container" +#endif + +namespace detail { + +[[nodiscard]] inline auto sha512_256_file_impl(detail::file_reader<64U>& reader) -> compat::expected +{ + sha512_256_hasher hasher; + while (!reader.eof()) + { + const auto buffer_iter {reader.read_next_block()}; + const auto len {reader.get_bytes_read()}; + const auto buffer_span {std::span(buffer_iter, len)}; + hasher.process_bytes(buffer_span); + } + + hasher.finalize(); + return hasher.get_digest(); +} + +} // namespace detail + +template +[[nodiscard]] BOOST_CRYPT_EXPORT inline auto sha512_256_file(const T& filepath) -> compat::expected +{ + if constexpr (std::is_pointer_v>) + { + if (filepath == nullptr) + { + throw std::runtime_error("Invalid file path"); + } + } + + detail::file_reader<64U> reader(filepath); + return detail::sha512_256_file_impl(reader); +} + +#if defined(__clang__) && __clang_major__ >= 19 +#pragma clang diagnostic pop +#endif + +#endif + +} // namespace boost::crypt + +#endif //BOOST_CRYPT2_HASH_SHA512_256_HPP diff --git a/test/Jamfile b/test/Jamfile index afee6c9e..ae1c974a 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -65,7 +65,7 @@ run test_sha256.cpp ; run test_sha384.cpp ; run test_sha512.cpp ; run test_sha512_224.cpp ; -#run test_sha512_256.cpp ; +run test_sha512_256.cpp ; #run test_sha3_512.cpp ; #run test_sha3_384.cpp ; #run test_sha3_256.cpp ; @@ -118,8 +118,8 @@ run test_nist_cavs_sha512_224_short_long.cpp ; #run test_nist_cavs_sha512_224_hmac_drbg.cpp ; #run test_nist_cavs_sha512_224_hash_drbg.cpp ; -#run test_nist_cavs_sha512_256_monte.cpp ; -#run test_nist_cavs_sha512_256_short_long.cpp ; +run test_nist_cavs_sha512_256_monte.cpp ; +run test_nist_cavs_sha512_256_short_long.cpp ; #run test_nist_cavs_sha512_256_hmac.cpp ; #run test_nist_cavs_sha512_256_hmac_drbg.cpp ; #run test_nist_cavs_sha512_256_hash_drbg.cpp ; diff --git a/test/test_nist_cavs_sha512_256_monte.cpp b/test/test_nist_cavs_sha512_256_monte.cpp index 9ed9728d..fbe44fc9 100644 --- a/test/test_nist_cavs_sha512_256_monte.cpp +++ b/test/test_nist_cavs_sha512_256_monte.cpp @@ -3,13 +3,13 @@ // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt -#include +#include #include "test_nist_cavs_detail.hpp" auto main() -> int { - bool result_is_ok { true }; + bool result_is_ok { true }; { nist::cavs::test_vector_container_type my_test_vectors_monte { }; diff --git a/test/test_nist_cavs_sha512_256_short_long.cpp b/test/test_nist_cavs_sha512_256_short_long.cpp index c7c30690..b7cad637 100644 --- a/test/test_nist_cavs_sha512_256_short_long.cpp +++ b/test/test_nist_cavs_sha512_256_short_long.cpp @@ -3,7 +3,7 @@ // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt -#include +#include #include "test_nist_cavs_detail.hpp" diff --git a/test/test_sha512_256.cpp b/test/test_sha512_256.cpp index f9b39602..0806c9bc 100644 --- a/test/test_sha512_256.cpp +++ b/test/test_sha512_256.cpp @@ -2,9 +2,20 @@ // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt -#include +#include + + +#if defined(__clang__) && __clang_major__ >= 19 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" +#endif + #include -#include "generate_random_strings.hpp" + +#if defined(__clang__) && __clang_major__ >= 19 +#pragma clang diagnostic pop +#endif + #include #include #include @@ -15,24 +26,24 @@ #include #include -constexpr std::array, 3> test_values = +const std::array>, 3> test_values = { std::make_tuple("", - boost::crypt::sha512_256_hasher::return_type { + std::array { 0xc6, 0x72, 0xb8, 0xd1, 0xef, 0x56, 0xed, 0x28, 0xab, 0x87, 0xc3, 0x62, 0x2c, 0x51, 0x14, 0x06, 0x9b, 0xdd, 0x3a, 0xd7, 0xb8, 0xf9, 0x73, 0x74, 0x98, 0xd0, 0xc0, 0x1e, 0xce, 0xf0, 0x96, 0x7a }), std::make_tuple("The quick brown fox jumps over the lazy dog", - boost::crypt::sha512_256_hasher::return_type { + std::array { 0xdd, 0x9d, 0x67, 0xb3, 0x71, 0x51, 0x9c, 0x33, 0x9e, 0xd8, 0xdb, 0xd2, 0x5a, 0xf9, 0x0e, 0x97, 0x6a, 0x1e, 0xee, 0xfd, 0x4a, 0xd3, 0xd8, 0x89, 0x00, 0x5e, 0x53, 0x2f, 0xc5, 0xbe, 0xf0, 0x4d }), std::make_tuple("The quick brown fox jumps over the lazy dog.", - boost::crypt::sha512_256_hasher::return_type { + std::array { 0x15, 0x46, 0x74, 0x18, 0x40, 0xf8, 0xa4, 0x92, 0xb9, 0x59, 0xd9, 0xb8, 0xb2, 0x34, 0x4b, 0x9b, 0x0e, 0xb5, 0x1b, 0x00, 0x4b, 0xba, 0x35, 0xc0, @@ -44,11 +55,11 @@ void basic_tests() { for (const auto& test_value : test_values) { - const auto message_result {boost::crypt::sha512_256(std::get<0>(test_value))}; + const auto message_result {boost::crypt::sha512_256(std::get<0>(test_value)).value()}; const auto valid_result {std::get<1>(test_value)}; for (std::size_t i {}; i < message_result.size(); ++i) { - if (!BOOST_TEST_EQ(message_result[i], valid_result[i])) + if (!BOOST_TEST(message_result[i] == static_cast(valid_result[i]))) { // LCOV_EXCL_START std::cerr << "Failure with: " << std::get<0>(test_value) << '\n'; @@ -64,11 +75,11 @@ void string_test() for (const auto& test_value : test_values) { const std::string string_message {std::get<0>(test_value)}; - const auto message_result {boost::crypt::sha512_256(string_message)}; + const auto message_result {boost::crypt::sha512_256(string_message).value()}; const auto valid_result {std::get<1>(test_value)}; for (std::size_t i {}; i < message_result.size(); ++i) { - if (!BOOST_TEST_EQ(message_result[i], valid_result[i])) + if (!BOOST_TEST(message_result[i] == static_cast(valid_result[i]))) { // LCOV_EXCL_START std::cerr << "Failure with: " << std::get<0>(test_value) << '\n'; @@ -81,16 +92,15 @@ void string_test() void string_view_test() { - #ifdef BOOST_CRYPT_HAS_STRING_VIEW for (const auto& test_value : test_values) { const std::string string_message {std::get<0>(test_value)}; const std::string_view string_view_message {string_message}; - const auto message_result {boost::crypt::sha512_256(string_view_message)}; + const auto message_result {boost::crypt::sha512_256(string_view_message).value()}; const auto valid_result {std::get<1>(test_value)}; for (std::size_t i {}; i < message_result.size(); ++i) { - if (!BOOST_TEST_EQ(message_result[i], valid_result[i])) + if (!BOOST_TEST(message_result[i] == static_cast(valid_result[i]))) { // LCOV_EXCL_START std::cerr << "Failure with: " << std::get<0>(test_value) << '\n'; @@ -102,10 +112,11 @@ void string_view_test() boost::crypt::sha512_256_hasher hasher; const auto current_state = hasher.process_bytes(string_view_message); BOOST_TEST(current_state == boost::crypt::state::success); - const auto result2 = hasher.get_digest(); + hasher.finalize(); + const auto result2 = hasher.get_digest().value(); for (std::size_t i {}; i < message_result.size(); ++i) { - if (!BOOST_TEST_EQ(result2[i], valid_result[i])) + if (!BOOST_TEST(result2[i] == static_cast(valid_result[i]))) { // LCOV_EXCL_START std::cerr << "Failure with: " << std::get<0>(test_value) << '\n'; @@ -114,41 +125,6 @@ void string_view_test() } } } - #endif -} - -void bad_input() -{ - const auto null_message {boost::crypt::sha512_256(static_cast(nullptr))}; - BOOST_TEST_EQ(null_message[0], 0x0); - BOOST_TEST_EQ(null_message[1], 0x0); - BOOST_TEST_EQ(null_message[2], 0x0); - BOOST_TEST_EQ(null_message[3], 0x0); - - const auto null_message_len {boost::crypt::sha512_256(static_cast(nullptr), 100)}; - BOOST_TEST_EQ(null_message_len[0], 0x0); - BOOST_TEST_EQ(null_message_len[1], 0x0); - BOOST_TEST_EQ(null_message_len[2], 0x0); - BOOST_TEST_EQ(null_message_len[3], 0x0); - - const auto unsigned_null_message {boost::crypt::sha512_256(static_cast(nullptr))}; - BOOST_TEST_EQ(unsigned_null_message[0], 0x0); - BOOST_TEST_EQ(unsigned_null_message[1], 0x0); - BOOST_TEST_EQ(unsigned_null_message[2], 0x0); - BOOST_TEST_EQ(unsigned_null_message[3], 0x0); - - const auto unsigned_null_message_len {boost::crypt::sha512_256(static_cast(nullptr), 100)}; - BOOST_TEST_EQ(unsigned_null_message_len[0], 0x0); - BOOST_TEST_EQ(unsigned_null_message_len[1], 0x0); - BOOST_TEST_EQ(unsigned_null_message_len[2], 0x0); - BOOST_TEST_EQ(unsigned_null_message_len[3], 0x0); - - std::string test_str {"Test string"}; - const auto reveresed_input {boost::crypt::detail::sha512_256(test_str.end(), test_str.begin())}; - BOOST_TEST_EQ(reveresed_input[0], 0x0); - BOOST_TEST_EQ(reveresed_input[1], 0x0); - BOOST_TEST_EQ(reveresed_input[2], 0x0); - BOOST_TEST_EQ(reveresed_input[3], 0x0); } void test_class() @@ -158,13 +134,14 @@ void test_class() for (const auto& test_value : test_values) { const auto msg {std::get<0>(test_value)}; - hasher.process_bytes(msg, std::strlen(msg)); - const auto message_result {hasher.get_digest()}; + hasher.process_bytes(msg); + hasher.finalize(); + const auto message_result {hasher.get_digest().value()}; const auto valid_result {std::get<1>(test_value)}; for (std::size_t i {}; i < message_result.size(); ++i) { - if (!BOOST_TEST_EQ(message_result[i], valid_result[i])) + if (!BOOST_TEST(message_result[i] == static_cast(valid_result[i]))) { // LCOV_EXCL_START std::cerr << "Failure with: " << std::get<0>(test_value) << '\n'; @@ -178,32 +155,13 @@ void test_class() } template -void test_file(T filename, const boost::crypt::sha512_256_hasher::return_type& res) +void test_file(T filename, const std::array& res) { - const auto crypt_res {boost::crypt::sha512_256_file(filename)}; + const auto crypt_res {boost::crypt::sha512_256_file(filename).value()}; for (std::size_t j {}; j < crypt_res.size(); ++j) { - if (!BOOST_TEST_EQ(res[j], crypt_res[j])) - { - // LCOV_EXCL_START - std::cerr << "Failure with file: " << filename << std::endl; - break; - // LCOV_EXCL_STOP - } - } -} - -template -void test_invalid_file(T filename) -{ - constexpr boost::crypt::sha512_256_hasher::return_type res{}; - - const auto crypt_res {boost::crypt::sha512_256_file(filename)}; - - for (std::size_t j {}; j < crypt_res.size(); ++j) - { - if (!BOOST_TEST_EQ(res[j], crypt_res[j])) + if (!BOOST_TEST(static_cast(res[j]) == crypt_res[j])) { // LCOV_EXCL_START std::cerr << "Failure with file: " << filename << std::endl; @@ -263,79 +221,37 @@ void files_test() // On macOS 15 // shasum -a 512256 test_file_1.txt // d90ec85475853bc495a3243d13e664a3af0804705cee3e07edf741b - constexpr boost::crypt::sha512_256_hasher::return_type res{0x86, 0x2d, 0x8c, 0x33, 0x7f, 0x9d, 0x62, 0xac, 0x89, 0xaa, 0x83, 0xd7, 0xff, 0xbc, 0x22, 0x46, 0xed, 0x54, 0x96, 0x56, 0x84, 0xd0, 0x87, 0x7b, 0xea, 0xf2, 0x1e, 0x9a, 0xa7, 0xc4, 0x48, 0x52}; + constexpr std::array res{0x86, 0x2d, 0x8c, 0x33, 0x7f, 0x9d, 0x62, 0xac, 0x89, 0xaa, 0x83, 0xd7, 0xff, 0xbc, 0x22, 0x46, 0xed, 0x54, 0x96, 0x56, 0x84, 0xd0, 0x87, 0x7b, 0xea, 0xf2, 0x1e, 0x9a, 0xa7, 0xc4, 0x48, 0x52}; test_file(filename, res); const std::string str_filename {filename}; test_file(str_filename, res); - #ifdef BOOST_CRYPT_HAS_STRING_VIEW const std::string_view str_view_filename {str_filename}; test_file(str_view_filename, res); - #endif const auto invalid_filename = "broken.bin"; - test_invalid_file(invalid_filename); + BOOST_TEST_THROWS([[maybe_unused]] const auto trash1 = boost::crypt::sha512_256_file(invalid_filename), std::runtime_error); const std::string str_invalid_filename {invalid_filename}; - test_invalid_file(str_invalid_filename); + BOOST_TEST_THROWS([[maybe_unused]] const auto trash2 = boost::crypt::sha512_256_file(str_invalid_filename), std::runtime_error); - #ifdef BOOST_CRYPT_HAS_STRING_VIEW const std::string_view str_view_invalid_filename {str_invalid_filename}; - test_invalid_file(str_view_invalid_filename); - #endif + BOOST_TEST_THROWS([[maybe_unused]] const auto trash3 = boost::crypt::sha512_256_file(str_view_invalid_filename), std::runtime_error); // On macOS 15 // shasum -a 512256 test_file_2.txt // 6dc95388edc5b8eab4c7f440023bf7450651bdf9a5a72e65a24c3fe6 - constexpr boost::crypt::sha512_256_hasher::return_type res_2{0xd6, 0xae, 0x13, 0xcd, 0xa9, 0x21, 0xe5, 0x78, 0xe8, 0x3b, 0x90, 0x04, 0x2f, 0xaf, 0x37, 0x58, 0x56, 0x13, 0x56, 0x1e, 0x79, 0xee, 0xf3, 0xb1, 0x95, 0x92, 0x75, 0xe8, 0xd2, 0x2e, 0xf4, 0x9c}; + constexpr std::array res_2{0xd6, 0xae, 0x13, 0xcd, 0xa9, 0x21, 0xe5, 0x78, 0xe8, 0x3b, 0x90, 0x04, 0x2f, 0xaf, 0x37, 0x58, 0x56, 0x13, 0x56, 0x1e, 0x79, 0xee, 0xf3, 0xb1, 0x95, 0x92, 0x75, 0xe8, 0xd2, 0x2e, 0xf4, 0x9c}; test_file(filename_2, res_2); const char* test_null_file = nullptr; - test_invalid_file(test_null_file); -} - -void test_invalid_state() -{ - boost::crypt::sha512_256_hasher hasher; - auto current_state = hasher.process_bytes("test", 4); - BOOST_TEST(current_state == boost::crypt::state::success); + BOOST_TEST_THROWS([[maybe_unused]] const auto trash4 = boost::crypt::sha512_256_file(test_null_file), std::runtime_error); - hasher.get_digest(); - - const auto bad_state = hasher.process_bytes("test", 4); - BOOST_TEST(bad_state == boost::crypt::state::state_error); - - const auto digest = hasher.get_digest(); - - for (const auto& val : digest) - { - BOOST_TEST_EQ(val, static_cast(0)); - } - - hasher.init(); - - current_state = hasher.process_bytes("test", 4); - BOOST_TEST(current_state == boost::crypt::state::success); - current_state = hasher.process_byte(0x03); - BOOST_TEST(current_state == boost::crypt::state::success); - const char* ptr = nullptr; - current_state = hasher.process_bytes(ptr, 4); - BOOST_TEST(current_state == boost::crypt::state::null); - - const char16_t* ptr16 = nullptr; - current_state = hasher.process_bytes(ptr16, 4); - BOOST_TEST(current_state == boost::crypt::state::null); - - const char32_t* ptr32 = nullptr; - current_state = hasher.process_bytes(ptr32, 4); - BOOST_TEST(current_state == boost::crypt::state::null); - - const wchar_t* wptr = nullptr; - current_state = hasher.process_bytes(wptr, 4); - BOOST_TEST(current_state == boost::crypt::state::null); + std::filesystem::path bad_path = "path.txt"; + BOOST_TEST_THROWS([[maybe_unused]] const auto trash5 = boost::crypt::sha512_256_file(bad_path), std::runtime_error); } // This ends up being completely calculated in a constexpr fashion so Codecov complains @@ -369,12 +285,37 @@ void test_span() } // LCOV_EXCL_STOP +consteval bool immediate_test() +{ + constexpr std::array vals = {std::byte{0x61}, std::byte{0x62}, std::byte{0x63}}; + constexpr auto expected_res = std::array{0x53, 0x04, 0x8e, 0x26, 0x81, 0x94, 0x1e, 0xf9, 0x9b, 0x2e, 0x29, 0xb7, 0x6b, 0x4c, 0x7d, 0xab, 0xe4, 0xc2, 0xd0, 0xc6, 0x34, 0xfc, 0x6d, 0x46, 0xe0, 0xe2, 0xf1, 0x31, 0x07, 0xe7, 0xaf, 0x23}; + + std::span byte_span {vals}; + + boost::crypt::sha512_256_hasher hasher; + hasher.init(); + hasher.process_bytes(byte_span); + hasher.finalize(); + const auto res = hasher.get_digest().value(); + + bool correct {true}; + for (std::size_t i {}; i < res.size(); ++i) + { + if (res[i] != static_cast(expected_res[i])) + { + correct = false; + break; + } + } + + return correct; +} + int main() { basic_tests(); string_test(); string_view_test(); - bad_input(); test_class(); // The Windows file system returns a different result than on UNIX platforms @@ -382,9 +323,10 @@ int main() files_test(); #endif - test_invalid_state(); - - test_span(); + // GCC-14 has an internal compiler error here + #if defined(__GNUC__) && __GNUC__ != 14 + static_assert(immediate_test()); + #endif return boost::report_errors(); } diff --git a/test/test_sha512_256_nvcc.cu b/test/test_sha512_256_nvcc.cu index 195100d9..90d9cf77 100644 --- a/test/test_sha512_256_nvcc.cu +++ b/test/test_sha512_256_nvcc.cu @@ -3,7 +3,8 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#include +#include +#include #include "cuda_managed_ptr.hpp" #include "stopwatch.hpp" #include "generate_random_strings.hpp" @@ -11,10 +12,9 @@ #include #include #include +#include -#include - -using digest_type = boost::crypt::sha512_256_hasher::return_type; +using digest_type = cuda::std::array; // The kernel function __global__ void cuda_test(char** in, digest_type* out, int numElements) @@ -23,7 +23,8 @@ __global__ void cuda_test(char** in, digest_type* out, int numElements) if (i < numElements) { - out[i] = boost::crypt::sha512_256(in[i]); + auto in_span {cuda::std::span(in[i], 64)}; + out[i] = boost::crypt::sha512_256(in_span).value(); } } @@ -59,7 +60,7 @@ int main() // Launch the Vector Add CUDA Kernel int threadsPerBlock = 256; - int blocksPerGrid =(numElements + threadsPerBlock - 1) / threadsPerBlock; + int blocksPerGrid = (numElements + threadsPerBlock - 1) / threadsPerBlock; std::cout << "CUDA kernel launch with " << blocksPerGrid << " blocks of " << threadsPerBlock << " threads" << std::endl; watch w; @@ -80,7 +81,8 @@ int main() w.reset(); for(int i = 0; i < numElements; ++i) { - results.emplace_back(boost::crypt::sha512_256(input_vector1[i])); + std::span in(input_vector1[i], elementSize); + results.emplace_back(boost::crypt::sha512_256(in).value()); } double t = w.elapsed();