From 74c0cdd7b73de31aaac8543d42a289fecc0a50a6 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 8 Oct 2024 11:00:46 -0400 Subject: [PATCH 001/107] Add basic jamfiles --- build.jam | 19 +++++++++++++++++++ test/Jamfile | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 build.jam create mode 100644 test/Jamfile diff --git a/build.jam b/build.jam new file mode 100644 index 0000000..2095c98 --- /dev/null +++ b/build.jam @@ -0,0 +1,19 @@ +# Copyright Matt Borland 2024 +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +require-b2 5.2 ; + +project /boost/crypt + : common-requirements + include + ; + +explicit + [ alias boost_core ] + [ alias all : boost_crypt test ] + ; + +call-if : boost-library crypt + ; diff --git a/test/Jamfile b/test/Jamfile new file mode 100644 index 0000000..d0306e4 --- /dev/null +++ b/test/Jamfile @@ -0,0 +1,44 @@ +# Copyright 2023 - 2024 Matt Borland +# Copyright 2023 - 2024 Christopher Kormanyos +# Distributed under the Boost Software License, Version 1.0. +# https://www.boost.org/LICENSE_1_0.txt + +require-b2 5.0.1 ; +import-search /boost/config/checks ; +import config : requires ; +import modules ; +import testing ; + +project : requirements + + gcc:-Wall + gcc:-Wextra + + # Clang-Cl gives errors that are incorrect or irrelevant (e.g. C++98 compat) + #clang:-Wall + #clang:-Wextra + + msvc:all + + # Additional flags by request + gcc:-Wsign-conversion + gcc:-Wconversion + gcc:-Wundef + gcc:-Wold-style-cast + #gcc:-Wduplicated-branches + gcc:-Wfloat-equal + + clang:-Wsign-conversion + clang:-Wconversion + clang:-Wundef + clang:-Wold-style-cast + clang:-Wfloat-equal + + msvc:on + clang:on + gcc:on + + [ requires cxx14_decltype_auto cxx14_generic_lambdas cxx14_return_type_deduction cxx14_variable_templates cxx14_constexpr ] + ; + +run test_md5.cpp ; From b6469b03ad8ed39db9d8910098581a83e1f4e5e9 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 8 Oct 2024 11:00:54 -0400 Subject: [PATCH 002/107] Add cmake support --- CMakeLists.txt | 30 ++++++++++++++++++++++++++++++ test/CMakeLists.txt | 12 ++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 test/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..f9ef54f --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,30 @@ +# Generated by `boostdep --cmake crypt` +# Copyright 2020, 2021 Peter Dimov +# Copyright 2023 Matt Borland +# Distributed under the Boost Software License, Version 1.0. +# https://www.boost.org/LICENSE_1_0.txt + +cmake_minimum_required(VERSION 3.8...3.20) + +project(boost_crypt VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX) + +add_library(boost_crypt INTERFACE) + +add_library(Boost::crypt ALIAS boost_crypt) + +target_include_directories(boost_crypt INTERFACE include) + +target_compile_features(boost_crypt INTERFACE cxx_std_14) + +if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt") + + add_subdirectory(test) + +endif() + +if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) + + include(GNUInstallDirs) + install(DIRECTORY "include/" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}") + +endif() diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..eb31095 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,12 @@ +# Copyright 2018, 2019 Peter Dimov +# Copyright 2023 Matt Borland +# Distributed under the 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(BoostTestJamfile OPTIONAL RESULT_VARIABLE HAVE_BOOST_TEST) + +if(HAVE_BOOST_TEST) + + boost_test_jamfile(FILE Jamfile LINK_LIBRARIES Boost::crypt Boost::core) + +endif() From b992e40c111d674f53edcf004068daeeba470fa6 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 8 Oct 2024 12:20:00 -0400 Subject: [PATCH 003/107] Add table macro definitions --- include/boost/crypt/utility/config.hpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 include/boost/crypt/utility/config.hpp diff --git a/include/boost/crypt/utility/config.hpp b/include/boost/crypt/utility/config.hpp new file mode 100644 index 0000000..0aec83a --- /dev/null +++ b/include/boost/crypt/utility/config.hpp @@ -0,0 +1,25 @@ +// Copyright 2024 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CRYPT_DETAIL_CONFIG_HPP +#define BOOST_CRYPT_DETAIL_CONFIG_HPP + +#ifdef __CUDACC__ +# ifndef BOOST_CRYPT_ENABLE_CUDA +# define BOOST_CRYPT_ENABLE_CUDA +# endif +#endif + +#if defined(__cpp_inline_variables) && __cpp_inline_variables >= 201606L +# define BOOST_CRYPT_CONSTEXPR_ARRAY inline constexpr +# define BOOST_CRYPT_DEVICE_ARRAY inline constexpr +#elif defined(BOOST_CRYPT_ENABLE_CUDA) +# define BOOST_CYPRT_CONSTEXPR_ARRAY static constexpr +# define BOOST_CRYPT_DEVICE_ARRAY __constant__ +#else +# define BOOST_CRYPT_CONSTEXPR_ARRAY static constexpr +# define BOOST_CRYPT_DEVICE_ARRAY static constexpr +#endif + +#endif //BOOST_CRYPT_DETAIL_CONFIG_HPP From 8e426f9b2ecf42f4e318605ea6ff973a7a265c63 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 8 Oct 2024 13:11:36 -0400 Subject: [PATCH 004/107] Add rotr and rotl impls --- include/boost/crypt/utility/bit.hpp | 96 +++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 include/boost/crypt/utility/bit.hpp diff --git a/include/boost/crypt/utility/bit.hpp b/include/boost/crypt/utility/bit.hpp new file mode 100644 index 0000000..d69f86d --- /dev/null +++ b/include/boost/crypt/utility/bit.hpp @@ -0,0 +1,96 @@ +// Copyright 2024 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_BIT_HPP +#define BOOST_BIT_HPP + +#include +#include +#include + +namespace boost { +namespace crypt { +namespace detail { + +// Forward decls +template ::value, bool> = true> +constexpr T rotl(T x, U s) noexcept; +template ::value, bool> = true> +constexpr T rotl(T x, U s) noexcept; + +template ::value, bool> = true> +constexpr T rotr(T x, U s) noexcept; +template ::value, bool> = true> +constexpr T rotr(T x, U s) noexcept; + +// Only works for unsigned s so we can optimize away the call to rotr +template ::value, bool>> +constexpr T rotl(T x, U s) noexcept +{ + constexpr auto N {std::numeric_limits::digits}; + const auto r {s % N}; + + if (r == 0) + { + return x; + } + + return (x << r) | (x >> (N - r)); +} + +template ::value, bool>> +constexpr T rotl(T x, U s) noexcept +{ + constexpr auto N {std::numeric_limits::digits}; + const auto r {s % N}; + + if (r == 0) + { + return x; + } + else if (r < 0) + { + return rotr(x, -r); + } + + return (x << r) | (x >> (N - r)); +} + +template ::value, bool>> +constexpr T rotr(T x, U s) noexcept +{ + constexpr auto N {std::numeric_limits::digits}; + const auto r {s % N}; + + if (r == 0) + { + return x; + } + + return (x >> r) | (x << (N - r)); +} + +template ::value, bool>> +constexpr T rotr(T x, U s) noexcept +{ + constexpr auto N {std::numeric_limits::digits}; + const auto r {s % N}; + + if (r == 0) + { + return x; + } + else if (r < 0) + { + return rotl(x, -r); + } + + return (x >> r) | (x << (N - r)); +} + +} // namespace detail +} // namespace crypt +} // namespace boost + +#endif //BOOST_BIT_HPP From c40d30cd44567513536f3b143f894fd3e6b0da88 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 8 Oct 2024 15:16:21 -0400 Subject: [PATCH 005/107] Add 32 bit swap endian function --- include/boost/crypt/utility/bit.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/boost/crypt/utility/bit.hpp b/include/boost/crypt/utility/bit.hpp index d69f86d..36e93de 100644 --- a/include/boost/crypt/utility/bit.hpp +++ b/include/boost/crypt/utility/bit.hpp @@ -89,6 +89,14 @@ constexpr T rotr(T x, U s) noexcept return (x >> r) | (x << (N - r)); } +constexpr auto swap_endian(const std::uint32_t val) -> std::uint32_t +{ + return ((val & 0xFF000000) >> 24U) | + ((val & 0x00FF0000) >> 8U) | + ((val & 0x0000FF00) << 8U) | + ((val & 0x000000FF) << 24U); +} + } // namespace detail } // namespace crypt } // namespace boost From 8e9e823479f02643d2cd7adda95ab7a2c443988f Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 8 Oct 2024 15:21:12 -0400 Subject: [PATCH 006/107] Add assertion macros --- include/boost/crypt/utility/config.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/boost/crypt/utility/config.hpp b/include/boost/crypt/utility/config.hpp index 0aec83a..58fac47 100644 --- a/include/boost/crypt/utility/config.hpp +++ b/include/boost/crypt/utility/config.hpp @@ -11,6 +11,7 @@ # endif #endif +// ---- Constexpr arrays ----- #if defined(__cpp_inline_variables) && __cpp_inline_variables >= 201606L # define BOOST_CRYPT_CONSTEXPR_ARRAY inline constexpr # define BOOST_CRYPT_DEVICE_ARRAY inline constexpr @@ -21,5 +22,12 @@ # define BOOST_CRYPT_CONSTEXPR_ARRAY static constexpr # define BOOST_CRYPT_DEVICE_ARRAY static constexpr #endif +// ---- Constexpr arrays ----- + +// ----- Assertions ----- +#include +#define BOOST_CRYPT_ASSERT(x) assert(x) +#define BOOST_CRYPT_ASSERT_MSG(expr, msg) assert((expr)&&(msg)) +// ----- Assertions ----- #endif //BOOST_CRYPT_DETAIL_CONFIG_HPP From 14ca1e2cc9d60b24013f8ed4e87145c8974aa84f Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 8 Oct 2024 15:21:28 -0400 Subject: [PATCH 007/107] Add super basic md5 impl --- include/boost/crypt/hash/md5.hpp | 194 +++++++++++++++++++++++++++++++ 1 file changed, 194 insertions(+) create mode 100644 include/boost/crypt/hash/md5.hpp diff --git a/include/boost/crypt/hash/md5.hpp b/include/boost/crypt/hash/md5.hpp new file mode 100644 index 0000000..f570746 --- /dev/null +++ b/include/boost/crypt/hash/md5.hpp @@ -0,0 +1,194 @@ +// Copyright 2024 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CRYPT_HASH_MD5_HPP +#define BOOST_CRYPT_HASH_MD5_HPP + +#include +#include + +#include +#include +#include + +namespace boost { +namespace crypt { + +namespace detail { + +static constexpr std::array S { + 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 +}; + +static constexpr std::array K { + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 +}; + +template +auto md5_preprocess(T begin, T end) -> std::vector +{ + std::vector vec; + vec.reserve(end - begin); + std::copy(begin, end, std::back_inserter(vec)); + return vec; +} + +template +auto md5_preprocess(T begin, std::size_t len) -> std::vector +{ + std::vector vec; + vec.reserve(len); + std::copy(begin, begin + len, std::back_inserter(vec)); + return vec; +} + +auto md5_pad(const std::vector& message) noexcept -> std::vector +{ + std::vector padded_message {message}; + const std::uint64_t original_length {message.size() * 8U}; + padded_message.emplace_back(0x80); + + while ((padded_message.size() * 8U) % 512U != 448U) + { + padded_message.push_back(static_cast(0x00)); + } + + // Add the original length as a 64-bit number + for (std::size_t i = 0; i < 8; ++i) + { + padded_message.push_back(static_cast((original_length >> (8 * i)) & 0xFF)); + } + + return padded_message; +} + +template +auto md5_impl(const std::vector& padded_message) -> ResultType +{ + std::uint32_t a0 {0x67452301}; + std::uint32_t b0 {0xefcdab89}; + std::uint32_t c0 {0x98badcfe}; + std::uint32_t d0 {0x10325476}; + + std::array blocks {}; + + std::size_t message_chunk {}; + while (message_chunk < padded_message.size()) + { + for (auto& block : blocks) + { + block = static_cast( + (static_cast(padded_message[message_chunk])) + + (static_cast(padded_message[message_chunk + 1U]) << 8U) + + (static_cast(padded_message[message_chunk + 2U]) << 16U) + + (static_cast(padded_message[message_chunk + 3U]) << 24U) + ); + + message_chunk += 4U; + } + + std::uint32_t A {a0}; + std::uint32_t B {b0}; + std::uint32_t C {c0}; + std::uint32_t D {d0}; + + for (std::uint32_t i {}; i < 64U; ++i) + { + std::uint32_t F {}; + std::uint32_t g {}; + + if (i <= 15U) + { + F = (B & C) | ((~B) & D); + g = i; + } + else if (i <= 31U) + { + F = (D & B) | ((~D) & C); + g = (5U * i + 1U) % 16U; + } + else if (i <= 47U) + { + F = B ^ C ^ D; + g = (3U * i + 5U) % 16U; + } + else + { + F = C ^ (B | (~D)); + g = (7U * i) % 16U; + } + + BOOST_CRYPT_ASSERT(i <= 63U); + + F = F + A + K[i] + blocks[g]; + A = D; + D = C; + C = B; + B = B + rotl(F, S[i]); + } + + a0 += A; + b0 += B; + c0 += C; + d0 += D; + } + + return ResultType {swap_endian(a0), + swap_endian(b0), + swap_endian(c0), + swap_endian(d0)}; +} + +} // namespace detail + +template +ResultType md5(T begin, T end) +{ + if (end <= begin) + { + return ResultType {0, 0, 0, 0}; + } + + + const auto message {detail::md5_preprocess(begin, end)}; + const auto padded_message {detail::md5_pad(message)}; + return detail::md5_impl(padded_message); +} + +template > +ResultType md5(const char* str) +{ + if (str == nullptr) + { + return ResultType {0, 0, 0, 0}; + } + + const auto message_len {std::strlen(str)}; + const auto message {detail::md5_preprocess(str, message_len)}; + const auto padded_message {detail::md5_pad(message)}; + return detail::md5_impl(padded_message); +} + +} // namespace crypt +} // namespace boost + +#endif // BOOST_CRYPT_HASH_MD5_HPP From 0f52a735962e6c6d51015d090517882f15944799 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 8 Oct 2024 15:29:29 -0400 Subject: [PATCH 008/107] Add basic test set --- test/test_md5.cpp | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 test/test_md5.cpp diff --git a/test/test_md5.cpp b/test/test_md5.cpp new file mode 100644 index 0000000..2c26932 --- /dev/null +++ b/test/test_md5.cpp @@ -0,0 +1,36 @@ +// Copyright 2024 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt +// +// Start with the sample hashes from wiki + +#include +#include + +void basic_tests() +{ + const auto message_1_result {boost::crypt::md5("The quick brown fox jumps over the lazy dog")}; + BOOST_TEST_EQ(message_1_result[0], 0x9e107d9d); + BOOST_TEST_EQ(message_1_result[1], 0x372bb682); + BOOST_TEST_EQ(message_1_result[2], 0x6bd81d35); + BOOST_TEST_EQ(message_1_result[3], 0x42a419d6); + + const auto message_2_result {boost::crypt::md5("The quick brown fox jumps over the lazy dog.")}; + BOOST_TEST_EQ(message_2_result[0], 0xe4d909c2); + BOOST_TEST_EQ(message_2_result[1], 0x90d0fb1c); + BOOST_TEST_EQ(message_2_result[2], 0xa068ffad); + BOOST_TEST_EQ(message_2_result[3], 0xdf22cbd0); + + const auto message_3_result {boost::crypt::md5("")}; + BOOST_TEST_EQ(message_3_result[0], 0xd41d8cd9); + BOOST_TEST_EQ(message_3_result[1], 0x8f00b204); + BOOST_TEST_EQ(message_3_result[2], 0xe9800998); + BOOST_TEST_EQ(message_3_result[3], 0xecf8427e); +} + +int main() +{ + basic_tests(); + + return boost::report_errors(); +} From b5173b386f66b0aa33f38bcd16a2164a0dca00c9 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 8 Oct 2024 15:49:14 -0400 Subject: [PATCH 009/107] Fix conversion error --- include/boost/crypt/hash/md5.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/crypt/hash/md5.hpp b/include/boost/crypt/hash/md5.hpp index f570746..02157cd 100644 --- a/include/boost/crypt/hash/md5.hpp +++ b/include/boost/crypt/hash/md5.hpp @@ -47,7 +47,7 @@ template auto md5_preprocess(T begin, T end) -> std::vector { std::vector vec; - vec.reserve(end - begin); + vec.reserve(static_cast(end - begin)); std::copy(begin, end, std::back_inserter(vec)); return vec; } From 53ab95180e4565316c465f1eae921cfb3303f131 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 8 Oct 2024 15:49:33 -0400 Subject: [PATCH 010/107] Add detection for string view --- include/boost/crypt/utility/config.hpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/include/boost/crypt/utility/config.hpp b/include/boost/crypt/utility/config.hpp index 58fac47..4770b94 100644 --- a/include/boost/crypt/utility/config.hpp +++ b/include/boost/crypt/utility/config.hpp @@ -30,4 +30,16 @@ #define BOOST_CRYPT_ASSERT_MSG(expr, msg) assert((expr)&&(msg)) // ----- Assertions ----- +// ----- Has CXX something ----- +// C++17 +#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) +# if __has_include() +# include +# if defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201606L +# define BOOST_CRYPT_HAS_STRING_VIEW +# endif +# endif +#endif +// ----- Has CXX something ----- + #endif //BOOST_CRYPT_DETAIL_CONFIG_HPP From 35416f703f50188568a406f32fb343e207ba1980 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 8 Oct 2024 15:49:43 -0400 Subject: [PATCH 011/107] Add additional overloads --- include/boost/crypt/hash/md5.hpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/include/boost/crypt/hash/md5.hpp b/include/boost/crypt/hash/md5.hpp index 02157cd..33bf839 100644 --- a/include/boost/crypt/hash/md5.hpp +++ b/include/boost/crypt/hash/md5.hpp @@ -160,7 +160,7 @@ auto md5_impl(const std::vector& padded_message) -> ResultType } // namespace detail -template +template , typename T> ResultType md5(T begin, T end) { if (end <= begin) @@ -168,7 +168,6 @@ ResultType md5(T begin, T end) return ResultType {0, 0, 0, 0}; } - const auto message {detail::md5_preprocess(begin, end)}; const auto padded_message {detail::md5_pad(message)}; return detail::md5_impl(padded_message); @@ -188,6 +187,20 @@ ResultType md5(const char* str) return detail::md5_impl(padded_message); } +template > +ResultType md5(const std::string& str) +{ + return md5(str.begin(), str.end()); +} + +#ifdef BOOST_CRYPT_HAS_STRING_VIEW +template > +ResultType md5(const std::string_view& str) +{ + return md5(str.begin(), str.end()); +} +#endif + } // namespace crypt } // namespace boost From 235dd609c97f85d6beb76902d930616edf199db3 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 8 Oct 2024 15:50:00 -0400 Subject: [PATCH 012/107] Add additional tests for new overloads --- test/test_md5.cpp | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/test/test_md5.cpp b/test/test_md5.cpp index 2c26932..83ee3f5 100644 --- a/test/test_md5.cpp +++ b/test/test_md5.cpp @@ -6,6 +6,7 @@ #include #include +#include void basic_tests() { @@ -28,9 +29,52 @@ void basic_tests() BOOST_TEST_EQ(message_3_result[3], 0xecf8427e); } +void string_test() +{ + std::string message_1 {"The quick brown fox jumps over the lazy dog"}; + const auto message_1_result {boost::crypt::md5(message_1)}; + BOOST_TEST_EQ(message_1_result[0], 0x9e107d9d); + BOOST_TEST_EQ(message_1_result[1], 0x372bb682); + BOOST_TEST_EQ(message_1_result[2], 0x6bd81d35); + BOOST_TEST_EQ(message_1_result[3], 0x42a419d6); + + #ifdef BOOST_CRYPT_HAS_STRING_VIEW + std::string_view view_1 {message_1}; + const auto view_1_result {boost::crypt::md5(view_1)}; + BOOST_TEST_EQ(view_1_result[0], 0x9e107d9d); + BOOST_TEST_EQ(view_1_result[1], 0x372bb682); + BOOST_TEST_EQ(view_1_result[2], 0x6bd81d35); + BOOST_TEST_EQ(view_1_result[3], 0x42a419d6); + #endif + + std::string message_2 {"The quick brown fox jumps over the lazy dog."}; + const auto message_2_result {boost::crypt::md5(message_2.begin(), message_2.end())}; + BOOST_TEST_EQ(message_2_result[0], 0xe4d909c2); + BOOST_TEST_EQ(message_2_result[1], 0x90d0fb1c); + BOOST_TEST_EQ(message_2_result[2], 0xa068ffad); + BOOST_TEST_EQ(message_2_result[3], 0xdf22cbd0); +} + +void bad_input() +{ + const auto null_message {boost::crypt::md5(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); + + std::string message_1 {"The quick brown fox jumps over the lazy dog"}; + const auto message_1_result {boost::crypt::md5(message_1.begin(), message_1.begin())}; + BOOST_TEST_EQ(message_1_result[0], 0x0); + BOOST_TEST_EQ(message_1_result[1], 0x0); + BOOST_TEST_EQ(message_1_result[2], 0x0); + BOOST_TEST_EQ(message_1_result[3], 0x0); +} + int main() { basic_tests(); + bad_input(); return boost::report_errors(); } From da230bd062621acc6cff422af3cc67e685824cd4 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 8 Oct 2024 16:05:23 -0400 Subject: [PATCH 013/107] Add drone CI --- .drone.jsonnet | 420 +++++++++++++++++++++++++++++++++++++++++++++++ .drone/drone.bat | 25 +++ .drone/drone.sh | 32 ++++ 3 files changed, 477 insertions(+) create mode 100644 .drone.jsonnet create mode 100644 .drone/drone.bat create mode 100755 .drone/drone.sh diff --git a/.drone.jsonnet b/.drone.jsonnet new file mode 100644 index 0000000..a2c30dc --- /dev/null +++ b/.drone.jsonnet @@ -0,0 +1,420 @@ +# Copyright 2022, 2023 Peter Dimov +# Distributed under the Boost Software License, Version 1.0. +# https://www.boost.org/LICENSE_1_0.txt + +local library = "crypt"; + +local triggers = +{ + branch: [ "master", "develop", "feature/*" ] +}; + +local ubsan = { UBSAN: '1', UBSAN_OPTIONS: 'print_stacktrace=1' }; +local asan = { ASAN: '1' }; + +local linux_pipeline(name, image, environment, packages = "", sources = [], arch = "amd64") = +{ + name: name, + kind: "pipeline", + type: "docker", + trigger: triggers, + platform: + { + os: "linux", + arch: arch + }, + steps: + [ + { + name: "everything", + image: image, + privileged: true, + environment: environment, + commands: + [ + 'set -e', + 'wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -', + ] + + (if sources != [] then [ ('apt-add-repository "' + source + '"') for source in sources ] else []) + + (if packages != "" then [ 'apt-get update', 'apt-get -y install ' + packages ] else []) + + [ + 'export LIBRARY=' + library, + './.drone/drone.sh', + ] + } + ] +}; + +local macos_pipeline(name, environment, xcode_version = "12.2", osx_version = "catalina", arch = "amd64") = +{ + name: name, + kind: "pipeline", + type: "exec", + trigger: triggers, + platform: { + "os": "darwin", + "arch": arch + }, + node: { + "os": osx_version + }, + steps: [ + { + name: "everything", + environment: environment + { "DEVELOPER_DIR": "/Applications/Xcode-" + xcode_version + ".app/Contents/Developer" }, + commands: + [ + 'export LIBRARY=' + library, + './.drone/drone.sh', + ] + } + ] +}; + +local windows_pipeline(name, image, environment, arch = "amd64") = +{ + name: name, + kind: "pipeline", + type: "docker", + trigger: triggers, + platform: + { + os: "windows", + arch: arch + }, + "steps": + [ + { + name: "everything", + image: image, + environment: environment, + commands: + [ + 'cmd /C .drone\\\\drone.bat ' + library, + ] + } + ] +}; + +[ + + linux_pipeline( + "Linux 18.04 GCC 8 32/64", + "cppalliance/droneubuntu1804:1", + { TOOLSET: 'gcc', COMPILER: 'g++-8', CXXSTD: '03,11,14,17', ADDRMD: '32,64' }, + "g++-8-multilib", + ), + + linux_pipeline( + "Linux 20.04 GCC 9* 32/64", + "cppalliance/droneubuntu2004:1", + { TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a', ADDRMD: '32,64' }, + ), + + linux_pipeline( + "Linux 20.04 GCC 9* ARM64", + "cppalliance/droneubuntu2004:multiarch", + { TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a' }, + arch="arm64", + ), + + linux_pipeline( + "Linux 20.04 GCC 9* ARM64 - ASAN", + "cppalliance/droneubuntu2004:multiarch", + { TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a' } + asan, + arch="arm64", + ), + + linux_pipeline( + "Linux 20.04 GCC 9* S390x", + "cppalliance/droneubuntu2004:multiarch", + { TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a' }, + arch="s390x", + ), + + linux_pipeline( + "Linux 20.04 GCC 10 32/64", + "cppalliance/droneubuntu2004:1", + { TOOLSET: 'gcc', COMPILER: 'g++-10', CXXSTD: '03,11,14,17,20', ADDRMD: '32,64' }, + "g++-10-multilib", + ), + + linux_pipeline( + "Linux 22.04 GCC 11* 32/64", + "cppalliance/droneubuntu2204:1", + { TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a', ADDRMD: '32,64' }, + ), + + linux_pipeline( + "Linux 22.04 GCC 12 32 ASAN 03", + "cppalliance/droneubuntu2204:1", + { TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '03', ADDRMD: '32' } + asan, + "g++-12-multilib", + ), + + linux_pipeline( + "Linux 22.04 GCC 12 32 ASAN 11", + "cppalliance/droneubuntu2204:1", + { TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '11', ADDRMD: '32' } + asan, + "g++-12-multilib", + ), + + linux_pipeline( + "Linux 22.04 GCC 12 32 ASAN 14", + "cppalliance/droneubuntu2204:1", + { TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '14', ADDRMD: '32' } + asan, + "g++-12-multilib", + ), + + linux_pipeline( + "Linux 22.04 GCC 12 32 ASAN 17", + "cppalliance/droneubuntu2204:1", + { TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '17', ADDRMD: '32' } + asan, + "g++-12-multilib", + ), + + linux_pipeline( + "Linux 22.04 GCC 12 32 ASAN 20", + "cppalliance/droneubuntu2204:1", + { TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '20', ADDRMD: '32' } + asan, + "g++-12-multilib", + ), + + linux_pipeline( + "Linux 22.04 GCC 12 32 ASAN 2b", + "cppalliance/droneubuntu2204:1", + { TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '2b', ADDRMD: '32' } + asan, + "g++-12-multilib", + ), + + linux_pipeline( + "Linux 22.04 GCC 12 64 ASAN", + "cppalliance/droneubuntu2204:1", + { TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '03,11,14,17,20,2b', ADDRMD: '64' } + asan, + "g++-12-multilib", + ), + + linux_pipeline( + "Linux 24.04 GCC 13 32/64", + "cppalliance/droneubuntu2404:1", + { TOOLSET: 'gcc', COMPILER: 'g++-13', CXXSTD: '03,11,14,17,20,23', ADDRMD: '32,64', CXXFLAGS: "-fexcess-precision=fast" }, + "g++-13-multilib", + ), + + linux_pipeline( + "Linux 24.04 GCC 13 GNU 32/64", + "cppalliance/droneubuntu2404:1", + { TOOLSET: 'gcc', COMPILER: 'g++-13', CXXSTD: '03,11,14,17,20,23', ADDRMD: '32,64', CXXFLAGS: "-fexcess-precision=fast", CXXSTDDIALECT: "gnu" }, + "g++-13-multilib", + ), + + linux_pipeline( + "Linux 24.04 GCC 14 32", + "cppalliance/droneubuntu2404:1", + { TOOLSET: 'gcc', COMPILER: 'g++-14', CXXSTD: '03,11,14,17,20,23', ADDRMD: '32', CXXFLAGS: "-fexcess-precision=fast" }, + "g++-14-multilib", + ), + + linux_pipeline( + "Linux 24.04 GCC 14 64", + "cppalliance/droneubuntu2404:1", + { TOOLSET: 'gcc', COMPILER: 'g++-14', CXXSTD: '03,11,14,17,20,23', ADDRMD: '64', CXXFLAGS: "-fexcess-precision=fast" }, + "g++-14-multilib", + ), + + linux_pipeline( + "Linux 24.04 GCC 14 GNU 32", + "cppalliance/droneubuntu2404:1", + { TOOLSET: 'gcc', COMPILER: 'g++-14', CXXSTD: '03,11,14,17,20,23', ADDRMD: '32', CXXFLAGS: "-fexcess-precision=fast", CXXSTDDIALECT: "gnu" }, + "g++-14-multilib", + ), + + linux_pipeline( + "Linux 24.04 GCC 14 GNU 64", + "cppalliance/droneubuntu2404:1", + { TOOLSET: 'gcc', COMPILER: 'g++-14', CXXSTD: '03,11,14,17,20,23', ADDRMD: '64', CXXFLAGS: "-fexcess-precision=fast", CXXSTDDIALECT: "gnu" }, + "g++-14-multilib", + ), + + linux_pipeline( + "Linux 18.04 GCC 7* 32 03", + "cppalliance/droneubuntu1804:1", + { TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03', ADDRMD: '32' }, + "nload", + ), + + linux_pipeline( + "Linux 18.04 GCC 7* 32 11", + "cppalliance/droneubuntu1804:1", + { TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11', ADDRMD: '32' }, + "nload", + ), + + linux_pipeline( + "Linux 18.04 GCC 7* 32 14", + "cppalliance/droneubuntu1804:1", + { TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '14', ADDRMD: '32' }, + "nload", + ), + + linux_pipeline( + "Linux 18.04 GCC 7* 32 17", + "cppalliance/droneubuntu1804:1", + { TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '17', ADDRMD: '32' }, + "nload", + ), + + linux_pipeline( + "Linux 18.04 GCC 7* 64 03", + "cppalliance/droneubuntu1804:1", + { TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03', ADDRMD: '64' }, + "nload", + ), + + linux_pipeline( + "Linux 18.04 GCC 7* 64 11", + "cppalliance/droneubuntu1804:1", + { TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11', ADDRMD: '64' }, + "nload", + ), + + linux_pipeline( + "Linux 18.04 GCC 7* 64 14", + "cppalliance/droneubuntu1804:1", + { TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '14', ADDRMD: '64' }, + "nload", + ), + + linux_pipeline( + "Linux 18.04 GCC 7* 64 17", + "cppalliance/droneubuntu1804:1", + { TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '17', ADDRMD: '64' }, + "nload", + ), + + linux_pipeline( + "Linux 18.04 Clang 6.0", + "cppalliance/droneubuntu1804:1", + { TOOLSET: 'clang', COMPILER: 'clang++-6.0', CXXSTD: '03,11,14,17' }, + "clang-6.0", + ), + + linux_pipeline( + "Linux 20.04 Clang 7", + "cppalliance/droneubuntu2004:1", + { TOOLSET: 'clang', COMPILER: 'clang++-7', CXXSTD: '03,11,14,17' }, + "clang-7", + ), + + linux_pipeline( + "Linux 20.04 Clang 8", + "cppalliance/droneubuntu2004:1", + { TOOLSET: 'clang', COMPILER: 'clang++-8', CXXSTD: '03,11,14,17' }, + "clang-8", + ), + + linux_pipeline( + "Linux 20.04 Clang 9", + "cppalliance/droneubuntu2004:1", + { TOOLSET: 'clang', COMPILER: 'clang++-9', CXXSTD: '03,11,14,17,2a' }, + "clang-9", + ), + + linux_pipeline( + "Linux 20.04 Clang 10", + "cppalliance/droneubuntu2004:1", + { TOOLSET: 'clang', COMPILER: 'clang++-10', CXXSTD: '03,11,14,17,2a' }, + "clang-10", + ), + + linux_pipeline( + "Linux 20.04 Clang 11", + "cppalliance/droneubuntu2004:1", + { TOOLSET: 'clang', COMPILER: 'clang++-11', CXXSTD: '03,11,14,17,2a' }, + "clang-11", + ), + + linux_pipeline( + "Linux 20.04 Clang 12", + "cppalliance/droneubuntu2004:1", + { TOOLSET: 'clang', COMPILER: 'clang++-12', CXXSTD: '03,11,14,17,2a' }, + "clang-12", + ), + + linux_pipeline( + "Linux 22.04 Clang 13", + "cppalliance/droneubuntu2204:1", + { TOOLSET: 'clang', COMPILER: 'clang++-13', CXXSTD: '03,11,14,17,20' }, + "clang-13", + ), + + linux_pipeline( + "Linux 22.04 Clang 14 UBSAN", + "cppalliance/droneubuntu2204:1", + { TOOLSET: 'clang', COMPILER: 'clang++-14', CXXSTD: '03,11,14,17,20,2b' } + ubsan, + "clang-14", + ), + + linux_pipeline( + "Linux 22.04 Clang 14 ASAN", + "cppalliance/droneubuntu2204:1", + { TOOLSET: 'clang', COMPILER: 'clang++-14', CXXSTD: '03,11,14,17,20,2b' } + asan, + "clang-14", + ), + + linux_pipeline( + "Linux 22.04 Clang 15", + "cppalliance/droneubuntu2204:1", + { TOOLSET: 'clang', COMPILER: 'clang++-15', CXXSTD: '03,11,14,17,20,2b' }, + "clang-15", + ["deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-15 main"], + ), + + linux_pipeline( + "Linux 22.04 Clang 16", + "cppalliance/droneubuntu2204:1", + { TOOLSET: 'clang', COMPILER: 'clang++-16', CXXSTD: '03,11,14,17,20,2b' }, + "clang-16", + ["deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-16 main"], + ), + + linux_pipeline( + "Linux 24.04 Clang 17", + "cppalliance/droneubuntu2404:1", + { TOOLSET: 'clang', COMPILER: 'clang++-17', CXXSTD: '03,11,14,17,20,2b' }, + "clang-17", + ["deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-17 main"], + ), + + linux_pipeline( + "Linux 24.04 Clang 18", + "cppalliance/droneubuntu2404:1", + { TOOLSET: 'clang', COMPILER: 'clang++-18', CXXSTD: '03,11,14,17,20,2b' }, + "clang-18", + ["deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-18 main"], + ), + + macos_pipeline( + "MacOS 12.4 Xcode 13.4.1 UBSAN", + { TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '03,11,14,17,20,2b' } + ubsan, + xcode_version = "13.4.1", osx_version = "monterey", arch = "arm64", + ), + + macos_pipeline( + "MacOS 12.4 Xcode 13.4.1 ASAN", + { TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '03,11,14,17,20,2b' } + asan, + xcode_version = "13.4.1", osx_version = "monterey", arch = "arm64", + ), + + windows_pipeline( + "Windows VS2019 msvc-14.2", + "cppalliance/dronevs2019", + { TOOLSET: 'msvc-14.2', CXXSTD: '14,17,20,latest' }, + ), + + windows_pipeline( + "Windows VS2022 msvc-14.3", + "cppalliance/dronevs2022:1", + { TOOLSET: 'msvc-14.3', CXXSTD: '14,17,20,latest' }, + ), +] diff --git a/.drone/drone.bat b/.drone/drone.bat new file mode 100644 index 0000000..2b56e63 --- /dev/null +++ b/.drone/drone.bat @@ -0,0 +1,25 @@ +@REM Copyright 2022 Peter Dimov +@REM Distributed under the Boost Software License, Version 1.0. +@REM https://www.boost.org/LICENSE_1_0.txt + +@ECHO ON + +set LIBRARY=%1 +set DRONE_BUILD_DIR=%CD% + +echo $env:DRONE_STAGE_MACHINE + +set BOOST_BRANCH=develop +if "%DRONE_BRANCH%" == "master" set BOOST_BRANCH=master +cd .. +git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root +cd boost-root +git submodule update --init tools/boostdep +xcopy /s /e /q %DRONE_BUILD_DIR% libs\%LIBRARY%\ +python tools/boostdep/depinst/depinst.py -I example %LIBRARY% +cmd /c bootstrap +b2 -d0 headers + +if not "%CXXSTD%" == "" set CXXSTD=cxxstd=%CXXSTD% +if not "%ADDRMD%" == "" set ADDRMD=address-model=%ADDRMD% +b2 -j3 libs/%LIBRARY%/test toolset=%TOOLSET% %CXXSTD% %ADDRMD% variant=debug,release embed-manifest-via=linker diff --git a/.drone/drone.sh b/.drone/drone.sh new file mode 100755 index 0000000..5a54695 --- /dev/null +++ b/.drone/drone.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +# Copyright 2022 Peter Dimov +# Distributed under the Boost Software License, Version 1.0. +# https://www.boost.org/LICENSE_1_0.txt + +set -ex +export PATH=~/.local/bin:/usr/local/bin:$PATH +uname -a +echo $DRONE_STAGE_MACHINE + +DRONE_BUILD_DIR=$(pwd) + +BOOST_BRANCH=develop +if [ "$DRONE_BRANCH" = "master" ]; then BOOST_BRANCH=master; fi + +cd .. +git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root +cd boost-root +git submodule update --init tools/boostdep +mkdir -p libs/$LIBRARY +cp -r $DRONE_BUILD_DIR/* libs/$LIBRARY +python tools/boostdep/depinst/depinst.py -I example $LIBRARY +./bootstrap.sh +./b2 -d0 headers + +if [[ $(uname) == "Linux" ]]; then + echo 0 | sudo tee /proc/sys/kernel/randomize_va_space +fi + +echo "using $TOOLSET : : $COMPILER ;" > ~/user-config.jam +./b2 -j3 libs/$LIBRARY/test toolset=$TOOLSET cxxstd=$CXXSTD variant=debug,release ${ADDRMD:+address-model=$ADDRMD} ${UBSAN:+undefined-sanitizer=norecover debug-symbols=on} ${ASAN:+address-sanitizer=norecover debug-symbols=on} ${CXXFLAGS:+cxxflags=$CXXFLAGS} ${CXXSTDDIALECT:+cxxstd-dialect=$CXXSTDDIALECT} ${LINKFLAGS:+linkflags=$LINKFLAGS} From 23e5c23d5f1e23d738a2be494e36810efac03951 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 8 Oct 2024 16:07:15 -0400 Subject: [PATCH 014/107] Add codecov to CI --- .github/workflows/codecov.yml | 73 ++++++++++++++++++++ test/cover/make_gcov_01_generic.gmk | 103 ++++++++++++++++++++++++++++ test/cover/make_gcov_02_files.gmk | 21 ++++++ test/cover/make_gcov_03_flags.gmk | 73 ++++++++++++++++++++ test/cover/make_gcov_04_rules.gmk | 22 ++++++ 5 files changed, 292 insertions(+) create mode 100644 .github/workflows/codecov.yml create mode 100644 test/cover/make_gcov_01_generic.gmk create mode 100644 test/cover/make_gcov_02_files.gmk create mode 100644 test/cover/make_gcov_03_flags.gmk create mode 100644 test/cover/make_gcov_04_rules.gmk diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml new file mode 100644 index 0000000..e37414c --- /dev/null +++ b/.github/workflows/codecov.yml @@ -0,0 +1,73 @@ +# ------------------------------------------------------------------------------ +# Copyright Matt Borland 2023 - 2024. +# Copyright Christopher Kormanyos 2023 - 2024. +# Distributed under the Boost Software License, +# Version 1.0. (See accompanying file LICENSE_1_0.txt +# or copy at http://www.boost.org/LICENSE_1_0.txt) +# ------------------------------------------------------------------------------ + +name: codecov +on: + push: + branches: + - master + - develop + - feature/** + pull_request: + types: [opened, synchronize, reopened] +jobs: + gcc-gcov-native: + runs-on: ubuntu-latest + defaults: + run: + shell: bash + strategy: + fail-fast: false + matrix: + standard: [ c++20 ] + compiler: [ g++ ] + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: '0' + - name: update-tools + run: | + sudo apt install lcov locales + sudo locale-gen de_DE.UTF-8 + sudo update-locale + + - name: clone-submods-bootstrap-headers-boost-develop + run: | + git clone -b develop --depth 1 https://github.com/boostorg/boost.git ../boost-root + cd ../boost-root + git submodule update --init tools + git submodule update --init libs/assert + git submodule update --init libs/config + git submodule update --init libs/core + git submodule update --init libs/math + git submodule update --init libs/multiprecision + git submodule update --init libs/predef + git submodule update --init libs/static_assert + git submodule update --init libs/test + ./bootstrap.sh + ./b2 headers + - name: gcc-gcov-native + run: | + cd test/cover + echo "build and run gcov/lcov/genhtml" + echo "make prepare -f make_gcov_01_generic.gmk MY_ALL_COV=0 MY_BOOST_ROOT=../../../boost-root MY_CC=${{ matrix.compiler }} MY_STD=${{ matrix.standard }}" + echo + make prepare -f make_gcov_01_generic.gmk MY_ALL_COV=0 MY_BOOST_ROOT=../../../boost-root MY_CC=${{ matrix.compiler }} MY_STD=${{ matrix.standard }} + echo + echo "make gcov -f make_gcov_01_generic.gmk --jobs=8 MY_ALL_COV=0 MY_BOOST_ROOT=../../../boost-root MY_CC=${{ matrix.compiler }} MY_STD=${{ matrix.standard }}" + echo + make gcov -f make_gcov_01_generic.gmk --jobs=8 MY_ALL_COV=0 MY_BOOST_ROOT=../../../boost-root MY_CC=${{ matrix.compiler }} MY_STD=${{ matrix.standard }} + echo + - name: upload-codecov + uses: codecov/codecov-action@v4 + with: + plugin: gcov + file: ${{ runner.workspace }}/crypt/test/cover/coverage.info + token: ${{ secrets.CODECOV_TOKEN }} + fail_ci_if_error: true + verbose: false diff --git a/test/cover/make_gcov_01_generic.gmk b/test/cover/make_gcov_01_generic.gmk new file mode 100644 index 0000000..14a4b8c --- /dev/null +++ b/test/cover/make_gcov_01_generic.gmk @@ -0,0 +1,103 @@ +# ----------------------------------------------------------------------------- +# Copyright Matt Borland 2023 - 2024. +# Copyright Christopher Kormanyos 2023 - 2024. +# Distributed under the Boost Software License, +# Version 1.0. (See accompanying file LICENSE_1_0.txt +# or copy at http://www.boost.org/LICENSE_1_0.txt) +# ----------------------------------------------------------------------------- + +# cd /mnt/c/ChrisGitRepos/cppalliance/crypt/test/cover +# make prepare -f make_gcov_01_generic.gmk MY_ALL_COV=0 MY_BOOST_ROOT=/mnt/c/boost/boost_1_85_0 MY_CC=g++ +# make gcov -f make_gcov_01_generic.gmk --jobs=8 MY_ALL_COV=0 MY_BOOST_ROOT=/mnt/c/boost/boost_1_85_0 MY_CC=g++ + +all: gcov + +PATH_MAKE = $(CURDIR) +PATH_SRC = $(PATH_MAKE)/../../test +PATH_BIN = $(PATH_MAKE)/bin +PATH_OBJ = $(PATH_MAKE)/obj + +CAT = cat +GNUECHO = echo +LS = ls +MKDIR = mkdir +GCOV = gcov +LCOV = lcov +GENHTML = genhtml +RM = rm + +include make_gcov_02_files.gmk +include make_gcov_03_flags.gmk + +FILES_ALL = $(FILES_PRJ) +FILES_EXE = $(addprefix $(PATH_BIN)/, $(notdir $(addsuffix .exe, $(FILES_ALL)))) + +# ----------------------------------------------------------------------------- +# VPATH definition: VPATH is required for make to find the source files. +# ----------------------------------------------------------------------------- +VPATH := $(sort $(dir $(FILES_ALL))) + + +# ----------------------------------------------------------------------------- +# Executable file: +# ----------------------------------------------------------------------------- + +.PHONY: objects +objects: $(FILES_EXE) + @$(GNUECHO) + @$(GNUECHO) +++ compile source to object then link and execute + + +# ----------------------------------------------------------------------------- +# Main dependency: +# Compile all files and link them. +# Run gcov and get results. +# (See also https://github.com/codecov/example-cpp11-cmake) +# ----------------------------------------------------------------------------- + +.PHONY: gcov +gcov: objects + @$(GNUECHO) + @$(GNUECHO) +++ running gcov + @$(GCOV) $(GCOV_FLAGS) $(addsuffix .cpp,$(FILES_PRJ)) + @$(GNUECHO) + @$(GNUECHO) +++ running lcov + @$(LCOV) $(LCOV_BRANCH) -c --directory obj --output-file coverage_unfiltered.info + @$(LCOV) $(LCOV_BRANCH) --remove coverage_unfiltered.info $(LCOV_REMOVES) --output-file coverage.info + @$(GNUECHO) + @$(GNUECHO) +++ running genhtml + @$(GENHTML) coverage.info $(LCOV_BRANCH) --demangle-cpp --output-directory $(PATH_BIN)/report + +# ----------------------------------------------------------------------------- +# Clean temporary files. +# ----------------------------------------------------------------------------- + +.PHONY: clean +clean: + @$(GNUECHO) + @$(GNUECHO) +++ cleaning output directories + @-$(RM) -rf $(PATH_BIN)* || uname -r + @-$(RM) -rf $(PATH_OBJ)* || uname -r + @-$(RM) -f *.gcov || uname -r + @-$(RM) -f coverage* || uname -r + @$(GNUECHO) + + +# ----------------------------------------------------------------------------- +# Prepare the gcov build. +# ----------------------------------------------------------------------------- + +.PHONY: prepare +prepare: clean + @$(GNUECHO) + @$(GNUECHO) +++ creating output directories + @-$(MKDIR) -p $(PATH_BIN) + @-$(MKDIR) -p $(PATH_OBJ) + @$(GNUECHO) + @$(GNUECHO) +++ print gcov version + @$(GCOV) --version + @$(GNUECHO) + @$(GNUECHO) +++ print include paths + @$(GNUECHO) $(C_INCLUDES) + +include make_gcov_04_rules.gmk diff --git a/test/cover/make_gcov_02_files.gmk b/test/cover/make_gcov_02_files.gmk new file mode 100644 index 0000000..36213b9 --- /dev/null +++ b/test/cover/make_gcov_02_files.gmk @@ -0,0 +1,21 @@ +# ----------------------------------------------------------------------------- +# Copyright Matt Borland 2023 - 2024. +# Copyright Christopher Kormanyos 2023 - 2024. +# Distributed under the Boost Software License, +# Version 1.0. (See accompanying file LICENSE_1_0.txt +# or copy at http://www.boost.org/LICENSE_1_0.txt) +# ----------------------------------------------------------------------------- + +FILES_PRJ := $(basename $(wildcard $(PATH_SRC)/*.cpp)) + +FILES_EXCLUDE := $(PATH_SRC)/concepts_test.cpp \ + $(PATH_SRC)/link_1.cpp \ + $(PATH_SRC)/link_2.cpp \ + $(PATH_SRC)/link_3.cpp \ + $(PATH_SRC)/test_bad_evaluation_method.cpp \ + $(PATH_SRC)/test_explicit_floats.cpp \ + $(PATH_SRC)/test_from_chars.cpp + +FILES_EXCLUDE := $(basename $(FILES_EXCLUDE)) + +FILES_PRJ := $(filter-out $(FILES_EXCLUDE),$(FILES_PRJ)) diff --git a/test/cover/make_gcov_03_flags.gmk b/test/cover/make_gcov_03_flags.gmk new file mode 100644 index 0000000..7605ad9 --- /dev/null +++ b/test/cover/make_gcov_03_flags.gmk @@ -0,0 +1,73 @@ +# ----------------------------------------------------------------------------- +# Copyright Matt Borland 2023. +# Copyright Christopher Kormanyos 2023. +# Distributed under the Boost Software License, +# Version 1.0. (See accompanying file LICENSE_1_0.txt +# or copy at http://www.boost.org/LICENSE_1_0.txt) +# ----------------------------------------------------------------------------- + +CC = g++ +STD = c++20 +ALL_COV = 0 + +ifneq ($(MY_BOOST_ROOT),) +BOOST_ROOT_FOR_GCOV := $(MY_BOOST_ROOT) +endif + +ifneq ($(MY_CC),) +CC := $(MY_CC) +endif + +ifneq ($(MY_STD),) +STD := $(MY_STD) +endif + +ifneq ($(MY_ALL_COV),) +ALL_COV := $(MY_ALL_COV) +endif + +CXXFLAGS = -march=native \ + -mtune=native \ + -O1 \ + -Wextra \ + -Wall \ + -fno-inline-functions \ + -fprofile-arcs \ + -ftest-coverage + +C_DEFINES = + +C_INCLUDES = $(PATH_SRC) \ + $(PATH_SRC)/../include \ + $(BOOST_ROOT_FOR_GCOV) + +C_DEFINES :=$(addprefix -D,$(C_DEFINES)) +C_INCLUDES :=$(addprefix -I,$(C_INCLUDES)) + +GCOV_FLAGS = --object-directory obj \ + --demangled-names + + +# ----------------------------------------------------------------------------- +# All gcov flags: The GCOV_FLAGS below are equivalent to -abcfu +# ----------------------------------------------------------------------------- + +ifneq ($(ALL_COV),0) +GCOV_FLAGS := $(GCOV_FLAGS) \ + --all-blocks \ + --branch-counts \ + --branch-probabilities \ + --function-summaries \ + --unconditional-branches +endif + +LCOV_BRANCH = + +ifneq ($(ALL_COV),0) +LCOV_BRANCH := --rc lcov_branch_coverage=1 +endif + +LCOV_REMOVES = '*/test/mini_to_chars.hpp' \ + '*$(MY_BOOST_ROOT)*' \ + '*/boost-root/*' \ + '/usr/*' diff --git a/test/cover/make_gcov_04_rules.gmk b/test/cover/make_gcov_04_rules.gmk new file mode 100644 index 0000000..05dc73a --- /dev/null +++ b/test/cover/make_gcov_04_rules.gmk @@ -0,0 +1,22 @@ +# ----------------------------------------------------------------------------- +# Copyright Matt Borland 2023. +# Copyright Christopher Kormanyos 2023. +# Distributed under the Boost Software License, +# Version 1.0. (See accompanying file LICENSE_1_0.txt +# or copy at http://www.boost.org/LICENSE_1_0.txt) +# ----------------------------------------------------------------------------- + +# ----------------------------------------------------------------------------- +# special flags (on pattern rule) for compilation of files needing threads +# Note: Each file with threads must be specifically, manually listed here. +# Note: TBD: We can/will use a similar method for libquadmath needs. +# ----------------------------------------------------------------------------- +$(PATH_BIN)/test_frexp_ldexp.exe : $(CXXFLAGS) += -pthread -lpthread + + +# ----------------------------------------------------------------------------- +# pattern rule for compilation of cpp-files +# ----------------------------------------------------------------------------- +$(PATH_BIN)/%.exe : %.cpp + @-$(GNUECHO) +++ compile and link and execute: $(notdir $<) to $(notdir $(PATH_BIN)/$(basename $(@F)).exe) + @-$(CC) $(CXXFLAGS) -x c++ -c $(C_INCLUDES) $(C_DEFINES) $< -o $(PATH_OBJ)/$(basename $(@F)).o && $(CC) $(CXXFLAGS) $(PATH_OBJ)/$(basename $(@F)).o -o $(PATH_BIN)/$(basename $(@F)).exe && $(PATH_BIN)/$(basename $(@F)).exe From fdae13a22c86b65ab939e1fbe254d295de5681da Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 8 Oct 2024 16:09:07 -0400 Subject: [PATCH 015/107] Add github actions CI --- .github/workflows/ci.yml | 798 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 798 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..ca1434e --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,798 @@ +# Copyright 2021-2022 Andrey Semashev +# Copyright 2023 Matt Borland +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) + +name: CI + +on: + pull_request: + push: + branches: + - master + - develop + - feature/** + +concurrency: + group: ${{format('{0}:{1}', github.repository, github.ref)}} + cancel-in-progress: true + +env: + GIT_FETCH_JOBS: 8 + NET_RETRY_COUNT: 5 + DEFAULT_BUILD_VARIANT: debug,release + ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true + +jobs: + posix: + defaults: + run: + shell: bash + + strategy: + fail-fast: false + matrix: + include: + - toolset: gcc-7 + cxxstd: "03,11,14,17" + address_model: 32,64 + os: ubuntu-latest + container: ubuntu:18.04 + install: + - g++-7-multilib + - toolset: gcc-8 + cxxstd: "03,11,14,17,2a" + address_model: 32,64 + os: ubuntu-latest + container: ubuntu:18.04 + install: + - g++-8-multilib + - toolset: gcc-9 + cxxstd: "03,11,14,17,2a" + address_model: 32,64 + os: ubuntu-20.04 + install: + - g++-9-multilib + - toolset: gcc-9 + cxxstd: "03-gnu,11-gnu,14-gnu,17-gnu,2a-gnu" + address_model: 32,64 + os: ubuntu-20.04 + install: + - g++-9-multilib + - toolset: gcc-10 + cxxstd: "03,11,14,17,20" + address_model: 32,64 + os: ubuntu-20.04 + install: + - g++-10-multilib + - toolset: gcc-11 + cxxstd: "03,11,14,17,20,23" + address_model: 32,64 + os: ubuntu-22.04 + install: + - g++-11-multilib + - toolset: gcc-12 + cxxstd: "03,11,14,17,20,23" + address_model: 32,64 + os: ubuntu-22.04 + install: + - g++-12-multilib + # Disabled for now. 22.04 dropped support and 24.04 has internal errors + #- toolset: gcc-13 + # cxxstd: "03,11,14,17,20,23" + # address_model: 32,64 + # os: ubuntu-24.04 + # install: + # - g++-13-multilib + # cxxflags: -Wno-uninitialized + - toolset: gcc-12 + cxxstd: "03-gnu,11-gnu,14-gnu,17-gnu,20-gnu,23-gnu" + address_model: "32" + os: ubuntu-22.04 + install: + - g++-12-multilib + - toolset: gcc-12 + cxxstd: "03-gnu,11-gnu,14-gnu,17-gnu,20-gnu,23-gnu" + address_model: "64" + os: ubuntu-22.04 + install: + - g++-12-multilib + - name: 32-bit UBSAN + toolset: gcc-12 + cxxstd: "03,11,14,17,20,23" + address_model: "32" + ubsan: 1 + os: ubuntu-22.04 + install: + - g++-12-multilib + - name: 64-bit UBSAN + toolset: gcc-12 + cxxstd: "03,11,14,17,20,23" + address_model: "64" + ubsan: 1 + os: ubuntu-22.04 + install: + - g++-12-multilib + + # Linux, clang + - toolset: clang + compiler: clang++-6.0 + cxxstd: "03,11,14,17" + os: ubuntu-latest + container: ubuntu:18.04 + install: + - clang-6.0 + - toolset: clang + compiler: clang++-7 + cxxstd: "03,11,14,17" + os: ubuntu-latest + container: ubuntu:18.04 + install: + - clang-7 + # Note: clang-8 does not fully support C++20, so it is not compatible with libstdc++-8 in this mode + - toolset: clang + compiler: clang++-8 + cxxstd: "03,11,14,17,2a" + os: ubuntu-latest + container: ubuntu:18.04 + install: + - clang-8 + - g++-7 + gcc_toolchain: 7 + - toolset: clang + compiler: clang++-9 + cxxstd: "03,11,14,17,2a" + os: ubuntu-20.04 + install: + - clang-9 + - toolset: clang + compiler: clang++-10 + cxxstd: "03,11,14,17,20" + os: ubuntu-20.04 + install: + - clang-10 + - toolset: clang + compiler: clang++-11 + cxxstd: "03,11,14,17" + os: ubuntu-22.04 + install: + - clang-11 + - toolset: clang + compiler: clang++-12 + cxxstd: "03,11,14,17" + os: ubuntu-22.04 + install: + - clang-12 + - toolset: clang + compiler: clang++-13 + cxxstd: "03,11,14,17" + os: ubuntu-22.04 + install: + - clang-13 + - toolset: clang + compiler: clang++-14 + cxxstd: "03,11,14,17" + os: ubuntu-22.04 + install: + - clang-14 + - toolset: clang + compiler: clang++-14 + cxxstd: "03-gnu,11-gnu,14-gnu,17-gnu" + os: ubuntu-22.04 + install: + - clang-14 + - toolset: clang + compiler: clang++-15 + cxxstd: "03,11,14,17,20" + os: ubuntu-22.04 + install: + - clang-15 + sources: + - "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-15 main" + source_keys: + - "https://apt.llvm.org/llvm-snapshot.gpg.key" + - toolset: clang + compiler: clang++-15 + cxxstd: "03,11,14,17,20,2b" + os: ubuntu-22.04 + install: + - clang-15 + - libc++-15-dev + - libc++abi-15-dev + sources: + - "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-15 main" + source_keys: + - "https://apt.llvm.org/llvm-snapshot.gpg.key" + cxxflags: -stdlib=libc++ + linkflags: -stdlib=libc++ + - toolset: clang + compiler: clang++-16 + cxxstd: "03,11,14,17,20,2b" + os: ubuntu-22.04 + install: + - clang-16 + sources: + - "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-16 main" + source_keys: + - "https://apt.llvm.org/llvm-snapshot.gpg.key" + - toolset: clang + compiler: clang++-17 + cxxstd: "03,11,14,17,20,2b" + os: ubuntu-22.04 + install: + - clang-17 + sources: + - "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-17 main" + source_keys: + - "https://apt.llvm.org/llvm-snapshot.gpg.key" + - name: UBSAN + toolset: clang + compiler: clang++-14 + cxxstd: "03,11,14,17,20,2b" + cxxflags: -stdlib=libc++ + linkflags: -stdlib=libc++ + ubsan: 1 + os: ubuntu-22.04 + install: + - clang-14 + - libc++-14-dev + - libc++abi-14-dev + + - toolset: clang + cxxstd: "03,11,14,17,20,2b" + os: macos-12 + - toolset: clang + cxxstd: "03,11,14,17,20,2b" + os: macos-13 + - toolset: clang + cxxstd: "03,11,14,17,20,2b" + os: macos-14 + + timeout-minutes: 180 + runs-on: ${{matrix.os}} + container: ${{matrix.container}} + + steps: + - name: Setup environment + run: | + if [ -f "/etc/debian_version" ] + then + echo "DEBIAN_FRONTEND=noninteractive" >> $GITHUB_ENV + export DEBIAN_FRONTEND=noninteractive + fi + if [ -n "${{matrix.container}}" ] + then + echo "GHA_CONTAINER=${{matrix.container}}" >> $GITHUB_ENV + if [ -f "/etc/debian_version" ] + then + apt-get -o Acquire::Retries=$NET_RETRY_COUNT update + if [ "$(apt-cache search "^python-is-python3$" | wc -l)" -ne 0 ] + then + PYTHON_PACKAGE="python-is-python3" + else + PYTHON_PACKAGE="python" + fi + apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y sudo software-properties-common tzdata wget curl apt-transport-https ca-certificates make build-essential g++ $PYTHON_PACKAGE python3 perl git cmake + fi + fi + git config --global pack.threads 0 + - uses: actions/checkout@v3 + + - name: Install packages + if: matrix.install + run: | + declare -a SOURCE_KEYS SOURCES + if [ -n "${{join(matrix.source_keys, ' ')}}" ] + then + SOURCE_KEYS=("${{join(matrix.source_keys, '" "')}}") + fi + if [ -n "${{join(matrix.sources, ' ')}}" ] + then + SOURCES=("${{join(matrix.sources, '" "')}}") + fi + for key in "${SOURCE_KEYS[@]}" + do + for i in {1..$NET_RETRY_COUNT} + do + echo "Adding key: $key" + wget -O - "$key" | sudo apt-key add - && break || sleep 2 + done + done + if [ ${#SOURCES[@]} -gt 0 ] + then + APT_ADD_REPO_COMMON_ARGS=("-y") + APT_ADD_REPO_SUPPORTED_ARGS="$(apt-add-repository --help | perl -ne 'if (/^\s*-n/) { print "n"; } elsif (/^\s*-P/) { print "P"; } elsif (/^\s*-S/) { print "S"; } elsif (/^\s*-U/) { print "U"; }')" + if [ -n "$APT_ADD_REPO_SUPPORTED_ARGS" -a -z "${APT_ADD_REPO_SUPPORTED_ARGS##*n*}" ] + then + APT_ADD_REPO_COMMON_ARGS+=("-n") + fi + APT_ADD_REPO_HAS_SOURCE_ARGS="$([ -n "$APT_ADD_REPO_SUPPORTED_ARGS" -a -z "${APT_ADD_REPO_SUPPORTED_ARGS##*P*}" -a -z "${APT_ADD_REPO_SUPPORTED_ARGS##*S*}" -a -z "${APT_ADD_REPO_SUPPORTED_ARGS##*U*}" ] && echo 1 || echo 0)" + for source in "${SOURCES[@]}" + do + for i in {1..$NET_RETRY_COUNT} + do + APT_ADD_REPO_ARGS=("${APT_ADD_REPO_COMMON_ARGS[@]}") + if [ $APT_ADD_REPO_HAS_SOURCE_ARGS -ne 0 ] + then + case "$source" in + "ppa:"*) + APT_ADD_REPO_ARGS+=("-P") + ;; + "deb "*) + APT_ADD_REPO_ARGS+=("-S") + ;; + *) + APT_ADD_REPO_ARGS+=("-U") + ;; + esac + fi + APT_ADD_REPO_ARGS+=("$source") + echo "apt-add-repository ${APT_ADD_REPO_ARGS[@]}" + sudo -E apt-add-repository "${APT_ADD_REPO_ARGS[@]}" && break || sleep 2 + done + done + fi + sudo apt-get -o Acquire::Retries=$NET_RETRY_COUNT update + sudo apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y ${{join(matrix.install, ' ')}} locales + sudo locale-gen de_DE.UTF-8 + sudo update-locale + - name: Setup GCC Toolchain + if: matrix.gcc_toolchain + run: | + GCC_TOOLCHAIN_ROOT="$HOME/gcc-toolchain" + echo "GCC_TOOLCHAIN_ROOT=\"$GCC_TOOLCHAIN_ROOT\"" >> $GITHUB_ENV + MULTIARCH_TRIPLET="$(dpkg-architecture -qDEB_HOST_MULTIARCH)" + mkdir -p "$GCC_TOOLCHAIN_ROOT" + ln -s /usr/include "$GCC_TOOLCHAIN_ROOT/include" + ln -s /usr/bin "$GCC_TOOLCHAIN_ROOT/bin" + mkdir -p "$GCC_TOOLCHAIN_ROOT/lib/gcc/$MULTIARCH_TRIPLET" + ln -s "/usr/lib/gcc/$MULTIARCH_TRIPLET/${{matrix.gcc_toolchain}}" "$GCC_TOOLCHAIN_ROOT/lib/gcc/$MULTIARCH_TRIPLET/${{matrix.gcc_toolchain}}" + - name: Setup Boost + run: | + echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY + LIBRARY=${GITHUB_REPOSITORY#*/} + echo LIBRARY: $LIBRARY + echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV + echo GITHUB_BASE_REF: $GITHUB_BASE_REF + echo GITHUB_REF: $GITHUB_REF + REF=${GITHUB_BASE_REF:-$GITHUB_REF} + REF=${REF#refs/heads/} + echo REF: $REF + BOOST_BRANCH=develop && [ "$REF" = "master" ] && BOOST_BRANCH=master || true + echo BOOST_BRANCH: $BOOST_BRANCH + BUILD_JOBS=$((nproc || sysctl -n hw.ncpu) 2> /dev/null) + echo "BUILD_JOBS=$BUILD_JOBS" >> $GITHUB_ENV + echo "CMAKE_BUILD_PARALLEL_LEVEL=$BUILD_JOBS" >> $GITHUB_ENV + DEPINST_ARGS=() + GIT_VERSION="$(git --version | sed -e 's/git version //')" + GIT_HAS_JOBS=1 + if [ -f "/etc/debian_version" ] + then + if $(dpkg --compare-versions "$GIT_VERSION" lt 2.8.0) + then + GIT_HAS_JOBS=0 + fi + else + declare -a GIT_VER=(${GIT_VERSION//./ }) + declare -a GIT_MIN_VER=(2 8 0) + for ((i=0; i<${#GIT_VER[@]}; i++)) + do + if [ -z "${GIT_MIN_VER[i]}" ] + then + GIT_MIN_VER[i]=0 + fi + if [ "${GIT_VER[i]}" -lt "${GIT_MIN_VER[i]}" ] + then + GIT_HAS_JOBS=0 + break + fi + done + fi + if [ "$GIT_HAS_JOBS" -ne 0 ] + then + DEPINST_ARGS+=("--git_args" "--jobs $GIT_FETCH_JOBS") + fi + cd .. + git clone -b "$BOOST_BRANCH" --depth 1 "https://github.com/boostorg/boost.git" "boost-root" + cd boost-root + mkdir -p libs/$LIBRARY + cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY + git submodule update --init tools/boostdep + DEPINST_ARGS+=("$LIBRARY") + python tools/boostdep/depinst/depinst.py "${DEPINST_ARGS[@]}" + if [ -z "${{matrix.cmake_tests}}" ] + then + ./bootstrap.sh + ./b2 headers + if [ -n "${{matrix.compiler}}" -o -n "$GCC_TOOLCHAIN_ROOT" ] + then + echo -n "using ${{matrix.toolset}} : : ${{matrix.compiler}}" > ~/user-config.jam + if [ -n "$GCC_TOOLCHAIN_ROOT" ] + then + echo -n " : \"--gcc-toolchain=$GCC_TOOLCHAIN_ROOT\" \"--gcc-toolchain=$GCC_TOOLCHAIN_ROOT\"" >> ~/user-config.jam + fi + echo " ;" >> ~/user-config.jam + fi + fi + - name: Run tests + if: matrix.cmake_tests == '' + run: | + cd ../boost-root + B2_ARGS=("-j" "$BUILD_JOBS" "toolset=${{matrix.toolset}}" "cxxstd=${{matrix.cxxstd}}" "link=static,shared") + if [ -n "${{matrix.build_variant}}" ] + then + B2_ARGS+=("variant=${{matrix.build_variant}}") + else + B2_ARGS+=("variant=$DEFAULT_BUILD_VARIANT") + fi + if [ -n "${{matrix.threading}}" ] + then + B2_ARGS+=("threading=${{matrix.threading}}") + fi + if [ -n "${{matrix.ubsan}}" ] + then + export UBSAN_OPTIONS="print_stacktrace=1" + B2_ARGS+=("cxxflags=-fsanitize=undefined -fno-sanitize-recover=undefined" "linkflags=-fsanitize=undefined -fuse-ld=gold" "define=UBSAN=1" "debug-symbols=on" "visibility=global") + fi + if [ -n "${{matrix.cxxflags}}" ] + then + B2_ARGS+=("cxxflags=${{matrix.cxxflags}}") + fi + if [ -n "${{matrix.linkflags}}" ] + then + B2_ARGS+=("linkflags=${{matrix.linkflags}}") + fi + if [ -n "${{matrix.address_model}}" ] + then + B2_ARGS+=("address-model=${{matrix.address_model}}") + fi + B2_ARGS+=("libs/$LIBRARY/test") + ./b2 "${B2_ARGS[@]}" cxxflags="-Wall -Wextra -Werror" + + windows: + strategy: + fail-fast: false + matrix: + include: + - toolset: msvc-14.2 + cxxstd: "14,17,20,latest" + addrmd: "32" + os: windows-2019 + # B2 does not work with MSVC 17.10. Once it's updated we can re-enable these tests + # Still covered in drone + #- toolset: msvc-14.3 + # cxxstd: "14,17,20,latest" + # addrmd: "32" + # os: windows-2022 + - toolset: msvc-14.2 + cxxstd: "14,17,20,latest" + addrmd: "64" + os: windows-2019 + #- toolset: msvc-14.3 + # cxxstd: "14,17,20,latest" + # addrmd: "64" + # os: windows-2022 + #- toolset: clang-win + # cxxstd: "14,17,latest" + # addrmd: "32" + # os: windows-2022 + #- toolset: clang-win + # cxxstd: "14,17,latest" + # addrmd: "64" + # os: windows-2022 + - toolset: gcc + cxxstd: "03,11,14,17,2a" + addrmd: "64" + os: windows-2019 + + runs-on: ${{matrix.os}} + + steps: + - uses: actions/checkout@v3 + + - name: Setup Boost + shell: cmd + run: | + echo GITHUB_REPOSITORY: %GITHUB_REPOSITORY% + for /f %%i in ("%GITHUB_REPOSITORY%") do set LIBRARY=%%~nxi + echo LIBRARY: %LIBRARY% + echo LIBRARY=%LIBRARY%>>%GITHUB_ENV% + echo GITHUB_BASE_REF: %GITHUB_BASE_REF% + echo GITHUB_REF: %GITHUB_REF% + if "%GITHUB_BASE_REF%" == "" set GITHUB_BASE_REF=%GITHUB_REF% + set BOOST_BRANCH=develop + for /f %%i in ("%GITHUB_BASE_REF%") do if "%%~nxi" == "master" set BOOST_BRANCH=master + echo BOOST_BRANCH: %BOOST_BRANCH% + cd .. + git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root + cd boost-root + xcopy /s /e /q %GITHUB_WORKSPACE% libs\%LIBRARY%\ + git submodule update --init tools/boostdep + python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" %LIBRARY% + cmd /c bootstrap + b2 -d0 headers + + - name: Run tests + shell: cmd + run: | + cd ../boost-root + b2 -j3 libs/%LIBRARY%/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} address-model=${{matrix.addrmd}} variant=debug,release link=static,shared embed-manifest-via=linker + + posix-cmake-subdir: + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-20.04 + - os: ubuntu-22.04 + - os: macos-12 + - os: macos-13 + - os: macos-14 + + runs-on: ${{matrix.os}} + + steps: + - uses: actions/checkout@v3 + + - name: Install packages + if: matrix.install + run: sudo apt install ${{matrix.install}} + + - name: Setup Boost + run: | + echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY + LIBRARY=${GITHUB_REPOSITORY#*/} + echo LIBRARY: $LIBRARY + echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV + echo GITHUB_BASE_REF: $GITHUB_BASE_REF + echo GITHUB_REF: $GITHUB_REF + REF=${GITHUB_BASE_REF:-$GITHUB_REF} + REF=${REF#refs/heads/} + echo REF: $REF + BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true + echo BOOST_BRANCH: $BOOST_BRANCH + cd .. + git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root + cd boost-root + mkdir -p libs/$LIBRARY + cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY + git submodule update --init tools/boostdep + python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY + + - name: Use library with add_subdirectory + run: | + cd ../boost-root/libs/$LIBRARY/test/cmake_subdir_test + mkdir __build__ && cd __build__ + cmake .. + cmake --build . + ctest --output-on-failure --no-tests=error + + posix-cmake-install: + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-20.04 + - os: ubuntu-22.04 + - os: macos-12 + - os: macos-13 + - os: macos-14 + + runs-on: ${{matrix.os}} + + steps: + - uses: actions/checkout@v3 + + - name: Install packages + if: matrix.install + run: sudo apt install ${{matrix.install}} + + - name: Setup Boost + run: | + echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY + LIBRARY=${GITHUB_REPOSITORY#*/} + echo LIBRARY: $LIBRARY + echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV + echo GITHUB_BASE_REF: $GITHUB_BASE_REF + echo GITHUB_REF: $GITHUB_REF + REF=${GITHUB_BASE_REF:-$GITHUB_REF} + REF=${REF#refs/heads/} + echo REF: $REF + BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true + echo BOOST_BRANCH: $BOOST_BRANCH + cd .. + git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root + cd boost-root + mkdir -p libs/$LIBRARY + cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY + git submodule update --init tools/boostdep + python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY + + - name: Configure + run: | + cd ../boost-root + mkdir __build__ && cd __build__ + cmake -DBOOST_INCLUDE_LIBRARIES=$LIBRARY -DCMAKE_INSTALL_PREFIX=~/.local .. + + - name: Install + run: | + cd ../boost-root/__build__ + cmake --build . --target install + + - name: Use the installed library + run: | + cd ../boost-root/libs/$LIBRARY/test/cmake_install_test && mkdir __build__ && cd __build__ + cmake -DCMAKE_INSTALL_PREFIX=~/.local .. + cmake --build . + ctest --output-on-failure --no-tests=error + + posix-cmake-test: + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-20.04 + - os: ubuntu-22.04 + - os: macos-12 + - os: macos-13 + - os: macos-14 + + runs-on: ${{matrix.os}} + + steps: + - uses: actions/checkout@v3 + + - name: Install packages + if: matrix.install + run: sudo apt install ${{matrix.install}} + + - name: Setup Boost + run: | + echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY + LIBRARY=${GITHUB_REPOSITORY#*/} + echo LIBRARY: $LIBRARY + echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV + echo GITHUB_BASE_REF: $GITHUB_BASE_REF + echo GITHUB_REF: $GITHUB_REF + REF=${GITHUB_BASE_REF:-$GITHUB_REF} + REF=${REF#refs/heads/} + echo REF: $REF + BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true + echo BOOST_BRANCH: $BOOST_BRANCH + cd .. + git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root + cd boost-root + mkdir -p libs/$LIBRARY + cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY + git submodule update --init tools/boostdep + python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY + + - name: Configure + run: | + cd ../boost-root + mkdir __build__ && cd __build__ + cmake -DBOOST_INCLUDE_LIBRARIES=$LIBRARY -DBUILD_TESTING=ON .. + + - name: Build tests + run: | + cd ../boost-root/__build__ + cmake --build . --target tests + + - name: Run tests + run: | + cd ../boost-root/__build__ + ctest --output-on-failure --no-tests=error + + MSYS2: + defaults: + run: + shell: msys2 {0} + strategy: + fail-fast: false + matrix: + include: + - { sys: MINGW32, compiler: gcc, cxxstd: '03,11,17,20' } + - { sys: MINGW64, compiler: gcc, cxxstd: '03,11,17,20' } + + runs-on: windows-latest + + steps: + - uses: actions/checkout@v3 + + - name: Setup MSYS2 environment + uses: msys2/setup-msys2@v2 + with: + msystem: ${{matrix.sys}} + update: true + install: git python + pacboy: gcc:p cmake:p ninja:p + + - name: Fetch Boost.CI + uses: actions/checkout@v3 + with: + repository: boostorg/boost-ci + ref: master + path: boost-ci-cloned + - name: Get CI scripts folder + run: | + # Copy ci folder if not testing Boost.CI + [[ "$GITHUB_REPOSITORY" =~ "boost-ci" ]] || cp -r boost-ci-cloned/ci . + rm -rf boost-ci-cloned + + - name: Setup Boost + env: + B2_COMPILER: ${{matrix.compiler}} + B2_CXXSTD: ${{matrix.cxxstd}} + B2_SANITIZE: ${{matrix.sanitize}} + B2_STDLIB: ${{matrix.stdlib}} + run: ci/github/install.sh + + - name: Run tests + run: ci/build.sh + + intel: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + compiler: [ intel ] + standard: [ c++20 ] + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: '0' + + - name: Intel Apt repository + timeout-minutes: 1 + run: | + wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB + sudo apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB + rm GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB + echo "deb https://apt.repos.intel.com/oneapi all main" | sudo tee /etc/apt/sources.list.d/oneAPI.list + sudo apt-get update + - name: Install Intel oneAPI compilers + timeout-minutes: 5 + run: sudo apt-get install -y intel-oneapi-compiler-fortran intel-oneapi-compiler-dpcpp-cpp + + - name: Setup Intel oneAPI environment + run: | + source /opt/intel/oneapi/setvars.sh + printenv >> $GITHUB_ENV + + - name: Setup Boost + run: | + echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY + LIBRARY=${GITHUB_REPOSITORY#*/} + echo LIBRARY: $LIBRARY + echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV + echo GITHUB_BASE_REF: $GITHUB_BASE_REF + echo GITHUB_REF: $GITHUB_REF + REF=${GITHUB_BASE_REF:-$GITHUB_REF} + REF=${REF#refs/heads/} + echo REF: $REF + BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true + echo BOOST_BRANCH: $BOOST_BRANCH + cd .. + git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root + cd boost-root + mkdir -p libs/$LIBRARY + cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY + git submodule update --init tools/boostdep + python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY + + - name: Configure + run: | + cd ../boost-root + mkdir __build__ && cd __build__ + cmake -DCMAKE_C_COMPILER=icx -DCMAKE_CXX_COMPILER=icpx -DBOOST_INCLUDE_LIBRARIES=$LIBRARY -DBUILD_TESTING=ON .. + + - name: Build tests + run: | + cd ../boost-root/__build__ + cmake --build . --target tests + + - name: Run tests + run: | + cd ../boost-root/__build__ + ctest --output-on-failure --no-tests=error From 2c57a4a8ccfaae1da19ae85af1eeefea0fc7942d Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 8 Oct 2024 16:14:16 -0400 Subject: [PATCH 016/107] Add fuzzing --- .github/workflows/fuzz.yml | 289 +++++++++++++++++++++++++++++++++++++ fuzzing/.gitignore | 7 + fuzzing/Jamfile | 66 +++++++++ fuzzing/fuzz_md5.cpp | 26 ++++ 4 files changed, 388 insertions(+) create mode 100644 .github/workflows/fuzz.yml create mode 100644 fuzzing/.gitignore create mode 100644 fuzzing/Jamfile create mode 100644 fuzzing/fuzz_md5.cpp diff --git a/.github/workflows/fuzz.yml b/.github/workflows/fuzz.yml new file mode 100644 index 0000000..4487018 --- /dev/null +++ b/.github/workflows/fuzz.yml @@ -0,0 +1,289 @@ +# Copyright 2021-2022 Andrey Semashev +# Copyright 2024 Matt Borland +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) + +name: Fuzz + +on: + pull_request: + push: + branches: + - master + - develop + - feature/** + +env: + GIT_FETCH_JOBS: 8 + NET_RETRY_COUNT: 5 + DEFAULT_BUILD_VARIANT: debug,release + ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true + +jobs: + posix: + defaults: + run: + shell: bash + + strategy: + fail-fast: false + matrix: + include: + + # Linux, clang + # https://llvm.org/docs/LibFuzzer.html#fuzzer-usage + - toolset: clang + compiler: clang++-12 + cxxstd: "14,17,20" + os: ubuntu-22.04 + install: + - clang-12 + - toolset: clang + compiler: clang++-13 + cxxstd: "14,17,20" + os: ubuntu-22.04 + install: + - clang-13 + - toolset: clang + compiler: clang++-14 + cxxstd: "14,17,20" + os: ubuntu-22.04 + install: + - clang-14 + - toolset: clang + compiler: clang++-14 + cxxstd: "14-gnu,17-gnu,20-gnu" + os: ubuntu-22.04 + install: + - clang-14 + - toolset: clang + compiler: clang++-15 + cxxstd: "14,17,20" + os: ubuntu-22.04 + install: + - clang-15 + sources: + - "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-15 main" + source_keys: + - "https://apt.llvm.org/llvm-snapshot.gpg.key" + - toolset: clang + compiler: clang++-16 + cxxstd: "14,17,20" + os: ubuntu-22.04 + install: + - clang-16 + sources: + - "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-16 main" + source_keys: + - "https://apt.llvm.org/llvm-snapshot.gpg.key" + - toolset: clang + compiler: clang++-17 + cxxstd: "14,17,20" + os: ubuntu-22.04 + install: + - clang-17 + sources: + - "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-17 main" + source_keys: + - "https://apt.llvm.org/llvm-snapshot.gpg.key" + + + timeout-minutes: 60 + runs-on: ${{matrix.os}} + container: ${{matrix.container}} + + steps: + - name: Setup environment + run: | + if [ -f "/etc/debian_version" ] + then + echo "DEBIAN_FRONTEND=noninteractive" >> $GITHUB_ENV + export DEBIAN_FRONTEND=noninteractive + fi + if [ -n "${{matrix.container}}" ] + then + echo "GHA_CONTAINER=${{matrix.container}}" >> $GITHUB_ENV + if [ -f "/etc/debian_version" ] + then + apt-get -o Acquire::Retries=$NET_RETRY_COUNT update + if [ "$(apt-cache search "^python-is-python3$" | wc -l)" -ne 0 ] + then + PYTHON_PACKAGE="python-is-python3" + else + PYTHON_PACKAGE="python" + fi + apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y sudo software-properties-common tzdata wget curl apt-transport-https ca-certificates make build-essential g++ $PYTHON_PACKAGE python3 perl git cmake + fi + fi + git config --global pack.threads 0 + - uses: actions/checkout@v4 + + - name: Install packages + if: matrix.install + run: | + declare -a SOURCE_KEYS SOURCES + if [ -n "${{join(matrix.source_keys, ' ')}}" ] + then + SOURCE_KEYS=("${{join(matrix.source_keys, '" "')}}") + fi + if [ -n "${{join(matrix.sources, ' ')}}" ] + then + SOURCES=("${{join(matrix.sources, '" "')}}") + fi + for key in "${SOURCE_KEYS[@]}" + do + for i in {1..$NET_RETRY_COUNT} + do + echo "Adding key: $key" + wget -O - "$key" | sudo apt-key add - && break || sleep 2 + done + done + if [ ${#SOURCES[@]} -gt 0 ] + then + APT_ADD_REPO_COMMON_ARGS=("-y") + APT_ADD_REPO_SUPPORTED_ARGS="$(apt-add-repository --help | perl -ne 'if (/^\s*-n/) { print "n"; } elsif (/^\s*-P/) { print "P"; } elsif (/^\s*-S/) { print "S"; } elsif (/^\s*-U/) { print "U"; }')" + if [ -n "$APT_ADD_REPO_SUPPORTED_ARGS" -a -z "${APT_ADD_REPO_SUPPORTED_ARGS##*n*}" ] + then + APT_ADD_REPO_COMMON_ARGS+=("-n") + fi + APT_ADD_REPO_HAS_SOURCE_ARGS="$([ -n "$APT_ADD_REPO_SUPPORTED_ARGS" -a -z "${APT_ADD_REPO_SUPPORTED_ARGS##*P*}" -a -z "${APT_ADD_REPO_SUPPORTED_ARGS##*S*}" -a -z "${APT_ADD_REPO_SUPPORTED_ARGS##*U*}" ] && echo 1 || echo 0)" + for source in "${SOURCES[@]}" + do + for i in {1..$NET_RETRY_COUNT} + do + APT_ADD_REPO_ARGS=("${APT_ADD_REPO_COMMON_ARGS[@]}") + if [ $APT_ADD_REPO_HAS_SOURCE_ARGS -ne 0 ] + then + case "$source" in + "ppa:"*) + APT_ADD_REPO_ARGS+=("-P") + ;; + "deb "*) + APT_ADD_REPO_ARGS+=("-S") + ;; + *) + APT_ADD_REPO_ARGS+=("-U") + ;; + esac + fi + APT_ADD_REPO_ARGS+=("$source") + echo "apt-add-repository ${APT_ADD_REPO_ARGS[@]}" + sudo -E apt-add-repository "${APT_ADD_REPO_ARGS[@]}" && break || sleep 2 + done + done + fi + sudo apt-get -o Acquire::Retries=$NET_RETRY_COUNT update + sudo apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y ${{join(matrix.install, ' ')}} locales + sudo locale-gen de_DE.UTF-8 + sudo update-locale + - name: Setup GCC Toolchain + if: matrix.gcc_toolchain + run: | + GCC_TOOLCHAIN_ROOT="$HOME/gcc-toolchain" + echo "GCC_TOOLCHAIN_ROOT=\"$GCC_TOOLCHAIN_ROOT\"" >> $GITHUB_ENV + MULTIARCH_TRIPLET="$(dpkg-architecture -qDEB_HOST_MULTIARCH)" + mkdir -p "$GCC_TOOLCHAIN_ROOT" + ln -s /usr/include "$GCC_TOOLCHAIN_ROOT/include" + ln -s /usr/bin "$GCC_TOOLCHAIN_ROOT/bin" + mkdir -p "$GCC_TOOLCHAIN_ROOT/lib/gcc/$MULTIARCH_TRIPLET" + ln -s "/usr/lib/gcc/$MULTIARCH_TRIPLET/${{matrix.gcc_toolchain}}" "$GCC_TOOLCHAIN_ROOT/lib/gcc/$MULTIARCH_TRIPLET/${{matrix.gcc_toolchain}}" + - name: Setup Boost + run: | + echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY + LIBRARY=${GITHUB_REPOSITORY#*/} + echo LIBRARY: $LIBRARY + echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV + echo GITHUB_BASE_REF: $GITHUB_BASE_REF + echo GITHUB_REF: $GITHUB_REF + REF=${GITHUB_BASE_REF:-$GITHUB_REF} + REF=${REF#refs/heads/} + echo REF: $REF + BOOST_BRANCH=develop && [ "$REF" = "master" ] && BOOST_BRANCH=master || true + echo BOOST_BRANCH: $BOOST_BRANCH + BUILD_JOBS=$((nproc || sysctl -n hw.ncpu) 2> /dev/null) + echo "BUILD_JOBS=$BUILD_JOBS" >> $GITHUB_ENV + echo "CMAKE_BUILD_PARALLEL_LEVEL=$BUILD_JOBS" >> $GITHUB_ENV + DEPINST_ARGS=() + GIT_VERSION="$(git --version | sed -e 's/git version //')" + GIT_HAS_JOBS=1 + if [ -f "/etc/debian_version" ] + then + if $(dpkg --compare-versions "$GIT_VERSION" lt 2.8.0) + then + GIT_HAS_JOBS=0 + fi + else + declare -a GIT_VER=(${GIT_VERSION//./ }) + declare -a GIT_MIN_VER=(2 8 0) + for ((i=0; i<${#GIT_VER[@]}; i++)) + do + if [ -z "${GIT_MIN_VER[i]}" ] + then + GIT_MIN_VER[i]=0 + fi + if [ "${GIT_VER[i]}" -lt "${GIT_MIN_VER[i]}" ] + then + GIT_HAS_JOBS=0 + break + fi + done + fi + if [ "$GIT_HAS_JOBS" -ne 0 ] + then + DEPINST_ARGS+=("--git_args" "--jobs $GIT_FETCH_JOBS") + fi + cd .. + git clone -b "$BOOST_BRANCH" --depth 1 "https://github.com/boostorg/boost.git" "boost-root" + cd boost-root + mkdir -p libs/$LIBRARY + cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY + git submodule update --init tools/boostdep + DEPINST_ARGS+=("$LIBRARY") + python tools/boostdep/depinst/depinst.py "${DEPINST_ARGS[@]}" + if [ -z "${{matrix.cmake_tests}}" ] + then + ./bootstrap.sh + ./b2 headers + if [ -n "${{matrix.compiler}}" -o -n "$GCC_TOOLCHAIN_ROOT" ] + then + echo -n "using ${{matrix.toolset}} : : ${{matrix.compiler}}" > ~/user-config.jam + if [ -n "$GCC_TOOLCHAIN_ROOT" ] + then + echo -n " : \"--gcc-toolchain=$GCC_TOOLCHAIN_ROOT\" \"--gcc-toolchain=$GCC_TOOLCHAIN_ROOT\"" >> ~/user-config.jam + fi + echo " ;" >> ~/user-config.jam + fi + fi + - name: Run tests + if: matrix.cmake_tests == '' + run: | + cd ../boost-root/libs/$LIBRARY/fuzzing + B2_ARGS=("-j" "$BUILD_JOBS" "toolset=${{matrix.toolset}}" "cxxstd=${{matrix.cxxstd}}" "link=static,shared") + if [ -n "${{matrix.build_variant}}" ] + then + B2_ARGS+=("variant=${{matrix.build_variant}}") + else + B2_ARGS+=("variant=$DEFAULT_BUILD_VARIANT") + fi + if [ -n "${{matrix.threading}}" ] + then + B2_ARGS+=("threading=${{matrix.threading}}") + fi + if [ -n "${{matrix.ubsan}}" ] + then + export UBSAN_OPTIONS="print_stacktrace=1" + B2_ARGS+=("cxxflags=-fsanitize=undefined -fno-sanitize-recover=undefined" "linkflags=-fsanitize=undefined -fuse-ld=gold" "define=UBSAN=1" "debug-symbols=on" "visibility=global") + fi + if [ -n "${{matrix.cxxflags}}" ] + then + B2_ARGS+=("cxxflags=${{matrix.cxxflags}}") + fi + if [ -n "${{matrix.linkflags}}" ] + then + B2_ARGS+=("linkflags=${{matrix.linkflags}}") + fi + if [ -n "${{matrix.address_model}}" ] + then + B2_ARGS+=("address-model=${{matrix.address_model}}") + fi + ../../../b2 "${B2_ARGS[@]}" diff --git a/fuzzing/.gitignore b/fuzzing/.gitignore new file mode 100644 index 0000000..3884657 --- /dev/null +++ b/fuzzing/.gitignore @@ -0,0 +1,7 @@ +cmin/ +out/ +oldcorpus/ +seedcorpus/ +corpus.tar +out*/ +fuzz-*.log diff --git a/fuzzing/Jamfile b/fuzzing/Jamfile new file mode 100644 index 0000000..4739898 --- /dev/null +++ b/fuzzing/Jamfile @@ -0,0 +1,66 @@ +# +# Copyright (c) 2019-2023 Ruben Perez Hidalgo (rubenperez038 at gmail dot com) +# Copyright (c) 2024 Matt Borland +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +import common ; +import regex ; + +local all_fuzzers = [ regex.replace-list + [ glob "fuzz_*.cpp" ] : ".cpp" : "" +] ; + +for local fuzzer in $(all_fuzzers) +{ + # These two fuzzers are the most complex ones. The rest are really + # simple, so less time is enough + local fuzz_time = 30 ; + + # Create the output corpus directories + make /tmp/corpus/$(fuzzer) : : common.MkDir ; + make /tmp/mincorpus/$(fuzzer) : : common.MkDir ; + + # Build the fuzzer + exe $(fuzzer) + : + $(fuzzer).cpp + : requirements + on + speed + on + norecover + -fsanitize=fuzzer + -fsanitize=fuzzer + ; + + # Make sure that any old crashes are run without problems + local old_crashes = [ glob-tree-ex old_crashes/$(fuzzer) : * ] ; + if $(old_crashes) + { + run $(fuzzer) + : target-name $(fuzzer)-old-crashes + : input-files [ SORT $(old_crashes) ] + ; + } + + # Run the fuzzer for a short while + run $(fuzzer) + : "seedcorpus/$(fuzzer) -max_total_time=$(fuzz_time)" + : target-name $(fuzzer)-fuzzing + : requirements + /tmp/corpus/$(fuzzer) + ; + + # Minimize the corpus + run $(fuzzer) + : "/tmp/mincorpus/$(fuzzer) /tmp/corpus/$(fuzzer) -merge=1" + : target-name $(fuzzer)-minimize-corpus + : requirements + $(fuzzer)-fuzzing + /tmp/corpus/$(fuzzer) + /tmp/mincorpus/$(fuzzer) + ; +} diff --git a/fuzzing/fuzz_md5.cpp b/fuzzing/fuzz_md5.cpp new file mode 100644 index 0000000..ee70888 --- /dev/null +++ b/fuzzing/fuzz_md5.cpp @@ -0,0 +1,26 @@ +// 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::md5(c_data_str); + } + catch(...) + { + std::cerr << "Error with: " << data << std::endl; + std::terminate(); + } + + return 0; +} From 9634af0e2f63ff47132edd999f53a78088d6d580 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 8 Oct 2024 16:17:46 -0400 Subject: [PATCH 017/107] Add CMake install and subdir testing --- test/Jamfile | 1 + test/cmake_install_test/CMakeLists.txt | 17 ++++++++++++ test/cmake_subdir_test/CMakeLists.txt | 37 ++++++++++++++++++++++++++ test/quick.cpp | 10 +++++++ 4 files changed, 65 insertions(+) create mode 100644 test/cmake_install_test/CMakeLists.txt create mode 100644 test/cmake_subdir_test/CMakeLists.txt create mode 100644 test/quick.cpp diff --git a/test/Jamfile b/test/Jamfile index d0306e4..201cf17 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -41,4 +41,5 @@ project : requirements [ requires cxx14_decltype_auto cxx14_generic_lambdas cxx14_return_type_deduction cxx14_variable_templates cxx14_constexpr ] ; +run quick.cpp ; run test_md5.cpp ; diff --git a/test/cmake_install_test/CMakeLists.txt b/test/cmake_install_test/CMakeLists.txt new file mode 100644 index 0000000..83a2bf0 --- /dev/null +++ b/test/cmake_install_test/CMakeLists.txt @@ -0,0 +1,17 @@ +# Copyright 2018, 2019 Peter Dimov +# Distributed under the Boost Software License, Version 1.0. +# See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt + +cmake_minimum_required(VERSION 3.5...3.16) + +project(cmake_install_test LANGUAGES CXX) + +find_package(boost_quick REQUIRED) + +add_executable(quick ../quick.cpp) +target_link_libraries(quick Boost::quick) + +enable_testing() +add_test(quick quick) + +add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -C $) diff --git a/test/cmake_subdir_test/CMakeLists.txt b/test/cmake_subdir_test/CMakeLists.txt new file mode 100644 index 0000000..0ac83cf --- /dev/null +++ b/test/cmake_subdir_test/CMakeLists.txt @@ -0,0 +1,37 @@ +# Copyright 2018, 2019 Peter Dimov +# Distributed under the Boost Software License, Version 1.0. +# See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt + +cmake_minimum_required(VERSION 3.5...3.20) + +project(cmake_subdir_test LANGUAGES CXX) + +add_subdirectory(../.. boostorg/crypt) + +set(deps + +# Primary dependencies + +assert +config +core + +# Secondary dependencies + +static_assert +throw_exception +) + +foreach(dep IN LISTS deps) + + add_subdirectory(../../../${dep} boostorg/${dep}) + +endforeach() + +add_executable(quick ../quick.cpp) +target_link_libraries(quick Boost::crypt) + +enable_testing() +add_test(quick quick) + +add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -C $) diff --git a/test/quick.cpp b/test/quick.cpp new file mode 100644 index 0000000..ca796b7 --- /dev/null +++ b/test/quick.cpp @@ -0,0 +1,10 @@ +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include + +auto main() -> int +{ + return 0; +} From b82683749f9da54c668513b7d94f75c27ac7939c Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 8 Oct 2024 16:18:20 -0400 Subject: [PATCH 018/107] Add the seed corpus --- fuzzing/seedcorpus/fuzz_md5/md5.txt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 fuzzing/seedcorpus/fuzz_md5/md5.txt diff --git a/fuzzing/seedcorpus/fuzz_md5/md5.txt b/fuzzing/seedcorpus/fuzz_md5/md5.txt new file mode 100644 index 0000000..48e3b98 --- /dev/null +++ b/fuzzing/seedcorpus/fuzz_md5/md5.txt @@ -0,0 +1,18 @@ +"The quick brown fox jumps over the lazy dog" +"The quick brown fox jumps over the lazy dog." +"" +"aB3$x9Yz" +"12345" +"!@#$%^&*()" +"FuzzTest123" +" " +"Lorem ipsum dolor sit amet" +"a" +"9876543210" +"ABCDEFGHIJKLMNOPQRSTUVWXYZ" +"ñÑáéíóúÁÉÍÓÚ" +"\n\r\t" +"0" +"ThisIsAVeryLongStringWithNoSpacesOrPunctuationToTestEdgeCases" +"" +"SELECT * FROM users;" From 392aebcb1eefedbaeeeadb4634e9404b7c997383 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 8 Oct 2024 16:26:03 -0400 Subject: [PATCH 019/107] Fix typo --- test/cmake_install_test/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/cmake_install_test/CMakeLists.txt b/test/cmake_install_test/CMakeLists.txt index 83a2bf0..5cbfe3d 100644 --- a/test/cmake_install_test/CMakeLists.txt +++ b/test/cmake_install_test/CMakeLists.txt @@ -9,7 +9,7 @@ project(cmake_install_test LANGUAGES CXX) find_package(boost_quick REQUIRED) add_executable(quick ../quick.cpp) -target_link_libraries(quick Boost::quick) +target_link_libraries(quick Boost::crypt) enable_testing() add_test(quick quick) From 04e7d07ecc3f39c73e30d4672ad69cb7d668692c Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 8 Oct 2024 16:26:44 -0400 Subject: [PATCH 020/107] Add missing headers --- include/boost/crypt/hash/md5.hpp | 2 ++ include/boost/crypt/utility/bit.hpp | 1 + 2 files changed, 3 insertions(+) diff --git a/include/boost/crypt/hash/md5.hpp b/include/boost/crypt/hash/md5.hpp index 33bf839..0bdad19 100644 --- a/include/boost/crypt/hash/md5.hpp +++ b/include/boost/crypt/hash/md5.hpp @@ -10,7 +10,9 @@ #include #include +#include #include +#include namespace boost { namespace crypt { diff --git a/include/boost/crypt/utility/bit.hpp b/include/boost/crypt/utility/bit.hpp index 36e93de..55fe9dc 100644 --- a/include/boost/crypt/utility/bit.hpp +++ b/include/boost/crypt/utility/bit.hpp @@ -8,6 +8,7 @@ #include #include #include +#include namespace boost { namespace crypt { From d42854f36ec8a26c4aac98a441f9d0991baf4c29 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 8 Oct 2024 16:40:44 -0400 Subject: [PATCH 021/107] Fix testing --- test/cmake_install_test/CMakeLists.txt | 2 +- test/test_md5.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/test/cmake_install_test/CMakeLists.txt b/test/cmake_install_test/CMakeLists.txt index 5cbfe3d..d859726 100644 --- a/test/cmake_install_test/CMakeLists.txt +++ b/test/cmake_install_test/CMakeLists.txt @@ -6,7 +6,7 @@ cmake_minimum_required(VERSION 3.5...3.16) project(cmake_install_test LANGUAGES CXX) -find_package(boost_quick REQUIRED) +find_package(boost_crypt REQUIRED) add_executable(quick ../quick.cpp) target_link_libraries(quick Boost::crypt) diff --git a/test/test_md5.cpp b/test/test_md5.cpp index 83ee3f5..04470d4 100644 --- a/test/test_md5.cpp +++ b/test/test_md5.cpp @@ -74,6 +74,7 @@ void bad_input() int main() { basic_tests(); + string_test(); bad_input(); return boost::report_errors(); From efbe3cea0a0c7d11dba0d71710fa9b003472d685 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 8 Oct 2024 16:44:58 -0400 Subject: [PATCH 022/107] Use std::transform instead of std::copy --- include/boost/crypt/hash/md5.hpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/include/boost/crypt/hash/md5.hpp b/include/boost/crypt/hash/md5.hpp index 0bdad19..0295dcb 100644 --- a/include/boost/crypt/hash/md5.hpp +++ b/include/boost/crypt/hash/md5.hpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -50,7 +51,13 @@ auto md5_preprocess(T begin, T end) -> std::vector { std::vector vec; vec.reserve(static_cast(end - begin)); - std::copy(begin, end, std::back_inserter(vec)); + + // Like std::copy but gives us the correct cast + std::transform(begin, end, std::back_inserter(vec), + [](const auto& element) { + return static_cast(element); + }); + return vec; } @@ -59,7 +66,12 @@ auto md5_preprocess(T begin, std::size_t len) -> std::vector { std::vector vec; vec.reserve(len); - std::copy(begin, begin + len, std::back_inserter(vec)); + + std::transform(begin, begin + len, std::back_inserter(vec), + [](const auto& element) { + return static_cast(element); + }); + return vec; } From 15db237102e936cfe8c06a154bec6d20b2544d13 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 8 Oct 2024 16:45:04 -0400 Subject: [PATCH 023/107] CI fixes --- .github/workflows/ci.yml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ca1434e..66ba35d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -241,7 +241,7 @@ jobs: - toolset: clang cxxstd: "03,11,14,17,20,2b" - os: macos-12 + os: macos-15 - toolset: clang cxxstd: "03,11,14,17,20,2b" os: macos-13 @@ -461,18 +461,18 @@ jobs: os: windows-2019 # B2 does not work with MSVC 17.10. Once it's updated we can re-enable these tests # Still covered in drone - #- toolset: msvc-14.3 - # cxxstd: "14,17,20,latest" - # addrmd: "32" - # os: windows-2022 + - toolset: msvc-14.3 + cxxstd: "14,17,20,latest" + addrmd: "32" + os: windows-2022 - toolset: msvc-14.2 cxxstd: "14,17,20,latest" addrmd: "64" os: windows-2019 - #- toolset: msvc-14.3 - # cxxstd: "14,17,20,latest" - # addrmd: "64" - # os: windows-2022 + - toolset: msvc-14.3 + cxxstd: "14,17,20,latest" + addrmd: "64" + os: windows-2022 #- toolset: clang-win # cxxstd: "14,17,latest" # addrmd: "32" @@ -526,7 +526,7 @@ jobs: include: - os: ubuntu-20.04 - os: ubuntu-22.04 - - os: macos-12 + - os: macos-15 - os: macos-13 - os: macos-14 @@ -575,7 +575,7 @@ jobs: include: - os: ubuntu-20.04 - os: ubuntu-22.04 - - os: macos-12 + - os: macos-15 - os: macos-13 - os: macos-14 @@ -634,7 +634,7 @@ jobs: include: - os: ubuntu-20.04 - os: ubuntu-22.04 - - os: macos-12 + - os: macos-15 - os: macos-13 - os: macos-14 From 3b05377b8e4a5ddd730e7cbb91b045a6c6240e49 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 8 Oct 2024 16:49:34 -0400 Subject: [PATCH 024/107] Add meta file --- meta/libraries.json | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 meta/libraries.json diff --git a/meta/libraries.json b/meta/libraries.json new file mode 100644 index 0000000..b01c225 --- /dev/null +++ b/meta/libraries.json @@ -0,0 +1,17 @@ +{ + "key": "crypt", + "name": "Crypt", + "authors": [ + "Matt Borland", + "Christopher Kormanyos" + ], + "maintainers": [ + "Matt Borland ", + "Christopher Kormanyos " + ], + "description": "A module of cryptographic utilities.", + "category": [ + "Math and numerics" + ], + "cxxstd": "14" +} From 6844616bcba9a5114af90928255ada9ff48545f8 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 8 Oct 2024 16:50:03 -0400 Subject: [PATCH 025/107] Add PPC64LE QEMU run --- .github/workflows/qemu.yml | 206 +++++++++++++++++++++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 .github/workflows/qemu.yml diff --git a/.github/workflows/qemu.yml b/.github/workflows/qemu.yml new file mode 100644 index 0000000..08bbfdc --- /dev/null +++ b/.github/workflows/qemu.yml @@ -0,0 +1,206 @@ +# Copyright 2020-2021 Peter Dimov +# Copyright 2021 Andrey Semashev +# Copyright 2021 Alexander Grund +# Copyright 2022 James E. King III +# Copyright 2024 Matt Borland +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) +--- +name: qemu + +on: + pull_request: + push: + branches: + - master + - develop + - bugfix/** + - feature/** + - fix/** + - pr/** + +env: + GIT_FETCH_JOBS: 8 + NET_RETRY_COUNT: 5 + B2_CI_VERSION: 1 + B2_VARIANT: release + B2_LINK: static + LCOV_BRANCH_COVERAGE: 0 + CODECOV_NAME: Github Actions + ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true + +jobs: + posix: + defaults: + run: + shell: bash + + strategy: + fail-fast: false + matrix: + include: + # multiarch testing + - { name: PPC64LE-GCC, multiarch: yes, + compiler: gcc, cxxstd: '14', os: ubuntu-22.04, ccache: no, distro: alpine, edition: edge, arch: ppc64le } + - { name: PPC64LE-Clang, multiarch: yes, + compiler: clang, cxxstd: '14', os: ubuntu-22.04, ccache: no, distro: alpine, edition: edge, arch: ppc64le } + + + timeout-minutes: 360 + runs-on: ${{matrix.os}} + container: ${{matrix.container}} + env: {B2_USE_CCACHE: 1} + + steps: + - name: Setup environment + run: | + if [ -f "/etc/debian_version" ]; then + echo "DEBIAN_FRONTEND=noninteractive" >> $GITHUB_ENV + export DEBIAN_FRONTEND=noninteractive + fi + if [ -n "${{matrix.container}}" ] && [ -f "/etc/debian_version" ]; then + apt-get -o Acquire::Retries=$NET_RETRY_COUNT update + apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y sudo software-properties-common curl + # Need (newer) git, and the older Ubuntu container may require requesting the key manually using port 80 + curl -sSL --retry ${NET_RETRY_COUNT:-5} 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0xE1DD270288B4E6030699E45FA1715D88E1DF1F24' | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/git-core_ubuntu_ppa.gpg + for i in {1..${NET_RETRY_COUNT:-3}}; do sudo -E add-apt-repository -y ppa:git-core/ppa && break || sleep 10; done + apt-get -o Acquire::Retries=$NET_RETRY_COUNT update + osver=$(lsb_release -sr | cut -f1 -d.) + pkgs="g++ git" + # Ubuntu 22+ has only Python 3 in the repos + if [ -n "$osver" ] && [ "$osver" -ge "22" ]; then + pkgs+=" python-is-python3 libpython3-dev" + else + pkgs+=" python libpython-dev" + fi + apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y $pkgs locales + sudo locale-gen de_DE.UTF-8 + sudo update-locale + fi + # For jobs not compatible with ccache, use "ccache: no" in the matrix + if [[ "${{ matrix.ccache }}" == "no" ]]; then + echo "B2_USE_CCACHE=0" >> $GITHUB_ENV + fi + git config --global pack.threads 0 + if [[ "${{matrix.container}}" == "ubuntu:16.04" ]] || [[ "${{matrix.container}}" == "ubuntu:18.04" ]]; then + # Ubuntu 16/18 can't run Node 20, so stick to older actions: https://github.com/actions/checkout/issues/1590 + echo "GHA_USE_NODE_20=false" >> $GITHUB_ENV + echo "ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION=true" >> $GITHUB_ENV + else + echo "GHA_USE_NODE_20=true" >> $GITHUB_ENV + fi + + - uses: actions/checkout@v3 + if: env.GHA_USE_NODE_20 == 'false' + with: + # For coverage builds fetch the whole history, else only 1 commit using a 'fake ternary' + fetch-depth: ${{ matrix.coverage && '0' || '1' }} + - uses: actions/checkout@v4 + if: env.GHA_USE_NODE_20 == 'true' + with: + # For coverage builds fetch the whole history, else only 1 commit using a 'fake ternary' + fetch-depth: ${{ matrix.coverage && '0' || '1' }} + + - name: Cache ccache + uses: actions/cache@v3 + if: env.B2_USE_CCACHE && env.GHA_USE_NODE_20 == 'false' + with: + path: ~/.ccache + key: ${{matrix.os}}-${{matrix.container}}-${{matrix.compiler}}-${{github.sha}} + restore-keys: ${{matrix.os}}-${{matrix.container}}-${{matrix.compiler}}- + + - name: Cache ccache + uses: actions/cache@v4 + if: env.B2_USE_CCACHE && env.GHA_USE_NODE_20 == 'true' + with: + path: ~/.ccache + key: ${{matrix.os}}-${{matrix.container}}-${{matrix.compiler}}-${{github.sha}} + restore-keys: ${{matrix.os}}-${{matrix.container}}-${{matrix.compiler}}- + + - name: Fetch Boost.CI + uses: actions/checkout@v3 + if: env.GHA_USE_NODE_20 == 'false' + with: + repository: boostorg/boost-ci + ref: master + path: boost-ci-cloned + + - name: Fetch Boost.CI + uses: actions/checkout@v4 + if: env.GHA_USE_NODE_20 == 'true' + with: + repository: boostorg/boost-ci + ref: master + path: boost-ci-cloned + + - name: Get CI scripts folder + run: | + # Copy ci folder if not testing Boost.CI + [[ "$GITHUB_REPOSITORY" =~ "boost-ci" ]] || cp -r boost-ci-cloned/ci . + rm -rf boost-ci-cloned + + - name: Install packages + if: startsWith(matrix.os, 'ubuntu') + run: | + SOURCE_KEYS=(${{join(matrix.source_keys, ' ')}}) + SOURCES=(${{join(matrix.sources, ' ')}}) + # Add this by default + SOURCE_KEYS+=('http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x1E9377A2BA9EF27F') + SOURCES+=(ppa:ubuntu-toolchain-r/test) + + ci/add-apt-keys.sh "${SOURCE_KEYS[@]}" + # Initial update before adding sources required to get e.g. keys + sudo apt-get -o Acquire::Retries=$NET_RETRY_COUNT update + ci/add-apt-repositories.sh "${SOURCES[@]}" + + sudo apt-get -o Acquire::Retries=$NET_RETRY_COUNT update + if [[ -z "${{matrix.install}}" ]]; then + pkgs="${{matrix.compiler}}" + pkgs="${pkgs/gcc-/g++-}" + else + pkgs="${{matrix.install}}" + fi + sudo apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y $pkgs + + - name: Setup GCC Toolchain + if: matrix.gcc_toolchain + run: | + GCC_TOOLCHAIN_ROOT="$HOME/gcc-toolchain" + echo "GCC_TOOLCHAIN_ROOT=$GCC_TOOLCHAIN_ROOT" >> $GITHUB_ENV + if ! command -v dpkg-architecture; then + apt-get install -y dpkg-dev + fi + MULTIARCH_TRIPLET="$(dpkg-architecture -qDEB_HOST_MULTIARCH)" + mkdir -p "$GCC_TOOLCHAIN_ROOT" + ln -s /usr/include "$GCC_TOOLCHAIN_ROOT/include" + ln -s /usr/bin "$GCC_TOOLCHAIN_ROOT/bin" + mkdir -p "$GCC_TOOLCHAIN_ROOT/lib/gcc/$MULTIARCH_TRIPLET" + ln -s "/usr/lib/gcc/$MULTIARCH_TRIPLET/${{matrix.gcc_toolchain}}" "$GCC_TOOLCHAIN_ROOT/lib/gcc/$MULTIARCH_TRIPLET/${{matrix.gcc_toolchain}}" + + - name: Setup multiarch + if: matrix.multiarch + env: + BDDE_DISTRO: ${{matrix.distro}} + BDDE_EDITION: ${{matrix.edition}} + BDDE_ARCH: ${{matrix.arch}} + run: ci/github/setup_bdde.sh + + - name: Setup Boost + env: + B2_ADDRESS_MODEL: ${{matrix.address-model}} + B2_COMPILER: ${{matrix.compiler}} + B2_CXXSTD: ${{matrix.cxxstd}} + B2_SANITIZE: ${{matrix.sanitize}} + B2_STDLIB: ${{matrix.stdlib}} + # More entries can be added in the same way, see the B2_ARGS assignment in ci/enforce.sh for the possible keys. + # B2_DEFINES: 'BOOST_DECIMAL_QEMU_TEST' + # Variables set here (to non-empty) will override the top-level environment variables, e.g. + # B2_VARIANT: ${{matrix.variant}} + # Set the (B2) target(s) to build, defaults to the test folder of the current library + # Can alternatively be done like this in the build step or in the build command of the build step, e.g. `run: B2_TARGETS=libs/$SELF/doc ci/build.sh` + # B2_TARGETS: libs/foo/test//bar + run: source ci/github/install.sh + + - name: Run tests + if: '!matrix.coverity' + run: ci/build.sh From 0e7ca0e2a88974c8e6b465c0d8bf3fe7bc5dedb7 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 8 Oct 2024 16:51:47 -0400 Subject: [PATCH 026/107] Add additional header --- include/boost/crypt/hash/md5.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/boost/crypt/hash/md5.hpp b/include/boost/crypt/hash/md5.hpp index 0295dcb..007e8c3 100644 --- a/include/boost/crypt/hash/md5.hpp +++ b/include/boost/crypt/hash/md5.hpp @@ -9,6 +9,7 @@ #include #include +#include #include #include #include From 32ea9d0647bd82f078f700d99132eb856c1eb0f6 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 8 Oct 2024 16:59:00 -0400 Subject: [PATCH 027/107] Additional casts --- include/boost/crypt/hash/md5.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/boost/crypt/hash/md5.hpp b/include/boost/crypt/hash/md5.hpp index 007e8c3..1cdde53 100644 --- a/include/boost/crypt/hash/md5.hpp +++ b/include/boost/crypt/hash/md5.hpp @@ -80,17 +80,17 @@ auto md5_pad(const std::vector& message) noexcept -> std::vector padded_message {message}; const std::uint64_t original_length {message.size() * 8U}; - padded_message.emplace_back(0x80); + padded_message.emplace_back(static_cast(0x80)); while ((padded_message.size() * 8U) % 512U != 448U) { - padded_message.push_back(static_cast(0x00)); + padded_message.emplace_back(static_cast(0x00)); } // Add the original length as a 64-bit number for (std::size_t i = 0; i < 8; ++i) { - padded_message.push_back(static_cast((original_length >> (8 * i)) & 0xFF)); + padded_message.emplace_back(static_cast((original_length >> (8 * i)) & 0xFF)); } return padded_message; From 0990f0eb95d9350acfc7abbaad0f83a336aecac6 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 9 Oct 2024 09:31:50 -0400 Subject: [PATCH 028/107] Add outline of byte class --- include/boost/crypt/utility/byte.hpp | 104 +++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 include/boost/crypt/utility/byte.hpp diff --git a/include/boost/crypt/utility/byte.hpp b/include/boost/crypt/utility/byte.hpp new file mode 100644 index 0000000..669a152 --- /dev/null +++ b/include/boost/crypt/utility/byte.hpp @@ -0,0 +1,104 @@ +// Copyright 2024 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CRYPT_UTILITY_BYTE_HPP +#define BOOST_CRYPT_UTILITY_BYTE_HPP + +#include +#include +#include + +namespace boost { +namespace crypt { + +class byte +{ +private: + std::uint8_t bits_; + +public: + constexpr byte() noexcept : bits_ {} {} + explicit constexpr byte(std::uint8_t bits) noexcept : bits_ {bits} {} + + template + constexpr auto to_integer() noexcept -> IntegerType + { + return static_cast(bits_); + } + + template + constexpr auto operator<<(IntegerType shift) noexcept -> byte + { + return byte{bits_ << shift}; + } + + template + constexpr auto operator>>(IntegerType shift) noexcept -> byte + { + return byte{bits_ >> shift}; + } + + constexpr auto operator|(byte rhs) const noexcept -> byte + { + return byte{static_cast(bits_ | rhs.bits_)}; + } + + constexpr auto operator&(byte rhs) const noexcept -> byte + { + return byte{static_cast(bits_ & rhs.bits_)}; + } + + constexpr auto operator^(byte rhs) const noexcept -> byte + { + return byte{static_cast(bits_ ^ rhs.bits_)}; + } + + constexpr auto operator~() const noexcept -> byte + { + return byte{static_cast(~bits_)}; + } + + template + constexpr auto operator<<=(IntegerType shift) noexcept -> byte& + { + bits_ <<= shift; + return *this; + } + + template + constexpr auto operator >>=(IntegerType shift) noexcept -> byte& + { + bits_ >>= shift; + return *this; + } + + constexpr auto operator|(byte rhs) noexcept -> byte& + { + bits_ = static_cast(bits_ | rhs.bits_); + return *this; + } + + constexpr auto operator&(byte rhs) noexcept -> byte& + { + bits_ = static_cast(bits_ & rhs.bits_); + return *this; + } + + constexpr auto operator^(byte rhs) noexcept -> byte& + { + bits_ = static_cast(bits_ ^ rhs.bits_); + return *this; + } + + constexpr auto operator~() noexcept -> byte& + { + bits_ = ~bits_; + return *this; + } +}; + +} // namespace crypt +} // namespace boost + +#endif //BOOST_CRYPT_UTILITY_BYTE_HPP From d0fc1c5cc79429d7071f2b8e1f70d541cf11ef0e Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 9 Oct 2024 09:58:50 -0400 Subject: [PATCH 029/107] Add inline constexpr --- include/boost/crypt/utility/config.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/boost/crypt/utility/config.hpp b/include/boost/crypt/utility/config.hpp index 4770b94..fd71b68 100644 --- a/include/boost/crypt/utility/config.hpp +++ b/include/boost/crypt/utility/config.hpp @@ -15,12 +15,15 @@ #if defined(__cpp_inline_variables) && __cpp_inline_variables >= 201606L # define BOOST_CRYPT_CONSTEXPR_ARRAY inline constexpr # define BOOST_CRYPT_DEVICE_ARRAY inline constexpr +# define BOOST_CRYPT_INLINE_CONSTEXPR inline constexpr #elif defined(BOOST_CRYPT_ENABLE_CUDA) # define BOOST_CYPRT_CONSTEXPR_ARRAY static constexpr # define BOOST_CRYPT_DEVICE_ARRAY __constant__ +# define BOOST_CRYPT_INLINE_CONSTEXPR static constexpr #else # define BOOST_CRYPT_CONSTEXPR_ARRAY static constexpr # define BOOST_CRYPT_DEVICE_ARRAY static constexpr +# define BOOST_CRYPT_INLINE_CONSTEXPR static constexpr #endif // ---- Constexpr arrays ----- From 7c7947c285bb5503eff13925d2f05798a93c8a5f Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 9 Oct 2024 09:59:01 -0400 Subject: [PATCH 030/107] Add CUDA capable type_traits --- include/boost/crypt/utility/type_traits.hpp | 494 ++++++++++++++++++++ 1 file changed, 494 insertions(+) create mode 100644 include/boost/crypt/utility/type_traits.hpp diff --git a/include/boost/crypt/utility/type_traits.hpp b/include/boost/crypt/utility/type_traits.hpp new file mode 100644 index 0000000..5e78db7 --- /dev/null +++ b/include/boost/crypt/utility/type_traits.hpp @@ -0,0 +1,494 @@ +// Copyright (c) 2024 Matt Borland +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Regular use of is not compatible with CUDA +// Adds aliases to unify the support +// Also adds convience overloads like is_same_v so we don't have to wait for C++17 + +#ifndef BOOST_CRYPT_UTILITY_TYPE_TRAITS +#define BOOST_CRYPT_UTILITY_TYPE_TRAITS + +#include + +#ifdef BOOST_CRYPT_ENABLE_CUDA + +#include + +namespace boost { +namespace crypt { + +// Helper classes +using cuda::std::integral_constant; +using cuda::std::true_type; +using cuda::std::false_type; + +// Primary type categories +using cuda::std::is_void; +using cuda::std::is_null_pointer; +using cuda::std::is_integral; +using cuda::std::is_floating_point; +using cuda::std::is_array; +using cuda::std::is_enum; +using cuda::std::is_union; +using cuda::std::is_class; +using cuda::std::is_function; +using cuda::std::is_pointer; +using cuda::std::is_lvalue_reference; +using cuda::std::is_rvalue_reference; +using cuda::std::is_member_object_pointer; +using cuda::std::is_member_function_pointer; + +// Composite Type Categories +using cuda::std::is_fundamental; +using cuda::std::is_arithmetic; +using cuda::std::is_scalar; +using cuda::std::is_object; +using cuda::std::is_compound; +using cuda::std::is_reference; +using cuda::std::is_member_pointer; + +// Type properties +using cuda::std::is_const; +using cuda::std::is_volatile; +using cuda::std::is_trivial; +using cuda::std::is_trivially_copyable; +using cuda::std::is_standard_layout; +using cuda::std::is_empty; +using cuda::std::is_polymorphic; +using cuda::std::is_abstract; +using cuda::std::is_final; +using cuda::std::is_signed; +using cuda::std::is_unsigned; + +// Supported Operations +using cuda::std::is_constructible; +using cuda::std::is_trivially_constructible; +using cuda::std::is_nothrow_constructible; + +using cuda::std::is_default_constructible; +using cuda::std::is_trivially_default_constructible; +using cuda::std::is_nothrow_default_constructible; + +using cuda::std::is_copy_constructible; +using cuda::std::is_trivially_copy_constructible; +using cuda::std::is_nothrow_copy_constructible; + +using cuda::std::is_move_constructible; +using cuda::std::is_trivially_move_constructible; +using cuda::std::is_nothrow_move_constructible; + +using cuda::std::is_assignable; +using cuda::std::is_trivially_assignable; +using cuda::std::is_nothrow_assignable; + +using cuda::std::is_copy_assignable; +using cuda::std::is_trivially_copy_assignable; +using cuda::std::is_nothrow_copy_assignable; + +using cuda::std::is_move_assignable; +using cuda::std::is_trivially_move_assignable; +using cuda::std::is_nothrow_move_assignable; + +using cuda::std::is_destructible; +using cuda::std::is_trivially_destructible; +using cuda::std::is_nothrow_destructible; + +using cuda::std::has_virtual_destructor; + +// Property Queries +using cuda::std::alignment_of; +using cuda::std::rank; +using cuda::std::extent; + +// Type Relationships +using cuda::std::is_same; +using cuda::std::is_base_of; +using cuda::std::is_convertible; + +// Const-volatility specifiers +using cuda::std::remove_cv; +using cuda::std::remove_cv_t; +using cuda::std::remove_const; +using cuda::std::remove_const_t; +using cuda::std::remove_volatile; +using cuda::std::remove_volatile_t; +using cuda::std::add_cv; +using cuda::std::add_cv_t; +using cuda::std::add_const; +using cuda::std::add_const_t; +using cuda::std::add_volatile; +using cuda::std::add_volatile_t; + +// References +using cuda::std::remove_reference; +using cuda::std::remove_reference_t; +using cuda::std::add_lvalue_reference; +using cuda::std::add_lvalue_reference_t; +using cuda::std::add_rvalue_reference; +using cuda::std::add_rvalue_reference_t; + +// Pointers +using cuda::std::remove_pointer; +using cuda::std::remove_pointer_t; +using cuda::std::add_pointer; +using cuda::std::add_pointer_t; + +// Sign Modifiers +using cuda::std::make_signed; +using cuda::std::make_signed_t; +using cuda::std::make_unsigned; +using cuda::std::make_unsigned_t; + +// Arrays +using cuda::std::remove_extent; +using cuda::std::remove_extent_t; +using cuda::std::remove_all_extents; +using cuda::std::remove_all_extents_t; + +// Misc transformations +using cuda::std::decay; +using cuda::std::decay_t; +using cuda::std::enable_if; +using cuda::std::enable_if_t; +using cuda::std::conditional; +using cuda::std::conditional_t; +using cuda::std::common_type; +using cuda::std::common_type_t; +using cuda::std::underlying_type; +using cuda::std::underlying_type_t; + +#else // STD versions + +#include + +namespace boost { +namespace crypt { + +// Helper classes +using std::integral_constant; +using std::true_type; +using std::false_type; + +// Primary type categories +using std::is_void; +using std::is_null_pointer; +using std::is_integral; +using std::is_floating_point; +using std::is_array; +using std::is_enum; +using std::is_union; +using std::is_class; +using std::is_function; +using std::is_pointer; +using std::is_lvalue_reference; +using std::is_rvalue_reference; +using std::is_member_object_pointer; +using std::is_member_function_pointer; + +// Composite Type Categories +using std::is_fundamental; +using std::is_arithmetic; +using std::is_scalar; +using std::is_object; +using std::is_compound; +using std::is_reference; +using std::is_member_pointer; + +// Type properties +using std::is_const; +using std::is_volatile; +using std::is_trivial; +using std::is_trivially_copyable; +using std::is_standard_layout; +using std::is_empty; +using std::is_polymorphic; +using std::is_abstract; +using std::is_final; +using std::is_signed; +using std::is_unsigned; + +// Supported Operations +using std::is_constructible; +using std::is_trivially_constructible; +using std::is_nothrow_constructible; + +using std::is_default_constructible; +using std::is_trivially_default_constructible; +using std::is_nothrow_default_constructible; + +using std::is_copy_constructible; +using std::is_trivially_copy_constructible; +using std::is_nothrow_copy_constructible; + +using std::is_move_constructible; +using std::is_trivially_move_constructible; +using std::is_nothrow_move_constructible; + +using std::is_assignable; +using std::is_trivially_assignable; +using std::is_nothrow_assignable; + +using std::is_copy_assignable; +using std::is_trivially_copy_assignable; +using std::is_nothrow_copy_assignable; + +using std::is_move_assignable; +using std::is_trivially_move_assignable; +using std::is_nothrow_move_assignable; + +using std::is_destructible; +using std::is_trivially_destructible; +using std::is_nothrow_destructible; + +using std::has_virtual_destructor; + +// Property Queries +using std::alignment_of; +using std::rank; +using std::extent; + +// Type Relationships +using std::is_same; +using std::is_base_of; +using std::is_convertible; + +// Const-volatility specifiers +using std::remove_cv; +using std::remove_cv_t; +using std::remove_const; +using std::remove_const_t; +using std::remove_volatile; +using std::remove_volatile_t; +using std::add_cv; +using std::add_cv_t; +using std::add_const; +using std::add_const_t; +using std::add_volatile; +using std::add_volatile_t; + +// References +using std::remove_reference; +using std::remove_reference_t; +using std::add_lvalue_reference; +using std::add_lvalue_reference_t; +using std::add_rvalue_reference; +using std::add_rvalue_reference_t; + +// Pointers +using std::remove_pointer; +using std::remove_pointer_t; +using std::add_pointer; +using std::add_pointer_t; + +// Sign Modifiers +using std::make_signed; +using std::make_signed_t; +using std::make_unsigned; +using std::make_unsigned_t; + +// Arrays +using std::remove_extent; +using std::remove_extent_t; +using std::remove_all_extents; +using std::remove_all_extents_t; + +// Misc transformations +using std::decay; +using std::decay_t; +using std::enable_if; +using std::enable_if_t; +using std::conditional; +using std::conditional_t; +using std::common_type; +using std::common_type_t; +using std::underlying_type; +using std::underlying_type_t; + +#endif + +template +using bool_constant = boost::crypt::integral_constant; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_void_v = boost::crypt::is_void::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_null_pointer_v = boost::crypt::is_null_pointer::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_integral_v = boost::crypt::is_integral::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_floating_point_v = boost::crypt::is_floating_point::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_array_v = boost::crypt::is_array::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_enum_v = boost::crypt::is_enum::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_union_v = boost::crypt::is_union::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_class_v = boost::crypt::is_class::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_function_v = boost::crypt::is_function::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_pointer_v = boost::crypt::is_pointer::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_lvalue_reference_v = boost::crypt::is_lvalue_reference::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_rvalue_reference_v = boost::crypt::is_rvalue_reference::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_member_object_pointer_v = boost::crypt::is_member_object_pointer::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_member_function_pointer_v = boost::crypt::is_member_function_pointer::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_fundamental_v = boost::crypt::is_fundamental::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_arithmetic_v = boost::crypt::is_arithmetic::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_scalar_v = boost::crypt::is_scalar::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_object_v = boost::crypt::is_object::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_compound_v = boost::crypt::is_compound::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_reference_v = boost::crypt::is_reference::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_member_pointer_v = boost::crypt::is_member_pointer::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_const_v = boost::crypt::is_const::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_volatile_v = boost::crypt::is_volatile::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_trivial_v = boost::crypt::is_trivial::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_trivially_copyable_v = boost::crypt::is_trivially_copyable::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_standard_layout_v = boost::crypt::is_standard_layout::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_empty_v = boost::crypt::is_empty::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_polymorphic_v = boost::crypt::is_polymorphic::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_abstract_v = boost::crypt::is_abstract::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_final_v = boost::crypt::is_final::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_signed_v = boost::crypt::is_signed::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_unsigned_v = boost::crypt::is_unsigned::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_constructible_v = boost::crypt::is_constructible::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_trivially_constructible_v = boost::crypt::is_trivially_constructible::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_nothrow_constructible_v = boost::crypt::is_nothrow_constructible::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_default_constructible_v = boost::crypt::is_default_constructible::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_trivially_default_constructible_v = boost::crypt::is_trivially_default_constructible::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_nothrow_default_constructible_v = boost::crypt::is_nothrow_default_constructible::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_copy_constructible_v = boost::crypt::is_copy_constructible::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_trivially_copy_constructible_v = boost::crypt::is_trivially_copy_constructible::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_nothrow_copy_constructible_v = boost::crypt::is_nothrow_copy_constructible::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_move_constructible_v = boost::crypt::is_move_constructible::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_trivially_move_constructible_v = boost::crypt::is_trivially_move_constructible::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_nothrow_move_constructible_v = boost::crypt::is_nothrow_move_constructible::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_assignable_v = boost::crypt::is_assignable::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_trivially_assignable_v = boost::crypt::is_trivially_assignable::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_nothrow_assignable_v = boost::crypt::is_nothrow_assignable::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_copy_assignable_v = boost::crypt::is_copy_assignable::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_trivially_copy_assignable_v = boost::crypt::is_trivially_copy_assignable::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_nothrow_copy_assignable_v = boost::crypt::is_nothrow_copy_assignable::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_move_assignable_v = boost::crypt::is_move_assignable::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_trivially_move_assignable_v = boost::crypt::is_trivially_move_assignable::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_nothrow_move_assignable_v = boost::crypt::is_nothrow_move_assignable::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_destructible_v = boost::crypt::is_destructible::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_trivially_destructible_v = boost::crypt::is_trivially_destructible::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_nothrow_destructible_v = boost::crypt::is_nothrow_destructible::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool has_virtual_destructor_v = boost::crypt::has_virtual_destructor::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_same_v = boost::crypt::is_same::value; + +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_base_of_v = boost::crypt::is_base_of::value; + +} // namespace crypt +} // namespace boost + +#endif // BOOST_CRYPT_UTILITY_TYPE_TRAITS From 3be97dc1a914af1fd691b47f1aec8653eee2f353 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 9 Oct 2024 11:23:38 -0400 Subject: [PATCH 031/107] Add starting concepts definitions --- include/boost/crypt/utility/concepts.hpp | 124 +++++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 include/boost/crypt/utility/concepts.hpp diff --git a/include/boost/crypt/utility/concepts.hpp b/include/boost/crypt/utility/concepts.hpp new file mode 100644 index 0000000..889f724 --- /dev/null +++ b/include/boost/crypt/utility/concepts.hpp @@ -0,0 +1,124 @@ +// Copyright 2024 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CRYPT_UTILITY_CONCEPTS_HPP +#define BOOST_CRYPT_UTILITY_CONCEPTS_HPP + +#include + +#ifndef BOOST_CRYPT_BUILD_MODULE +#include +#endif + +// GCC-11 yields internal compiler errors when using the concepts + +/* +./boost/decimal/detail/concepts.hpp:239:80: note: in definition of macro 'BOOST_CRYPT_REQUIRES_RETURN' + 239 | #define BOOST_CRYPT_REQUIRES_RETURN(X, T, ReturnType) -> ReturnType requires X + | ^ +0xe3223b internal_error(char const*, ...) + ???:0 +0xf56ed4 duplicate_decls(tree_node*, tree_node*, bool, bool) + ???:0 +0xf60a2b pushdecl_namespace_level(tree_node*, bool) + ???:0 +0x10801ca push_template_decl(tree_node*, bool) + ???:0 +0x1527ec1 do_friend(tree_node*, tree_node*, tree_node*, tree_node*, overload_flags, bool) + ???:0 +0xfc4e1e grokdeclarator(cp_declarator const*, cp_decl_specifier_seq*, decl_context, int, tree_node**) + ???:0 +0x100dcf4 grokfield(cp_declarator const*, cp_decl_specifier_seq*, tree_node*, bool, tree_node*, tree_node*) + ???:0 +0x149dce3 c_parse_file() + ???:0 +0x148d4de c_common_parse_file() + ???:0 +*/ +#if (__cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)) && !defined(BOOST_MATH_DISABLE_CONCEPTS) &&\ + (!defined(__GNUC__) || __GNUC__ != 11) + +#if __has_include() + +#ifndef BOOST_CRYPT_BUILD_MODULE +#include +#include +#include +#include +#include +#include +#include +#endif + +namespace boost::crypt::concepts { + +template +concept integral = boost::crypt::detail::is_integral_v; + +template +concept signed_integral = integral && boost::crypt::is_signed_v; + +template +concept unsigned_integral = integral && boost::crypt::is_unsigned_v; + +template +concept real = boost::crypt::detail::is_floating_point_v; + +} // boost::crypt::concepts + +#define BOOST_CRYPT_HAS_CONCEPTS 1 + +#define BOOST_CRYPT_INTEGRAL boost::crypt::concepts::integral +#define BOOST_CRYPT_SIGNED_INTEGRAL boost::crypt::concepts::signed_integral +#define BOOST_CRYPT_UNSIGNED_INTEGRAL boost::crypt::concepts::unsigned_integral +#define BOOST_CRYPT_REAL boost::crypt::concepts::real + +#define BOOST_CRYPT_REQUIRES(X, T) -> T requires X +#define BOOST_CRYPT_REQUIRES_TWO(X1, T1, X2, T2) -> detail::promote_args_t requires X1 && X2 +#define BOOST_CRYPT_REQUIRES_TWO_RETURN(X1, T1, X2, T2, ReturnType) -> ReturnType requires X1 && X2 +#define BOOST_CRYPT_REQUIRES_THREE(X1, T1, X2, T2, X3, T3) -> detail::promote_args_t requires X1 && X2 && X3 +#define BOOST_CRYPT_REQUIRES_RETURN(X, T, ReturnType) -> ReturnType requires X + + +#endif // Has +#endif // C++20 + +// If concepts are unavailable replace them with typename for compatibility + +#ifndef BOOST_CRYPT_INTEGRAL +# define BOOST_CRYPT_INTEGRAL typename +#endif + +#ifndef BOOST_CRYPT_SIGNED_INTEGRAL +# define BOOST_CRYPT_SIGNED_INTEGRAL typename +#endif + +#ifndef BOOST_CRYPT_UNSIGNED_INTEGRAL +# define BOOST_CRYPT_UNSIGNED_INTEGRAL typename +#endif + +#ifndef BOOST_CRYPT_REAL +# define BOOST_CRYPT_REAL typename +#endif +#ifndef BOOST_CRYPT_REQUIRES +# define BOOST_CRYPT_REQUIRES(X, T) -> boost::crypt::enable_if_t, T> +#endif + +#ifndef BOOST_CRYPT_REQUIRES_TWO +# define BOOST_CRYPT_REQUIRES_TWO(X1, T1, X2, T2) -> boost::crypt::enable_if_t && X2, detail::promote_args_t> +#endif + +#ifndef BOOST_CRYPT_REQUIRES_TWO_RETURN +# define BOOST_CRYPT_REQUIRES_TWO_RETURN(X1, T1, X2, T2, ReturnType) -> boost::crypt::enable_if_t && X2, ReturnType> +#endif + +#ifndef BOOST_CRYPT_REQUIRES_THREE +# define BOOST_CRYPT_REQUIRES_THREE(X1, T1, X2, T2, X3, T3) -> boost::crypt::enable_if_t && X2 && X3, detail::promote_args_t> +#endif + +#ifndef BOOST_CRYPT_REQUIRES_RETURN +# define BOOST_CRYPT_REQUIRES_RETURN(X, T, ReturnType) -> boost::crypt::enable_if_t, ReturnType> +#endif + +#endif //BOOST_CRYPT_UTILITY_CONCEPTS_HPP From 82a69ebe080d27f9ce54ff9b7bda6f321910d798 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 9 Oct 2024 11:26:28 -0400 Subject: [PATCH 032/107] Add concepts to byte --- include/boost/crypt/utility/byte.hpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/include/boost/crypt/utility/byte.hpp b/include/boost/crypt/utility/byte.hpp index 669a152..43a8453 100644 --- a/include/boost/crypt/utility/byte.hpp +++ b/include/boost/crypt/utility/byte.hpp @@ -6,8 +6,11 @@ #define BOOST_CRYPT_UTILITY_BYTE_HPP #include -#include +#include + +#ifndef BOOST_CRYPT_BUILD_MODULE #include +#endif namespace boost { namespace crypt { @@ -22,19 +25,22 @@ class byte explicit constexpr byte(std::uint8_t bits) noexcept : bits_ {bits} {} template - constexpr auto to_integer() noexcept -> IntegerType + constexpr auto to_integer() noexcept + BOOST_CRYPT_REQUIRES(boost::crypt::is_integral_v, IntegerType) { return static_cast(bits_); } template - constexpr auto operator<<(IntegerType shift) noexcept -> byte + constexpr auto operator<<(IntegerType shift) noexcept + BOOST_CRYPT_REQUIRES_RETURN(boost::crypt::is_integral_v, IntegerType, byte) { return byte{bits_ << shift}; } template - constexpr auto operator>>(IntegerType shift) noexcept -> byte + constexpr auto operator>>(IntegerType shift) noexcept + BOOST_CRYPT_REQUIRES_RETURN(boost::crypt::is_integral_v, IntegerType, byte) { return byte{bits_ >> shift}; } @@ -60,14 +66,16 @@ class byte } template - constexpr auto operator<<=(IntegerType shift) noexcept -> byte& + constexpr auto operator<<=(IntegerType shift) noexcept + BOOST_CRYPT_REQUIRES_RETURN(boost::crypt::is_integral_v, IntegerType, byte&) { bits_ <<= shift; return *this; } template - constexpr auto operator >>=(IntegerType shift) noexcept -> byte& + constexpr auto operator >>=(IntegerType shift) noexcept + BOOST_CRYPT_REQUIRES_RETURN(boost::crypt::is_integral_v, IntegerType, byte&) { bits_ >>= shift; return *this; From 385ce9492a2b338b99b66526a06b6cff494ef5f5 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 9 Oct 2024 11:37:34 -0400 Subject: [PATCH 033/107] Add CUDA array --- include/boost/crypt/utility/array.hpp | 39 +++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 include/boost/crypt/utility/array.hpp diff --git a/include/boost/crypt/utility/array.hpp b/include/boost/crypt/utility/array.hpp new file mode 100644 index 0000000..f2ab2af --- /dev/null +++ b/include/boost/crypt/utility/array.hpp @@ -0,0 +1,39 @@ +// Copyright 2024 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + + +#ifndef BOOST_CRYPT_UTILITIES_ARRAY_HPP +#define BOOST_CRYPT_UTILITIES_ARRAY_HPP + +#include + +#ifdef BOOST_CRYPT_ENABLE_CUDA + +#include + +namespace boost { +namespace crypt { + +using cuda::std::array; + +} // namespace crypt +} // namespace boost + +#else // Use the STL + +#ifndef BOOST_CRYPT_BUILD_MODULE +#include +#endif + +namespace boost { +namespace crypt { + +using std::array; + +} // namespace crypt +} // namespace boost + +#endif // CUDA + +#endif // BOOST_CRYPT_UTILITIES_ARRAY_HPP From 1574e1910a30fd8a6fbd996656e09f41d2e01ec1 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 9 Oct 2024 11:40:28 -0400 Subject: [PATCH 034/107] Add CUDA cstdint --- include/boost/crypt/utility/cstdint.hpp | 109 ++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 include/boost/crypt/utility/cstdint.hpp diff --git a/include/boost/crypt/utility/cstdint.hpp b/include/boost/crypt/utility/cstdint.hpp new file mode 100644 index 0000000..5863fc4 --- /dev/null +++ b/include/boost/crypt/utility/cstdint.hpp @@ -0,0 +1,109 @@ +// Copyright (c) 2024 Matt Borland +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_CRYPT_TOOLS_CSTDINT +#define BOOST_CRYPT_TOOLS_CSTDINT + +#include + +#ifdef BOOST_CRYPT_ENABLE_CUDA + +#include + +namespace boost { +namespace crypt { + +using cuda::std::int8_t; +using cuda::std::int16_t; +using cuda::std::int32_t; +using cuda::std::int64_t; + +using cuda::std::int_fast8_t; +using cuda::std::int_fast16_t; +using cuda::std::int_fast32_t; +using cuda::std::int_fast64_t; + +using cuda::std::int_least8_t; +using cuda::std::int_least16_t; +using cuda::std::int_least32_t; +using cuda::std::int_least64_t; + +using cuda::std::intmax_t; +using cuda::std::intptr_t; + +using cuda::std::uint8_t; +using cuda::std::uint16_t; +using cuda::std::uint32_t; +using cuda::std::uint64_t; + +using cuda::std::uint_fast8_t; +using cuda::std::uint_fast16_t; +using cuda::std::uint_fast32_t; +using cuda::std::uint_fast64_t; + +using cuda::std::uint_least8_t; +using cuda::std::uint_least16_t; +using cuda::std::uint_least32_t; +using cuda::std::uint_least64_t; + +using cuda::std::uintmax_t; +using cuda::std::uintptr_t; + +using size_t = unsigned long; + +#else + +#ifndef BOOST_CRYPT_BUILD_MODULE +#include +#include +#endif + +namespace boost { +namespace crypt { + +using std::int8_t; +using std::int16_t; +using std::int32_t; +using std::int64_t; + +using std::int_fast8_t; +using std::int_fast16_t; +using std::int_fast32_t; +using std::int_fast64_t; + +using std::int_least8_t; +using std::int_least16_t; +using std::int_least32_t; +using std::int_least64_t; + +using std::intmax_t; +using std::intptr_t; + +using std::uint8_t; +using std::uint16_t; +using std::uint32_t; +using std::uint64_t; + +using std::uint_fast8_t; +using std::uint_fast16_t; +using std::uint_fast32_t; +using std::uint_fast64_t; + +using std::uint_least8_t; +using std::uint_least16_t; +using std::uint_least32_t; +using std::uint_least64_t; + +using std::uintmax_t; +using std::uintptr_t; + +using std::size_t; + +#endif + +} // namespace crypt +} // namespace boost + +#endif // BOOST_CRYPT_TOOLS_CSTDINT From 265ea28101b4e5e73dba475dab5819a9d9d37320 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 9 Oct 2024 11:55:33 -0400 Subject: [PATCH 035/107] Add more GPU macros --- include/boost/crypt/utility/config.hpp | 29 ++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/include/boost/crypt/utility/config.hpp b/include/boost/crypt/utility/config.hpp index fd71b68..bec8d29 100644 --- a/include/boost/crypt/utility/config.hpp +++ b/include/boost/crypt/utility/config.hpp @@ -6,9 +6,34 @@ #define BOOST_CRYPT_DETAIL_CONFIG_HPP #ifdef __CUDACC__ -# ifndef BOOST_CRYPT_ENABLE_CUDA -# define BOOST_CRYPT_ENABLE_CUDA +# ifndef BOOST_CRYPT_HAS_CUDA +# define BOOST_CRYPT_HAS_CUDA # endif +# define BOOST_CRYPT_GPU_ENABLED __host__ __device__ +# define BOOST_CRYPT_GPU_HOST_ENABLED __host__ +# define BOOST_CRYPT_GPU_DEVICE_ENABLED __device__ +#endif + +#ifdef __CUDACC_RTC__ +# ifndef BOOST_CRYPT_HAS_CUDA +# define BOOST_CRYPT_HAS_CUDA +# endif +# define BOOST_CRYPT_HAS_NVRTC +# define BOOST_CRYPT_GPU_ENABLED __host__ __device__ +# define BOOST_CRYPT_GPU_HOST_ENABLED __host__ +# define BOOST_CRYPT_GPU_DEVICE_ENABLED __device__ +#endif + +#ifndef BOOST_CRYPT_GPU_ENABLED +# define BOOST_CRYPT_GPU_ENABLED +#endif + +#ifndef BOOST_CRYPT_GPU_HOST_ENABLED +# define BOOST_CRYPT_GPU_HOST_ENABLED +#endif + +#ifndef BOOST_CRYPT_GPU_DEVICE_ENABLED +# define BOOST_CRYPT_GPU_DEVICE_ENABLED #endif // ---- Constexpr arrays ----- From bd9adb9e7bca79233a206b0109965e60212a71fe Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 9 Oct 2024 11:55:41 -0400 Subject: [PATCH 036/107] Add limits support --- include/boost/crypt/utility/limits.hpp | 888 +++++++++++++++++++++++++ 1 file changed, 888 insertions(+) create mode 100644 include/boost/crypt/utility/limits.hpp diff --git a/include/boost/crypt/utility/limits.hpp b/include/boost/crypt/utility/limits.hpp new file mode 100644 index 0000000..a09a8bc --- /dev/null +++ b/include/boost/crypt/utility/limits.hpp @@ -0,0 +1,888 @@ +// Copyright (c) 2024 Matt Borland +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Regular use of std::numeric_limits functions can not be used on +// GPU platforms like CUDA since they are missing the __device__ marker +// and libcu++ does not provide something analogous. +// Rather than using giant if else blocks make our own version of numeric limits +// +// On the CUDA NVRTC platform we use a best attempt at emulating the functions +// and values since we do not have any macros to go off of. +// Use the values as found on GCC 11.4 RHEL 9.4 x64 + +#ifndef BOOST_CRYPT_UTILITY_LIMITS_HPP +#define BOOST_CRYPT_UTILITY_LIMITS_HPP + +#include + +#if !defined(BOOST_CRYPT_HAS_NVRTC) && !defined(BOOST_CRYPT_BUILD_MODULE) + +#include +#include +#include +#include + +#endif + +namespace boost { +namespace crypt { + +template +struct numeric_limits +#ifndef BOOST_CRYPT_HAS_NVRTC + : public std::numeric_limits {}; +#else +{}; +#endif + +#if defined(BOOST_CRYPT_HAS_CUDA) && !defined(BOOST_CRYPT_HAS_NVRTC) + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = std::numeric_limits::is_specialized; + static constexpr bool is_signed = std::numeric_limits::is_signed; + static constexpr bool is_integer = std::numeric_limits::is_integer; + static constexpr bool is_exact = std::numeric_limits::is_exact; + static constexpr bool has_infinity = std::numeric_limits::has_infinity; + static constexpr bool has_quiet_NaN = std::numeric_limits::has_quiet_NaN; + static constexpr bool has_signaling_NaN = std::numeric_limits::has_signaling_NaN; + + static constexpr std::float_round_style round_style = std::numeric_limits::round_style; + static constexpr bool is_iec559 = std::numeric_limits::is_iec559; + static constexpr bool is_bounded = std::numeric_limits::is_bounded; + static constexpr bool is_modulo = std::numeric_limits::is_modulo; + static constexpr int digits = std::numeric_limits::digits; + static constexpr int digits10 = std::numeric_limits::digits10; + static constexpr int max_digits10 = std::numeric_limits::max_digits10; + static constexpr int radix = std::numeric_limits::radix; + static constexpr int min_exponent = std::numeric_limits::min_exponent; + static constexpr int min_exponent10 = std::numeric_limits::min_exponent10; + static constexpr int max_exponent = std::numeric_limits::max_exponent; + static constexpr int max_exponent10 = std::numeric_limits::max_exponent10; + static constexpr bool traps = std::numeric_limits::traps; + static constexpr bool tinyness_before = std::numeric_limits::tinyness_before; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr float (min) () { return FLT_MIN; } + BOOST_CRYPT_GPU_ENABLED static constexpr float (max) () { return FLT_MAX; } + BOOST_CRYPT_GPU_ENABLED static constexpr float lowest () { return -FLT_MAX; } + BOOST_CRYPT_GPU_ENABLED static constexpr float epsilon () { return FLT_EPSILON; } + BOOST_CRYPT_GPU_ENABLED static constexpr float round_error () { return 0.5F; } + BOOST_CRYPT_GPU_ENABLED static constexpr float infinity () { return static_cast(INFINITY); } + BOOST_CRYPT_GPU_ENABLED static constexpr float quiet_NaN () { return static_cast(NAN); } + BOOST_CRYPT_GPU_ENABLED static constexpr float signaling_NaN () + { + #ifdef FLT_SNAN + return FLT_SNAN; + #else + return static_cast(NAN); + #endif + } + BOOST_CRYPT_GPU_ENABLED static constexpr float denorm_min () { return FLT_TRUE_MIN; } +}; + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = std::numeric_limits::is_specialized; + static constexpr bool is_signed = std::numeric_limits::is_signed; + static constexpr bool is_integer = std::numeric_limits::is_integer; + static constexpr bool is_exact = std::numeric_limits::is_exact; + static constexpr bool has_infinity = std::numeric_limits::has_infinity; + static constexpr bool has_quiet_NaN = std::numeric_limits::has_quiet_NaN; + static constexpr bool has_signaling_NaN = std::numeric_limits::has_signaling_NaN; + + static constexpr std::float_round_style round_style = std::numeric_limits::round_style; + static constexpr bool is_iec559 = std::numeric_limits::is_iec559; + static constexpr bool is_bounded = std::numeric_limits::is_bounded; + static constexpr bool is_modulo = std::numeric_limits::is_modulo; + static constexpr int digits = std::numeric_limits::digits; + static constexpr int digits10 = std::numeric_limits::digits10; + static constexpr int max_digits10 = std::numeric_limits::max_digits10; + static constexpr int radix = std::numeric_limits::radix; + static constexpr int min_exponent = std::numeric_limits::min_exponent; + static constexpr int min_exponent10 = std::numeric_limits::min_exponent10; + static constexpr int max_exponent = std::numeric_limits::max_exponent; + static constexpr int max_exponent10 = std::numeric_limits::max_exponent10; + static constexpr bool traps = std::numeric_limits::traps; + static constexpr bool tinyness_before = std::numeric_limits::tinyness_before; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr double (min) () { return DBL_MIN; } + BOOST_CRYPT_GPU_ENABLED static constexpr double (max) () { return DBL_MAX; } + BOOST_CRYPT_GPU_ENABLED static constexpr double lowest () { return -DBL_MAX; } + BOOST_CRYPT_GPU_ENABLED static constexpr double epsilon () { return DBL_EPSILON; } + BOOST_CRYPT_GPU_ENABLED static constexpr double round_error () { return 0.5; } + BOOST_CRYPT_GPU_ENABLED static constexpr double infinity () { return static_cast(INFINITY); } + BOOST_CRYPT_GPU_ENABLED static constexpr double quiet_NaN () { return static_cast(NAN); } + BOOST_CRYPT_GPU_ENABLED static constexpr double signaling_NaN () + { + #ifdef DBL_SNAN + return DBL_SNAN; + #else + return static_cast(NAN); + #endif + } + BOOST_CRYPT_GPU_ENABLED static constexpr double denorm_min () { return DBL_TRUE_MIN; } +}; + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = std::numeric_limits::is_specialized; + static constexpr bool is_signed = std::numeric_limits::is_signed; + static constexpr bool is_integer = std::numeric_limits::is_integer; + static constexpr bool is_exact = std::numeric_limits::is_exact; + static constexpr bool has_infinity = std::numeric_limits::has_infinity; + static constexpr bool has_quiet_NaN = std::numeric_limits::has_quiet_NaN; + static constexpr bool has_signaling_NaN = std::numeric_limits::has_signaling_NaN; + + static constexpr std::float_round_style round_style = std::numeric_limits::round_style; + static constexpr bool is_iec559 = std::numeric_limits::is_iec559; + static constexpr bool is_bounded = std::numeric_limits::is_bounded; + static constexpr bool is_modulo = std::numeric_limits::is_modulo; + static constexpr int digits = std::numeric_limits::digits; + static constexpr int digits10 = std::numeric_limits::digits10; + static constexpr int max_digits10 = std::numeric_limits::max_digits10; + static constexpr int radix = std::numeric_limits::radix; + static constexpr int min_exponent = std::numeric_limits::min_exponent; + static constexpr int min_exponent10 = std::numeric_limits::min_exponent10; + static constexpr int max_exponent = std::numeric_limits::max_exponent; + static constexpr int max_exponent10 = std::numeric_limits::max_exponent10; + static constexpr bool traps = std::numeric_limits::traps; + static constexpr bool tinyness_before = std::numeric_limits::tinyness_before; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr short (min) () { return SHRT_MIN; } + BOOST_CRYPT_GPU_ENABLED static constexpr short (max) () { return SHRT_MAX; } + BOOST_CRYPT_GPU_ENABLED static constexpr short lowest () { return SHRT_MIN; } + BOOST_CRYPT_GPU_ENABLED static constexpr short epsilon () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr short round_error () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr short infinity () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr short quiet_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr short signaling_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr short denorm_min () { return 0; } +}; + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = std::numeric_limits::is_specialized; + static constexpr bool is_signed = std::numeric_limits::is_signed; + static constexpr bool is_integer = std::numeric_limits::is_integer; + static constexpr bool is_exact = std::numeric_limits::is_exact; + static constexpr bool has_infinity = std::numeric_limits::has_infinity; + static constexpr bool has_quiet_NaN = std::numeric_limits::has_quiet_NaN; + static constexpr bool has_signaling_NaN = std::numeric_limits::has_signaling_NaN; + + static constexpr std::float_round_style round_style = std::numeric_limits::round_style; + static constexpr bool is_iec559 = std::numeric_limits::is_iec559; + static constexpr bool is_bounded = std::numeric_limits::is_bounded; + static constexpr bool is_modulo = std::numeric_limits::is_modulo; + static constexpr int digits = std::numeric_limits::digits; + static constexpr int digits10 = std::numeric_limits::digits10; + static constexpr int max_digits10 = std::numeric_limits::max_digits10; + static constexpr int radix = std::numeric_limits::radix; + static constexpr int min_exponent = std::numeric_limits::min_exponent; + static constexpr int min_exponent10 = std::numeric_limits::min_exponent10; + static constexpr int max_exponent = std::numeric_limits::max_exponent; + static constexpr int max_exponent10 = std::numeric_limits::max_exponent10; + static constexpr bool traps = std::numeric_limits::traps; + static constexpr bool tinyness_before = std::numeric_limits::tinyness_before; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned short (min) () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned short (max) () { return USHRT_MAX; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned short lowest () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned short epsilon () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned short round_error () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned short infinity () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned short quiet_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned short signaling_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned short denorm_min () { return 0; } +}; + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = std::numeric_limits::is_specialized; + static constexpr bool is_signed = std::numeric_limits::is_signed; + static constexpr bool is_integer = std::numeric_limits::is_integer; + static constexpr bool is_exact = std::numeric_limits::is_exact; + static constexpr bool has_infinity = std::numeric_limits::has_infinity; + static constexpr bool has_quiet_NaN = std::numeric_limits::has_quiet_NaN; + static constexpr bool has_signaling_NaN = std::numeric_limits::has_signaling_NaN; + + static constexpr std::float_round_style round_style = std::numeric_limits::round_style; + static constexpr bool is_iec559 = std::numeric_limits::is_iec559; + static constexpr bool is_bounded = std::numeric_limits::is_bounded; + static constexpr bool is_modulo = std::numeric_limits::is_modulo; + static constexpr int digits = std::numeric_limits::digits; + static constexpr int digits10 = std::numeric_limits::digits10; + static constexpr int max_digits10 = std::numeric_limits::max_digits10; + static constexpr int radix = std::numeric_limits::radix; + static constexpr int min_exponent = std::numeric_limits::min_exponent; + static constexpr int min_exponent10 = std::numeric_limits::min_exponent10; + static constexpr int max_exponent = std::numeric_limits::max_exponent; + static constexpr int max_exponent10 = std::numeric_limits::max_exponent10; + static constexpr bool traps = std::numeric_limits::traps; + static constexpr bool tinyness_before = std::numeric_limits::tinyness_before; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr int (min) () { return INT_MIN; } + BOOST_CRYPT_GPU_ENABLED static constexpr int (max) () { return INT_MAX; } + BOOST_CRYPT_GPU_ENABLED static constexpr int lowest () { return INT_MIN; } + BOOST_CRYPT_GPU_ENABLED static constexpr int epsilon () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr int round_error () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr int infinity () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr int quiet_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr int signaling_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr int denorm_min () { return 0; } +}; + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = std::numeric_limits::is_specialized; + static constexpr bool is_signed = std::numeric_limits::is_signed; + static constexpr bool is_integer = std::numeric_limits::is_integer; + static constexpr bool is_exact = std::numeric_limits::is_exact; + static constexpr bool has_infinity = std::numeric_limits::has_infinity; + static constexpr bool has_quiet_NaN = std::numeric_limits::has_quiet_NaN; + static constexpr bool has_signaling_NaN = std::numeric_limits::has_signaling_NaN; + + static constexpr std::float_round_style round_style = std::numeric_limits::round_style; + static constexpr bool is_iec559 = std::numeric_limits::is_iec559; + static constexpr bool is_bounded = std::numeric_limits::is_bounded; + static constexpr bool is_modulo = std::numeric_limits::is_modulo; + static constexpr int digits = std::numeric_limits::digits; + static constexpr int digits10 = std::numeric_limits::digits10; + static constexpr int max_digits10 = std::numeric_limits::max_digits10; + static constexpr int radix = std::numeric_limits::radix; + static constexpr int min_exponent = std::numeric_limits::min_exponent; + static constexpr int min_exponent10 = std::numeric_limits::min_exponent10; + static constexpr int max_exponent = std::numeric_limits::max_exponent; + static constexpr int max_exponent10 = std::numeric_limits::max_exponent10; + static constexpr bool traps = std::numeric_limits::traps; + static constexpr bool tinyness_before = std::numeric_limits::tinyness_before; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned int (min) () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned int (max) () { return UINT_MAX; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned int lowest () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned int epsilon () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned int round_error () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned int infinity () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned int quiet_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned int signaling_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned int denorm_min () { return 0; } +}; + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = std::numeric_limits::is_specialized; + static constexpr bool is_signed = std::numeric_limits::is_signed; + static constexpr bool is_integer = std::numeric_limits::is_integer; + static constexpr bool is_exact = std::numeric_limits::is_exact; + static constexpr bool has_infinity = std::numeric_limits::has_infinity; + static constexpr bool has_quiet_NaN = std::numeric_limits::has_quiet_NaN; + static constexpr bool has_signaling_NaN = std::numeric_limits::has_signaling_NaN; + + static constexpr std::float_round_style round_style = std::numeric_limits::round_style; + static constexpr bool is_iec559 = std::numeric_limits::is_iec559; + static constexpr bool is_bounded = std::numeric_limits::is_bounded; + static constexpr bool is_modulo = std::numeric_limits::is_modulo; + static constexpr int digits = std::numeric_limits::digits; + static constexpr int digits10 = std::numeric_limits::digits10; + static constexpr int max_digits10 = std::numeric_limits::max_digits10; + static constexpr int radix = std::numeric_limits::radix; + static constexpr int min_exponent = std::numeric_limits::min_exponent; + static constexpr int min_exponent10 = std::numeric_limits::min_exponent10; + static constexpr int max_exponent = std::numeric_limits::max_exponent; + static constexpr int max_exponent10 = std::numeric_limits::max_exponent10; + static constexpr bool traps = std::numeric_limits::traps; + static constexpr bool tinyness_before = std::numeric_limits::tinyness_before; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr long (min) () { return LONG_MIN; } + BOOST_CRYPT_GPU_ENABLED static constexpr long (max) () { return LONG_MAX; } + BOOST_CRYPT_GPU_ENABLED static constexpr long lowest () { return LONG_MIN; } + BOOST_CRYPT_GPU_ENABLED static constexpr long epsilon () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr long round_error () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr long infinity () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr long quiet_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr long signaling_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr long denorm_min () { return 0; } +}; + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = std::numeric_limits::is_specialized; + static constexpr bool is_signed = std::numeric_limits::is_signed; + static constexpr bool is_integer = std::numeric_limits::is_integer; + static constexpr bool is_exact = std::numeric_limits::is_exact; + static constexpr bool has_infinity = std::numeric_limits::has_infinity; + static constexpr bool has_quiet_NaN = std::numeric_limits::has_quiet_NaN; + static constexpr bool has_signaling_NaN = std::numeric_limits::has_signaling_NaN; + + static constexpr std::float_round_style round_style = std::numeric_limits::round_style; + static constexpr bool is_iec559 = std::numeric_limits::is_iec559; + static constexpr bool is_bounded = std::numeric_limits::is_bounded; + static constexpr bool is_modulo = std::numeric_limits::is_modulo; + static constexpr int digits = std::numeric_limits::digits; + static constexpr int digits10 = std::numeric_limits::digits10; + static constexpr int max_digits10 = std::numeric_limits::max_digits10; + static constexpr int radix = std::numeric_limits::radix; + static constexpr int min_exponent = std::numeric_limits::min_exponent; + static constexpr int min_exponent10 = std::numeric_limits::min_exponent10; + static constexpr int max_exponent = std::numeric_limits::max_exponent; + static constexpr int max_exponent10 = std::numeric_limits::max_exponent10; + static constexpr bool traps = std::numeric_limits::traps; + static constexpr bool tinyness_before = std::numeric_limits::tinyness_before; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long (min) () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long (max) () { return ULONG_MAX; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long lowest () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long epsilon () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long round_error () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long infinity () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long quiet_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long signaling_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long denorm_min () { return 0; } +}; + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = std::numeric_limits::is_specialized; + static constexpr bool is_signed = std::numeric_limits::is_signed; + static constexpr bool is_integer = std::numeric_limits::is_integer; + static constexpr bool is_exact = std::numeric_limits::is_exact; + static constexpr bool has_infinity = std::numeric_limits::has_infinity; + static constexpr bool has_quiet_NaN = std::numeric_limits::has_quiet_NaN; + static constexpr bool has_signaling_NaN = std::numeric_limits::has_signaling_NaN; + + static constexpr std::float_round_style round_style = std::numeric_limits::round_style; + static constexpr bool is_iec559 = std::numeric_limits::is_iec559; + static constexpr bool is_bounded = std::numeric_limits::is_bounded; + static constexpr bool is_modulo = std::numeric_limits::is_modulo; + static constexpr int digits = std::numeric_limits::digits; + static constexpr int digits10 = std::numeric_limits::digits10; + static constexpr int max_digits10 = std::numeric_limits::max_digits10; + static constexpr int radix = std::numeric_limits::radix; + static constexpr int min_exponent = std::numeric_limits::min_exponent; + static constexpr int min_exponent10 = std::numeric_limits::min_exponent10; + static constexpr int max_exponent = std::numeric_limits::max_exponent; + static constexpr int max_exponent10 = std::numeric_limits::max_exponent10; + static constexpr bool traps = std::numeric_limits::traps; + static constexpr bool tinyness_before = std::numeric_limits::tinyness_before; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr long long (min) () { return LLONG_MIN; } + BOOST_CRYPT_GPU_ENABLED static constexpr long long (max) () { return LLONG_MAX; } + BOOST_CRYPT_GPU_ENABLED static constexpr long long lowest () { return LLONG_MIN; } + BOOST_CRYPT_GPU_ENABLED static constexpr long long epsilon () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr long long round_error () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr long long infinity () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr long long quiet_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr long long signaling_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr long long denorm_min () { return 0; } +}; + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = std::numeric_limits::is_specialized; + static constexpr bool is_signed = std::numeric_limits::is_signed; + static constexpr bool is_integer = std::numeric_limits::is_integer; + static constexpr bool is_exact = std::numeric_limits::is_exact; + static constexpr bool has_infinity = std::numeric_limits::has_infinity; + static constexpr bool has_quiet_NaN = std::numeric_limits::has_quiet_NaN; + static constexpr bool has_signaling_NaN = std::numeric_limits::has_signaling_NaN; + + static constexpr std::float_round_style round_style = std::numeric_limits::round_style; + static constexpr bool is_iec559 = std::numeric_limits::is_iec559; + static constexpr bool is_bounded = std::numeric_limits::is_bounded; + static constexpr bool is_modulo = std::numeric_limits::is_modulo; + static constexpr int digits = std::numeric_limits::digits; + static constexpr int digits10 = std::numeric_limits::digits10; + static constexpr int max_digits10 = std::numeric_limits::max_digits10; + static constexpr int radix = std::numeric_limits::radix; + static constexpr int min_exponent = std::numeric_limits::min_exponent; + static constexpr int min_exponent10 = std::numeric_limits::min_exponent10; + static constexpr int max_exponent = std::numeric_limits::max_exponent; + static constexpr int max_exponent10 = std::numeric_limits::max_exponent10; + static constexpr bool traps = std::numeric_limits::traps; + static constexpr bool tinyness_before = std::numeric_limits::tinyness_before; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long long (min) () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long long (max) () { return ULLONG_MAX; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long long lowest () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long long epsilon () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long long round_error () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long long infinity () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long long quiet_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long long signaling_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long long denorm_min () { return 0; } +}; + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = std::numeric_limits::is_specialized; + static constexpr bool is_signed = std::numeric_limits::is_signed; + static constexpr bool is_integer = std::numeric_limits::is_integer; + static constexpr bool is_exact = std::numeric_limits::is_exact; + static constexpr bool has_infinity = std::numeric_limits::has_infinity; + static constexpr bool has_quiet_NaN = std::numeric_limits::has_quiet_NaN; + static constexpr bool has_signaling_NaN = std::numeric_limits::has_signaling_NaN; + + static constexpr std::float_round_style round_style = std::numeric_limits::round_style; + static constexpr bool is_iec559 = std::numeric_limits::is_iec559; + static constexpr bool is_bounded = std::numeric_limits::is_bounded; + static constexpr bool is_modulo = std::numeric_limits::is_modulo; + static constexpr int digits = std::numeric_limits::digits; + static constexpr int digits10 = std::numeric_limits::digits10; + static constexpr int max_digits10 = std::numeric_limits::max_digits10; + static constexpr int radix = std::numeric_limits::radix; + static constexpr int min_exponent = std::numeric_limits::min_exponent; + static constexpr int min_exponent10 = std::numeric_limits::min_exponent10; + static constexpr int max_exponent = std::numeric_limits::max_exponent; + static constexpr int max_exponent10 = std::numeric_limits::max_exponent10; + static constexpr bool traps = std::numeric_limits::traps; + static constexpr bool tinyness_before = std::numeric_limits::tinyness_before; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr bool (min) () { return false; } + BOOST_CRYPT_GPU_ENABLED static constexpr bool (max) () { return true; } + BOOST_CRYPT_GPU_ENABLED static constexpr bool lowest () { return false; } + BOOST_CRYPT_GPU_ENABLED static constexpr bool epsilon () { return false; } + BOOST_CRYPT_GPU_ENABLED static constexpr bool round_error () { return false; } + BOOST_CRYPT_GPU_ENABLED static constexpr bool infinity () { return false; } + BOOST_CRYPT_GPU_ENABLED static constexpr bool quiet_NaN () { return false; } + BOOST_CRYPT_GPU_ENABLED static constexpr bool signaling_NaN () { return false; } + BOOST_CRYPT_GPU_ENABLED static constexpr bool denorm_min () { return false; } +}; + +#elif defined(BOOST_CRYPT_HAS_NVRTC) // Pure NVRTC support - Removes rounding style and approximates the traits + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = true; + static constexpr bool is_signed = true; + static constexpr bool is_integer = false; + static constexpr bool is_exact = false; + static constexpr bool has_infinity = true; + static constexpr bool has_quiet_NaN = true; + static constexpr bool has_signaling_NaN = true; + + static constexpr bool is_iec559 = true; + static constexpr bool is_bounded = true; + static constexpr bool is_modulo = false; + static constexpr int digits = 24; + static constexpr int digits10 = 6; + static constexpr int max_digits10 = 9; + static constexpr int radix = 2; + static constexpr int min_exponent = -125; + static constexpr int min_exponent10 = -37; + static constexpr int max_exponent = 128; + static constexpr int max_exponent10 = 38; + static constexpr bool traps = false; + static constexpr bool tinyness_before = false; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr float (min) () { return 1.17549435e-38F; } + BOOST_CRYPT_GPU_ENABLED static constexpr float (max) () { return 3.40282347e+38F; } + BOOST_CRYPT_GPU_ENABLED static constexpr float lowest () { return -3.40282347e+38F; } + BOOST_CRYPT_GPU_ENABLED static constexpr float epsilon () { return 1.1920929e-07; } + BOOST_CRYPT_GPU_ENABLED static constexpr float round_error () { return 0.5F; } + BOOST_CRYPT_GPU_ENABLED static constexpr float infinity () { return __int_as_float(0x7f800000); } + BOOST_CRYPT_GPU_ENABLED static constexpr float quiet_NaN () { return __int_as_float(0x7fc00000); } + BOOST_CRYPT_GPU_ENABLED static constexpr float signaling_NaN () { return __int_as_float(0x7fa00000); } + BOOST_CRYPT_GPU_ENABLED static constexpr float denorm_min () { return 1.4013e-45F; } +}; + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = true; + static constexpr bool is_signed = true; + static constexpr bool is_integer = false; + static constexpr bool is_exact = false; + static constexpr bool has_infinity = true; + static constexpr bool has_quiet_NaN = true; + static constexpr bool has_signaling_NaN = true; + + static constexpr bool is_iec559 = true; + static constexpr bool is_bounded = true; + static constexpr bool is_modulo = false; + static constexpr int digits = 53; + static constexpr int digits10 = 15; + static constexpr int max_digits10 = 21; + static constexpr int radix = 2; + static constexpr int min_exponent = -1021; + static constexpr int min_exponent10 = -307; + static constexpr int max_exponent = 1024; + static constexpr int max_exponent10 = 308; + static constexpr bool traps = false; + static constexpr bool tinyness_before = false; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr double (min) () { return 2.2250738585072014e-308; } + BOOST_CRYPT_GPU_ENABLED static constexpr double (max) () { return 1.7976931348623157e+308; } + BOOST_CRYPT_GPU_ENABLED static constexpr double lowest () { return -1.7976931348623157e+308; } + BOOST_CRYPT_GPU_ENABLED static constexpr double epsilon () { return 2.2204460492503131e-16; } + BOOST_CRYPT_GPU_ENABLED static constexpr double round_error () { return 0.5; } + BOOST_CRYPT_GPU_ENABLED static constexpr double infinity () { return __longlong_as_double(0x7ff0000000000000ULL); } + BOOST_CRYPT_GPU_ENABLED static constexpr double quiet_NaN () { return __longlong_as_double(0x7ff8000000000000ULL); } + BOOST_CRYPT_GPU_ENABLED static constexpr double signaling_NaN () { return __longlong_as_double(0x7ff4000000000000ULL); } + BOOST_CRYPT_GPU_ENABLED static constexpr double denorm_min () { return 4.9406564584124654e-324; } +}; + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = true; + static constexpr bool is_signed = true; + static constexpr bool is_integer = true; + static constexpr bool is_exact = true; + static constexpr bool has_infinity = false; + static constexpr bool has_quiet_NaN = false; + static constexpr bool has_signaling_NaN = false; + + static constexpr bool is_iec559 = false; + static constexpr bool is_bounded = true; + static constexpr bool is_modulo = false; + static constexpr int digits = 15; + static constexpr int digits10 = 4; + static constexpr int max_digits10 = 0; + static constexpr int radix = 2; + static constexpr int min_exponent = 0; + static constexpr int min_exponent10 = 0; + static constexpr int max_exponent = 0; + static constexpr int max_exponent10 = 0; + static constexpr bool traps = true; + static constexpr bool tinyness_before = false; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr short (min) () { return -32768; } + BOOST_CRYPT_GPU_ENABLED static constexpr short (max) () { return 32767; } + BOOST_CRYPT_GPU_ENABLED static constexpr short lowest () { return -32768; } + BOOST_CRYPT_GPU_ENABLED static constexpr short epsilon () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr short round_error () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr short infinity () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr short quiet_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr short signaling_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr short denorm_min () { return 0; } +}; + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = true; + static constexpr bool is_signed = false; + static constexpr bool is_integer = true; + static constexpr bool is_exact = true; + static constexpr bool has_infinity = false; + static constexpr bool has_quiet_NaN = false; + static constexpr bool has_signaling_NaN = false; + + static constexpr bool is_iec559 = false; + static constexpr bool is_bounded = true; + static constexpr bool is_modulo = true; + static constexpr int digits = 16; + static constexpr int digits10 = 4; + static constexpr int max_digits10 = 0; + static constexpr int radix = 2; + static constexpr int min_exponent = 0; + static constexpr int min_exponent10 = 0; + static constexpr int max_exponent = 0; + static constexpr int max_exponent10 = 0; + static constexpr bool traps = true; + static constexpr bool tinyness_before = false; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned short (min) () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned short (max) () { return 65535U; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned short lowest () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned short epsilon () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned short round_error () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned short infinity () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned short quiet_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned short signaling_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned short denorm_min () { return 0; } +}; + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = true; + static constexpr bool is_signed = true; + static constexpr bool is_integer = true; + static constexpr bool is_exact = true; + static constexpr bool has_infinity = false; + static constexpr bool has_quiet_NaN = false; + static constexpr bool has_signaling_NaN = false; + + static constexpr bool is_iec559 = false; + static constexpr bool is_bounded = true; + static constexpr bool is_modulo = false; + static constexpr int digits = 31; + static constexpr int digits10 = 9; + static constexpr int max_digits10 = 0; + static constexpr int radix = 2; + static constexpr int min_exponent = 0; + static constexpr int min_exponent10 = 0; + static constexpr int max_exponent = 0; + static constexpr int max_exponent10 = 0; + static constexpr bool traps = true; + static constexpr bool tinyness_before = false; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr int (min) () { return -2147483648; } + BOOST_CRYPT_GPU_ENABLED static constexpr int (max) () { return 2147483647; } + BOOST_CRYPT_GPU_ENABLED static constexpr int lowest () { return -2147483648; } + BOOST_CRYPT_GPU_ENABLED static constexpr int epsilon () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr int round_error () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr int infinity () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr int quiet_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr int signaling_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr int denorm_min () { return 0; } +}; + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = true; + static constexpr bool is_signed = false; + static constexpr bool is_integer = true; + static constexpr bool is_exact = true; + static constexpr bool has_infinity = false; + static constexpr bool has_quiet_NaN = false; + static constexpr bool has_signaling_NaN = false; + + static constexpr bool is_iec559 = false; + static constexpr bool is_bounded = true; + static constexpr bool is_modulo = true; + static constexpr int digits = 32; + static constexpr int digits10 = 9; + static constexpr int max_digits10 = 0; + static constexpr int radix = 2; + static constexpr int min_exponent = 0; + static constexpr int min_exponent10 = 0; + static constexpr int max_exponent = 0; + static constexpr int max_exponent10 = 0; + static constexpr bool traps = true; + static constexpr bool tinyness_before = false; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned int (min) () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned int (max) () { return 4294967295U; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned int lowest () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned int epsilon () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned int round_error () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned int infinity () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned int quiet_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned int signaling_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned int denorm_min () { return 0; } +}; + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = true; + static constexpr bool is_signed = true; + static constexpr bool is_integer = true; + static constexpr bool is_exact = true; + static constexpr bool has_infinity = false; + static constexpr bool has_quiet_NaN = false; + static constexpr bool has_signaling_NaN = false; + + static constexpr bool is_iec559 = false; + static constexpr bool is_bounded = true; + static constexpr bool is_modulo = false; + static constexpr int digits = 63; + static constexpr int digits10 = 18; + static constexpr int max_digits10 = 0; + static constexpr int radix = 2; + static constexpr int min_exponent = 0; + static constexpr int min_exponent10 = 0; + static constexpr int max_exponent = 0; + static constexpr int max_exponent10 = 0; + static constexpr bool traps = true; + static constexpr bool tinyness_before = false; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr long (min) () { return -9223372036854775808L; } + BOOST_CRYPT_GPU_ENABLED static constexpr long (max) () { return 9223372036854775807L; } + BOOST_CRYPT_GPU_ENABLED static constexpr long lowest () { return -9223372036854775808L; } + BOOST_CRYPT_GPU_ENABLED static constexpr long epsilon () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr long round_error () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr long infinity () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr long quiet_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr long signaling_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr long denorm_min () { return 0; } +}; + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = true; + static constexpr bool is_signed = false; + static constexpr bool is_integer = true; + static constexpr bool is_exact = true; + static constexpr bool has_infinity = false; + static constexpr bool has_quiet_NaN = false; + static constexpr bool has_signaling_NaN = false; + + static constexpr bool is_iec559 = false; + static constexpr bool is_bounded = true; + static constexpr bool is_modulo = true; + static constexpr int digits = 64; + static constexpr int digits10 = 19; + static constexpr int max_digits10 = 0; + static constexpr int radix = 2; + static constexpr int min_exponent = 0; + static constexpr int min_exponent10 = 0; + static constexpr int max_exponent = 0; + static constexpr int max_exponent10 = 0; + static constexpr bool traps = true; + static constexpr bool tinyness_before = false; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long (min) () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long (max) () { return 18446744073709551615UL; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long lowest () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long epsilon () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long round_error () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long infinity () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long quiet_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long signaling_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long denorm_min () { return 0; } +}; + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = true; + static constexpr bool is_signed = true; + static constexpr bool is_integer = true; + static constexpr bool is_exact = true; + static constexpr bool has_infinity = false; + static constexpr bool has_quiet_NaN = false; + static constexpr bool has_signaling_NaN = false; + + static constexpr bool is_iec559 = false; + static constexpr bool is_bounded = true; + static constexpr bool is_modulo = false; + static constexpr int digits = 63; + static constexpr int digits10 = 18; + static constexpr int max_digits10 = 0; + static constexpr int radix = 2; + static constexpr int min_exponent = 0; + static constexpr int min_exponent10 = 0; + static constexpr int max_exponent = 0; + static constexpr int max_exponent10 = 0; + static constexpr bool traps = true; + static constexpr bool tinyness_before = false; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr long long (min) () { return -9223372036854775808LL; } + BOOST_CRYPT_GPU_ENABLED static constexpr long long (max) () { return 9223372036854775807LL; } + BOOST_CRYPT_GPU_ENABLED static constexpr long long lowest () { return -9223372036854775808LL; } + BOOST_CRYPT_GPU_ENABLED static constexpr long long epsilon () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr long long round_error () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr long long infinity () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr long long quiet_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr long long signaling_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr long long denorm_min () { return 0; } +}; + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = true; + static constexpr bool is_signed = false; + static constexpr bool is_integer = true; + static constexpr bool is_exact = true; + static constexpr bool has_infinity = false; + static constexpr bool has_quiet_NaN = false; + static constexpr bool has_signaling_NaN = false; + + static constexpr bool is_iec559 = false; + static constexpr bool is_bounded = true; + static constexpr bool is_modulo = true; + static constexpr int digits = 64; + static constexpr int digits10 = 19; + static constexpr int max_digits10 = 0; + static constexpr int radix = 2; + static constexpr int min_exponent = 0; + static constexpr int min_exponent10 = 0; + static constexpr int max_exponent = 0; + static constexpr int max_exponent10 = 0; + static constexpr bool traps = true; + static constexpr bool tinyness_before = false; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long long (min) () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long long (max) () { return 18446744073709551615UL; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long long lowest () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long long epsilon () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long long round_error () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long long infinity () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long long quiet_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long long signaling_NaN () { return 0; } + BOOST_CRYPT_GPU_ENABLED static constexpr unsigned long long denorm_min () { return 0; } +}; + +template <> +struct numeric_limits +{ + static constexpr bool is_specialized = true; + static constexpr bool is_signed = false; + static constexpr bool is_integer = true; + static constexpr bool is_exact = true; + static constexpr bool has_infinity = false; + static constexpr bool has_quiet_NaN = false; + static constexpr bool has_signaling_NaN = false; + + static constexpr bool is_iec559 = false; + static constexpr bool is_bounded = true; + static constexpr bool is_modulo = false; + static constexpr int digits = 1; + static constexpr int digits10 = 0; + static constexpr int max_digits10 = 0; + static constexpr int radix = 2; + static constexpr int min_exponent = 0; + static constexpr int min_exponent10 = 0; + static constexpr int max_exponent = 0; + static constexpr int max_exponent10 = 0; + static constexpr bool traps = false; + static constexpr bool tinyness_before = false; + + // Member Functions + BOOST_CRYPT_GPU_ENABLED static constexpr bool (min) () { return false; } + BOOST_CRYPT_GPU_ENABLED static constexpr bool (max) () { return true; } + BOOST_CRYPT_GPU_ENABLED static constexpr bool lowest () { return false; } + BOOST_CRYPT_GPU_ENABLED static constexpr bool epsilon () { return false; } + BOOST_CRYPT_GPU_ENABLED static constexpr bool round_error () { return false; } + BOOST_CRYPT_GPU_ENABLED static constexpr bool infinity () { return false; } + BOOST_CRYPT_GPU_ENABLED static constexpr bool quiet_NaN () { return false; } + BOOST_CRYPT_GPU_ENABLED static constexpr bool signaling_NaN () { return false; } + BOOST_CRYPT_GPU_ENABLED static constexpr bool denorm_min () { return false; } +}; + +#endif // BOOST_CRYPT_HAS_CUDA + +} // namespace crypt +} // namespace boost + +#endif // BOOST_CRYPT_UTILITY_LIMITS_HPP From 01c12c0802b9de080e605e0976961069e4827e14 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 9 Oct 2024 11:55:52 -0400 Subject: [PATCH 037/107] Refactor naming --- include/boost/crypt/utility/array.hpp | 2 +- include/boost/crypt/utility/concepts.hpp | 4 ---- include/boost/crypt/utility/cstdint.hpp | 2 +- include/boost/crypt/utility/type_traits.hpp | 2 +- 4 files changed, 3 insertions(+), 7 deletions(-) diff --git a/include/boost/crypt/utility/array.hpp b/include/boost/crypt/utility/array.hpp index f2ab2af..fdeeee7 100644 --- a/include/boost/crypt/utility/array.hpp +++ b/include/boost/crypt/utility/array.hpp @@ -8,7 +8,7 @@ #include -#ifdef BOOST_CRYPT_ENABLE_CUDA +#ifdef BOOST_CRYPT_HAS_CUDA #include diff --git a/include/boost/crypt/utility/concepts.hpp b/include/boost/crypt/utility/concepts.hpp index 889f724..069598c 100644 --- a/include/boost/crypt/utility/concepts.hpp +++ b/include/boost/crypt/utility/concepts.hpp @@ -7,10 +7,6 @@ #include -#ifndef BOOST_CRYPT_BUILD_MODULE -#include -#endif - // GCC-11 yields internal compiler errors when using the concepts /* diff --git a/include/boost/crypt/utility/cstdint.hpp b/include/boost/crypt/utility/cstdint.hpp index 5863fc4..975230a 100644 --- a/include/boost/crypt/utility/cstdint.hpp +++ b/include/boost/crypt/utility/cstdint.hpp @@ -8,7 +8,7 @@ #include -#ifdef BOOST_CRYPT_ENABLE_CUDA +#ifdef BOOST_CRYPT_HAS_CUDA #include diff --git a/include/boost/crypt/utility/type_traits.hpp b/include/boost/crypt/utility/type_traits.hpp index 5e78db7..9463549 100644 --- a/include/boost/crypt/utility/type_traits.hpp +++ b/include/boost/crypt/utility/type_traits.hpp @@ -12,7 +12,7 @@ #include -#ifdef BOOST_CRYPT_ENABLE_CUDA +#ifdef BOOST_CRYPT_HAS_CUDA #include From ea8af67565ef0ef088a07aba4c063ae199945a50 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 9 Oct 2024 11:59:02 -0400 Subject: [PATCH 038/107] Add cuda to bit utils --- include/boost/crypt/utility/bit.hpp | 38 ++++++++++++++--------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/include/boost/crypt/utility/bit.hpp b/include/boost/crypt/utility/bit.hpp index 55fe9dc..55b2ec4 100644 --- a/include/boost/crypt/utility/bit.hpp +++ b/include/boost/crypt/utility/bit.hpp @@ -2,34 +2,34 @@ // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt -#ifndef BOOST_BIT_HPP -#define BOOST_BIT_HPP +#ifndef BOOST_CRYPT_UTILITY_BIT_HPP +#define BOOST_CRYPT_UTILITY_BIT_HPP #include -#include -#include -#include +#include +#include +#include namespace boost { namespace crypt { namespace detail { // Forward decls -template ::value, bool> = true> +template ::value, bool> = true> constexpr T rotl(T x, U s) noexcept; -template ::value, bool> = true> +template ::value, bool> = true> constexpr T rotl(T x, U s) noexcept; -template ::value, bool> = true> +template ::value, bool> = true> constexpr T rotr(T x, U s) noexcept; -template ::value, bool> = true> +template ::value, bool> = true> constexpr T rotr(T x, U s) noexcept; // Only works for unsigned s so we can optimize away the call to rotr -template ::value, bool>> +template ::value, bool>> constexpr T rotl(T x, U s) noexcept { - constexpr auto N {std::numeric_limits::digits}; + constexpr auto N {boost::crypt::numeric_limits::digits}; const auto r {s % N}; if (r == 0) @@ -40,10 +40,10 @@ constexpr T rotl(T x, U s) noexcept return (x << r) | (x >> (N - r)); } -template ::value, bool>> +template ::value, bool>> constexpr T rotl(T x, U s) noexcept { - constexpr auto N {std::numeric_limits::digits}; + constexpr auto N {boost::crypt::numeric_limits::digits}; const auto r {s % N}; if (r == 0) @@ -58,10 +58,10 @@ constexpr T rotl(T x, U s) noexcept return (x << r) | (x >> (N - r)); } -template ::value, bool>> +template ::value, bool>> constexpr T rotr(T x, U s) noexcept { - constexpr auto N {std::numeric_limits::digits}; + constexpr auto N {boost::crypt::numeric_limits::digits}; const auto r {s % N}; if (r == 0) @@ -72,10 +72,10 @@ constexpr T rotr(T x, U s) noexcept return (x >> r) | (x << (N - r)); } -template ::value, bool>> +template ::value, bool>> constexpr T rotr(T x, U s) noexcept { - constexpr auto N {std::numeric_limits::digits}; + constexpr auto N {boost::crypt::numeric_limits::digits}; const auto r {s % N}; if (r == 0) @@ -90,7 +90,7 @@ constexpr T rotr(T x, U s) noexcept return (x >> r) | (x << (N - r)); } -constexpr auto swap_endian(const std::uint32_t val) -> std::uint32_t +constexpr auto swap_endian(const boost::crypt::uint32_t val) -> boost::crypt::uint32_t { return ((val & 0xFF000000) >> 24U) | ((val & 0x00FF0000) >> 8U) | @@ -102,4 +102,4 @@ constexpr auto swap_endian(const std::uint32_t val) -> std::uint32_t } // namespace crypt } // namespace boost -#endif //BOOST_BIT_HPP +#endif //BOOST_CRYPT_UTILITY_BIT_HPP From 5744e7656c66e538f20996885ec6f28178d9b5db Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 9 Oct 2024 11:59:44 -0400 Subject: [PATCH 039/107] Make a byte CUDA capable --- include/boost/crypt/utility/byte.hpp | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/include/boost/crypt/utility/byte.hpp b/include/boost/crypt/utility/byte.hpp index 43a8453..1856801 100644 --- a/include/boost/crypt/utility/byte.hpp +++ b/include/boost/crypt/utility/byte.hpp @@ -7,10 +7,7 @@ #include #include - -#ifndef BOOST_CRYPT_BUILD_MODULE -#include -#endif +#include namespace boost { namespace crypt { @@ -18,11 +15,11 @@ namespace crypt { class byte { private: - std::uint8_t bits_; + boost::crypt::uint8_t bits_; public: constexpr byte() noexcept : bits_ {} {} - explicit constexpr byte(std::uint8_t bits) noexcept : bits_ {bits} {} + explicit constexpr byte(boost::crypt::uint8_t bits) noexcept : bits_ {bits} {} template constexpr auto to_integer() noexcept @@ -47,22 +44,22 @@ class byte constexpr auto operator|(byte rhs) const noexcept -> byte { - return byte{static_cast(bits_ | rhs.bits_)}; + return byte{static_cast(bits_ | rhs.bits_)}; } constexpr auto operator&(byte rhs) const noexcept -> byte { - return byte{static_cast(bits_ & rhs.bits_)}; + return byte{static_cast(bits_ & rhs.bits_)}; } constexpr auto operator^(byte rhs) const noexcept -> byte { - return byte{static_cast(bits_ ^ rhs.bits_)}; + return byte{static_cast(bits_ ^ rhs.bits_)}; } constexpr auto operator~() const noexcept -> byte { - return byte{static_cast(~bits_)}; + return byte{static_cast(~bits_)}; } template @@ -83,19 +80,19 @@ class byte constexpr auto operator|(byte rhs) noexcept -> byte& { - bits_ = static_cast(bits_ | rhs.bits_); + bits_ = static_cast(bits_ | rhs.bits_); return *this; } constexpr auto operator&(byte rhs) noexcept -> byte& { - bits_ = static_cast(bits_ & rhs.bits_); + bits_ = static_cast(bits_ & rhs.bits_); return *this; } constexpr auto operator^(byte rhs) noexcept -> byte& { - bits_ = static_cast(bits_ ^ rhs.bits_); + bits_ = static_cast(bits_ ^ rhs.bits_); return *this; } From e3a137bd0c87e44ac89a91d99ea528a66b89e772 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 9 Oct 2024 12:08:18 -0400 Subject: [PATCH 040/107] Simplify body function --- include/boost/crypt/hash/md5.hpp | 162 ++++++++++++++++--------------- 1 file changed, 86 insertions(+), 76 deletions(-) diff --git a/include/boost/crypt/hash/md5.hpp b/include/boost/crypt/hash/md5.hpp index 1cdde53..c29179f 100644 --- a/include/boost/crypt/hash/md5.hpp +++ b/include/boost/crypt/hash/md5.hpp @@ -7,6 +7,9 @@ #include #include +#include +#include +#include #include #include @@ -21,14 +24,14 @@ namespace crypt { namespace detail { -static constexpr std::array S { +static constexpr boost::crypt::array S { 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 }; -static constexpr std::array K { +static constexpr boost::crypt::array K { 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, @@ -48,123 +51,130 @@ static constexpr std::array K { }; template -auto md5_preprocess(T begin, T end) -> std::vector +auto md5_preprocess(T begin, T end) -> std::vector { - std::vector vec; - vec.reserve(static_cast(end - begin)); + std::vector vec; + vec.reserve(static_cast(end - begin)); // Like std::copy but gives us the correct cast std::transform(begin, end, std::back_inserter(vec), [](const auto& element) { - return static_cast(element); + return static_cast(element); }); return vec; } template -auto md5_preprocess(T begin, std::size_t len) -> std::vector +auto md5_preprocess(T begin, boost::crypt::size_t len) -> std::vector { - std::vector vec; + std::vector vec; vec.reserve(len); std::transform(begin, begin + len, std::back_inserter(vec), [](const auto& element) { - return static_cast(element); + return static_cast(element); }); return vec; } -auto md5_pad(const std::vector& message) noexcept -> std::vector +auto md5_pad(const std::vector& message) noexcept -> std::vector { - std::vector padded_message {message}; - const std::uint64_t original_length {message.size() * 8U}; - padded_message.emplace_back(static_cast(0x80)); + std::vector padded_message {message}; + const boost::crypt::uint64_t original_length {message.size() * 8U}; + padded_message.emplace_back(static_cast(0x80)); while ((padded_message.size() * 8U) % 512U != 448U) { - padded_message.emplace_back(static_cast(0x00)); + padded_message.emplace_back(static_cast(0x00)); } // Add the original length as a 64-bit number - for (std::size_t i = 0; i < 8; ++i) + for (boost::crypt::size_t i = 0; i < 8; ++i) { - padded_message.emplace_back(static_cast((original_length >> (8 * i)) & 0xFF)); + padded_message.emplace_back(static_cast((original_length >> (8 * i)) & 0xFF)); } return padded_message; } +auto md5_body(const boost::crypt::array& blocks, + boost::crypt::uint32_t& a, boost::crypt::uint32_t& b, + boost::crypt::uint32_t& c, boost::crypt::uint32_t& d) noexcept +{ + boost::crypt::uint32_t A {a}; + boost::crypt::uint32_t B {b}; + boost::crypt::uint32_t C {c}; + boost::crypt::uint32_t D {d}; + + for (boost::crypt::uint32_t i {}; i < 64U; ++i) + { + boost::crypt::uint32_t F {}; + boost::crypt::uint32_t g {}; + + if (i <= 15U) + { + F = (B & C) | ((~B) & D); + g = i; + } + else if (i <= 31U) + { + F = (D & B) | ((~D) & C); + g = (5U * i + 1U) % 16U; + } + else if (i <= 47U) + { + F = B ^ C ^ D; + g = (3U * i + 5U) % 16U; + } + else + { + F = C ^ (B | (~D)); + g = (7U * i) % 16U; + } + + BOOST_CRYPT_ASSERT(i <= 63U); + + F = F + A + K[i] + blocks[g]; + A = D; + D = C; + C = B; + B = B + rotl(F, S[i]); + } + + a += A; + b += B; + c += C; + d += D; +} + template -auto md5_impl(const std::vector& padded_message) -> ResultType +auto md5_impl(const std::vector& padded_message) -> ResultType { - std::uint32_t a0 {0x67452301}; - std::uint32_t b0 {0xefcdab89}; - std::uint32_t c0 {0x98badcfe}; - std::uint32_t d0 {0x10325476}; + boost::crypt::uint32_t a0 {0x67452301}; + boost::crypt::uint32_t b0 {0xefcdab89}; + boost::crypt::uint32_t c0 {0x98badcfe}; + boost::crypt::uint32_t d0 {0x10325476}; - std::array blocks {}; + boost::crypt::array blocks {}; - std::size_t message_chunk {}; + boost::crypt::size_t message_chunk {}; while (message_chunk < padded_message.size()) { for (auto& block : blocks) { - block = static_cast( - (static_cast(padded_message[message_chunk])) + - (static_cast(padded_message[message_chunk + 1U]) << 8U) + - (static_cast(padded_message[message_chunk + 2U]) << 16U) + - (static_cast(padded_message[message_chunk + 3U]) << 24U) + block = static_cast( + (static_cast(padded_message[message_chunk])) + + (static_cast(padded_message[message_chunk + 1U]) << 8U) + + (static_cast(padded_message[message_chunk + 2U]) << 16U) + + (static_cast(padded_message[message_chunk + 3U]) << 24U) ); message_chunk += 4U; } - std::uint32_t A {a0}; - std::uint32_t B {b0}; - std::uint32_t C {c0}; - std::uint32_t D {d0}; - - for (std::uint32_t i {}; i < 64U; ++i) - { - std::uint32_t F {}; - std::uint32_t g {}; - - if (i <= 15U) - { - F = (B & C) | ((~B) & D); - g = i; - } - else if (i <= 31U) - { - F = (D & B) | ((~D) & C); - g = (5U * i + 1U) % 16U; - } - else if (i <= 47U) - { - F = B ^ C ^ D; - g = (3U * i + 5U) % 16U; - } - else - { - F = C ^ (B | (~D)); - g = (7U * i) % 16U; - } - - BOOST_CRYPT_ASSERT(i <= 63U); - - F = F + A + K[i] + blocks[g]; - A = D; - D = C; - C = B; - B = B + rotl(F, S[i]); - } - - a0 += A; - b0 += B; - c0 += C; - d0 += D; + md5_body(blocks, a0, b0, c0, d0); } return ResultType {swap_endian(a0), @@ -175,7 +185,7 @@ auto md5_impl(const std::vector& padded_message) -> ResultType } // namespace detail -template , typename T> +template , typename T> ResultType md5(T begin, T end) { if (end <= begin) @@ -188,7 +198,7 @@ ResultType md5(T begin, T end) return detail::md5_impl(padded_message); } -template > +template > ResultType md5(const char* str) { if (str == nullptr) @@ -202,14 +212,14 @@ ResultType md5(const char* str) return detail::md5_impl(padded_message); } -template > +template > ResultType md5(const std::string& str) { return md5(str.begin(), str.end()); } #ifdef BOOST_CRYPT_HAS_STRING_VIEW -template > +template > ResultType md5(const std::string_view& str) { return md5(str.begin(), str.end()); From 12e6fd04831f520ee528e3811f83da322787cfd1 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 9 Oct 2024 18:41:42 -0400 Subject: [PATCH 041/107] Add unreachable macro --- include/boost/crypt/utility/config.hpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/boost/crypt/utility/config.hpp b/include/boost/crypt/utility/config.hpp index bec8d29..07e0f94 100644 --- a/include/boost/crypt/utility/config.hpp +++ b/include/boost/crypt/utility/config.hpp @@ -70,4 +70,14 @@ #endif // ----- Has CXX something ----- +// ----- Unreachable ----- +#if defined(__GNUC__) || defined(__clang__) +# define BOOST_CRYPT_UNREACHABLE __builtin_unreachable() +#elif defined(_MSC_VER) +# define BOOST_CRYPT_UNREACHABLE __assume(0) +#else +# define BOOST_CRYPT_UNREACHABLE std::abort() +#endif +// ----- Unreachable ----- + #endif //BOOST_CRYPT_DETAIL_CONFIG_HPP From b9b0092383eb7a60dd86febf3b9655b9f08624fd Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 9 Oct 2024 18:42:26 -0400 Subject: [PATCH 042/107] Add iter pair md5 impl --- include/boost/crypt/hash/md5.hpp | 134 ++++++++++++++++++++++++++++++- 1 file changed, 131 insertions(+), 3 deletions(-) diff --git a/include/boost/crypt/hash/md5.hpp b/include/boost/crypt/hash/md5.hpp index c29179f..345902c 100644 --- a/include/boost/crypt/hash/md5.hpp +++ b/include/boost/crypt/hash/md5.hpp @@ -99,6 +99,7 @@ auto md5_pad(const std::vector& message) noexcept -> std: return padded_message; } +// TODO(mborland): Replace the loop with the known statements auto md5_body(const boost::crypt::array& blocks, boost::crypt::uint32_t& a, boost::crypt::uint32_t& b, boost::crypt::uint32_t& c, boost::crypt::uint32_t& d) noexcept @@ -183,6 +184,135 @@ auto md5_impl(const std::vector& padded_message) -> Resul swap_endian(d0)}; } +template +auto md5_impl(ForwardIterator first, ForwardIterator last) -> ResultType +{ + boost::crypt::uint32_t a0 {0x67452301}; + boost::crypt::uint32_t b0 {0xefcdab89}; + boost::crypt::uint32_t c0 {0x98badcfe}; + boost::crypt::uint32_t d0 {0x10325476}; + + boost::crypt::array blocks {}; + + do + { + if (first + 64U <= last) + { + for (auto& block : blocks) + { + block = static_cast( + static_cast(*first) + + (static_cast(*(first + 1U)) << 8U) + + (static_cast(*(first + 2U)) << 16U) + + (static_cast(*(first + 3U)) << 24U) + ); + + first += 4U; + } + } + else + { + // We need to conclude the message correctly with padding, and the message length + const auto message_length {static_cast(last - first) * 8UL}; + + boost::crypt::size_t current_block {}; + while (first + 4U < last) + { + blocks[current_block] = static_cast( + static_cast(*first) + + (static_cast(*(first + 1U)) << 8U) + + (static_cast(*(first + 2U)) << 16U) + + (static_cast(*(first + 3U)) << 24U) + ); + + first += 4U; + ++current_block; + } + + // Need to tack on the 0x80 as the last byte after the message + switch (last - first) + { + case 0: + blocks[current_block] = static_cast(0x80); + ++current_block; + break; + case 1: + blocks[current_block] = static_cast( + static_cast(*first) + + (static_cast(0x80) << 8U) + ); + ++current_block; + ++first; + break; + case 2: + blocks[current_block] = static_cast( + static_cast(*first) + + (static_cast(*(first + 1U)) << 8U) + + (static_cast(0x80) << 16U) + ); + ++current_block; + first += 2U; + break; + case 3: + blocks[current_block] = static_cast( + static_cast(*first) + + (static_cast(*(first + 1U)) << 8U) + + (static_cast(*(first + 2U)) << 16U) + + (static_cast(0x80) << 24U) + ); + ++current_block; + first += 3U; + break; + // LCOV_EXCL_START + default: + BOOST_CRYPT_UNREACHABLE; + // LCOV_EXCL_STOP + } + + while (current_block < 14U) + { + // Zero Pad + blocks[current_block] = static_cast(0x0); + ++current_block; + } + + // Now we need add the original string length + if (current_block == 14U) + { + blocks[current_block] = static_cast(message_length & 0xFFFFFFFF); + blocks[current_block + 1] = static_cast((message_length >> 32) & 0xFFFFFFFF); + } + else + { + // We need to do another loop + BOOST_CRYPT_ASSERT(current_block == 15U); + blocks[current_block] = static_cast(0x0); + md5_body(blocks, a0, b0, c0, d0); + + // The length is always last + current_block = 0; + ++current_block; + while (current_block < 14U) + { + blocks[current_block] = static_cast(0x0); + ++current_block; + } + + blocks[current_block] = static_cast(message_length & 0xFFFFFFFF); + blocks[current_block + 1] = static_cast((message_length >> 32) & 0xFFFFFFFF); + } + } + + md5_body(blocks, a0, b0, c0, d0); + + } while (first != last); + + return ResultType {swap_endian(a0), + swap_endian(b0), + swap_endian(c0), + swap_endian(d0)}; +} + } // namespace detail template , typename T> @@ -207,9 +337,7 @@ ResultType md5(const char* str) } const auto message_len {std::strlen(str)}; - const auto message {detail::md5_preprocess(str, message_len)}; - const auto padded_message {detail::md5_pad(message)}; - return detail::md5_impl(padded_message); + return detail::md5_impl(str, str + message_len); } template > From 2a07c51f01c0eb5b35ed4b213a725dc239e6371d Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 9 Oct 2024 19:11:00 -0400 Subject: [PATCH 043/107] Simplifications and corrections --- include/boost/crypt/hash/md5.hpp | 125 +++++++++++++------------------ 1 file changed, 52 insertions(+), 73 deletions(-) diff --git a/include/boost/crypt/hash/md5.hpp b/include/boost/crypt/hash/md5.hpp index 345902c..10029de 100644 --- a/include/boost/crypt/hash/md5.hpp +++ b/include/boost/crypt/hash/md5.hpp @@ -187,6 +187,7 @@ auto md5_impl(const std::vector& padded_message) -> Resul template auto md5_impl(ForwardIterator first, ForwardIterator last) -> ResultType { + // Initial MD5 buffer values boost::crypt::uint32_t a0 {0x67452301}; boost::crypt::uint32_t b0 {0xefcdab89}; boost::crypt::uint32_t c0 {0x98badcfe}; @@ -194,14 +195,26 @@ auto md5_impl(ForwardIterator first, ForwardIterator last) -> ResultType boost::crypt::array blocks {}; - do + // Store the original 'first' to compute the total message length + const auto total_message_length {static_cast(last - first) * 8UL}; + + // Handles the empty case with known values + if (first == last) + { + return ResultType{0xd41d8cd9, 0x8f00b204, 0xe9800998, 0xecf8427e}; + } + + while (first != last) { - if (first + 64U <= last) + boost::crypt::size_t current_block = 0; + + // Process as many full 64-byte blocks as possible + if (last - first >= 64) { for (auto& block : blocks) { block = static_cast( - static_cast(*first) + + static_cast(*first) + (static_cast(*(first + 1U)) << 8U) + (static_cast(*(first + 2U)) << 16U) + (static_cast(*(first + 3U)) << 24U) @@ -209,14 +222,16 @@ auto md5_impl(ForwardIterator first, ForwardIterator last) -> ResultType first += 4U; } + md5_body(blocks, a0, b0, c0, d0); } else { - // We need to conclude the message correctly with padding, and the message length - const auto message_length {static_cast(last - first) * 8UL}; + // Process remaining bytes + // Initialize blocks to zero + blocks.fill(0); - boost::crypt::size_t current_block {}; - while (first + 4U < last) + // Process complete 4-byte chunks + while (last - first >= 4) { blocks[current_block] = static_cast( static_cast(*first) + @@ -229,83 +244,47 @@ auto md5_impl(ForwardIterator first, ForwardIterator last) -> ResultType ++current_block; } - // Need to tack on the 0x80 as the last byte after the message - switch (last - first) + // Process remaining bytes (less than 4) + blocks[current_block] = 0; + auto byte_offset = 0U; + while (first != last) { - case 0: - blocks[current_block] = static_cast(0x80); - ++current_block; - break; - case 1: - blocks[current_block] = static_cast( - static_cast(*first) + - (static_cast(0x80) << 8U) - ); - ++current_block; - ++first; - break; - case 2: - blocks[current_block] = static_cast( - static_cast(*first) + - (static_cast(*(first + 1U)) << 8U) + - (static_cast(0x80) << 16U) - ); - ++current_block; - first += 2U; - break; - case 3: - blocks[current_block] = static_cast( - static_cast(*first) + - (static_cast(*(first + 1U)) << 8U) + - (static_cast(*(first + 2U)) << 16U) + - (static_cast(0x80) << 24U) - ); - ++current_block; - first += 3U; - break; - // LCOV_EXCL_START - default: - BOOST_CRYPT_UNREACHABLE; - // LCOV_EXCL_STOP + blocks[current_block] |= static_cast(*first) << (8U * byte_offset); + ++first; + ++byte_offset; } - while (current_block < 14U) - { - // Zero Pad - blocks[current_block] = static_cast(0x0); - ++current_block; - } + // Append the '1' bit (0x80) after the last byte + blocks[current_block] |= static_cast(0x80) << (8U * byte_offset); + ++current_block; - // Now we need add the original string length - if (current_block == 14U) - { - blocks[current_block] = static_cast(message_length & 0xFFFFFFFF); - blocks[current_block + 1] = static_cast((message_length >> 32) & 0xFFFFFFFF); - } - else + // Check if there is enough space to append the length + if (current_block > 14U) { - // We need to do another loop - BOOST_CRYPT_ASSERT(current_block == 15U); - blocks[current_block] = static_cast(0x0); + // Not enough space, process this block and start a new one md5_body(blocks, a0, b0, c0, d0); - - // The length is always last + blocks.fill(0); current_block = 0; + } + + // Pad with zeros until block[14] + while (current_block < 14U) + { + blocks[current_block] = 0; ++current_block; - while (current_block < 14U) - { - blocks[current_block] = static_cast(0x0); - ++current_block; - } - - blocks[current_block] = static_cast(message_length & 0xFFFFFFFF); - blocks[current_block + 1] = static_cast((message_length >> 32) & 0xFFFFFFFF); } - } - md5_body(blocks, a0, b0, c0, d0); + // Append the 64-bit length in bits in little-endian format + blocks[14] = static_cast(total_message_length & 0xFFFFFFFF); + blocks[15] = static_cast((total_message_length >> 32) & 0xFFFFFFFF); + + // Process the final block + md5_body(blocks, a0, b0, c0, d0); - } while (first != last); + // Break out of the loop as we've processed all data + break; + } + } return ResultType {swap_endian(a0), swap_endian(b0), From b51d2801d1feeb124fa79a45a252d9f8e874155b Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 9 Oct 2024 19:24:58 -0400 Subject: [PATCH 044/107] Fix conversion warning --- include/boost/crypt/utility/byte.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/crypt/utility/byte.hpp b/include/boost/crypt/utility/byte.hpp index 1856801..cf39298 100644 --- a/include/boost/crypt/utility/byte.hpp +++ b/include/boost/crypt/utility/byte.hpp @@ -98,7 +98,7 @@ class byte constexpr auto operator~() noexcept -> byte& { - bits_ = ~bits_; + bits_ = static_cast(~bits_); return *this; } }; From 20ccddac69e2b966875462d59e6a2c8df03609a5 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 9 Oct 2024 19:25:05 -0400 Subject: [PATCH 045/107] Fix concept namespace --- include/boost/crypt/utility/concepts.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/crypt/utility/concepts.hpp b/include/boost/crypt/utility/concepts.hpp index 069598c..3c05c3a 100644 --- a/include/boost/crypt/utility/concepts.hpp +++ b/include/boost/crypt/utility/concepts.hpp @@ -50,7 +50,7 @@ namespace boost::crypt::concepts { template -concept integral = boost::crypt::detail::is_integral_v; +concept integral = boost::crypt::is_integral_v; template concept signed_integral = integral && boost::crypt::is_signed_v; @@ -59,7 +59,7 @@ template concept unsigned_integral = integral && boost::crypt::is_unsigned_v; template -concept real = boost::crypt::detail::is_floating_point_v; +concept real = boost::crypt::is_floating_point_v; } // boost::crypt::concepts From ff7ffc4725ca3bb2997879dbd88f55e53d1da2d6 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 10 Oct 2024 09:39:25 -0400 Subject: [PATCH 046/107] Remove old impls --- include/boost/crypt/hash/md5.hpp | 93 ++------------------------------ 1 file changed, 3 insertions(+), 90 deletions(-) diff --git a/include/boost/crypt/hash/md5.hpp b/include/boost/crypt/hash/md5.hpp index 10029de..901ec99 100644 --- a/include/boost/crypt/hash/md5.hpp +++ b/include/boost/crypt/hash/md5.hpp @@ -11,13 +11,11 @@ #include #include -#include -#include -#include -#include +#ifndef BOOST_CRYPT_BUILD_MODULE #include #include #include +#endif namespace boost { namespace crypt { @@ -50,55 +48,6 @@ static constexpr boost::crypt::array K { 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 }; -template -auto md5_preprocess(T begin, T end) -> std::vector -{ - std::vector vec; - vec.reserve(static_cast(end - begin)); - - // Like std::copy but gives us the correct cast - std::transform(begin, end, std::back_inserter(vec), - [](const auto& element) { - return static_cast(element); - }); - - return vec; -} - -template -auto md5_preprocess(T begin, boost::crypt::size_t len) -> std::vector -{ - std::vector vec; - vec.reserve(len); - - std::transform(begin, begin + len, std::back_inserter(vec), - [](const auto& element) { - return static_cast(element); - }); - - return vec; -} - -auto md5_pad(const std::vector& message) noexcept -> std::vector -{ - std::vector padded_message {message}; - const boost::crypt::uint64_t original_length {message.size() * 8U}; - padded_message.emplace_back(static_cast(0x80)); - - while ((padded_message.size() * 8U) % 512U != 448U) - { - padded_message.emplace_back(static_cast(0x00)); - } - - // Add the original length as a 64-bit number - for (boost::crypt::size_t i = 0; i < 8; ++i) - { - padded_message.emplace_back(static_cast((original_length >> (8 * i)) & 0xFF)); - } - - return padded_message; -} - // TODO(mborland): Replace the loop with the known statements auto md5_body(const boost::crypt::array& blocks, boost::crypt::uint32_t& a, boost::crypt::uint32_t& b, @@ -150,40 +99,6 @@ auto md5_body(const boost::crypt::array& blocks, d += D; } -template -auto md5_impl(const std::vector& padded_message) -> ResultType -{ - boost::crypt::uint32_t a0 {0x67452301}; - boost::crypt::uint32_t b0 {0xefcdab89}; - boost::crypt::uint32_t c0 {0x98badcfe}; - boost::crypt::uint32_t d0 {0x10325476}; - - boost::crypt::array blocks {}; - - boost::crypt::size_t message_chunk {}; - while (message_chunk < padded_message.size()) - { - for (auto& block : blocks) - { - block = static_cast( - (static_cast(padded_message[message_chunk])) + - (static_cast(padded_message[message_chunk + 1U]) << 8U) + - (static_cast(padded_message[message_chunk + 2U]) << 16U) + - (static_cast(padded_message[message_chunk + 3U]) << 24U) - ); - - message_chunk += 4U; - } - - md5_body(blocks, a0, b0, c0, d0); - } - - return ResultType {swap_endian(a0), - swap_endian(b0), - swap_endian(c0), - swap_endian(d0)}; -} - template auto md5_impl(ForwardIterator first, ForwardIterator last) -> ResultType { @@ -302,9 +217,7 @@ ResultType md5(T begin, T end) return ResultType {0, 0, 0, 0}; } - const auto message {detail::md5_preprocess(begin, end)}; - const auto padded_message {detail::md5_pad(message)}; - return detail::md5_impl(padded_message); + return detail::md5_impl(begin, end); } template > From 24ec67d516eddaa34881d39209d776498d4e33a0 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 10 Oct 2024 11:04:37 -0400 Subject: [PATCH 047/107] Add generic strlen --- include/boost/crypt/utility/strlen.hpp | 30 ++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 include/boost/crypt/utility/strlen.hpp diff --git a/include/boost/crypt/utility/strlen.hpp b/include/boost/crypt/utility/strlen.hpp new file mode 100644 index 0000000..e81acd4 --- /dev/null +++ b/include/boost/crypt/utility/strlen.hpp @@ -0,0 +1,30 @@ +// Copyright 2024 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CRYPT_UTILITY_STRLEN_HPP +#define BOOST_CRYPT_UTILITY_STRLEN_HPP + +#include + +namespace boost { +namespace crypt { +namespace utility { + +template +constexpr auto strlen(ForwardIter str) noexcept -> boost::crypt::size_t +{ + boost::crypt::size_t len {}; + while (*(str + len) != static_cast('\0')) + { + ++len; + } + + return len; +} + +} // namespace utility +} // namespace crypt +} // namespace boost + +#endif //BOOST_CRYPT_UTILITY_STRLEN_HPP From 14177ef57d182137f9f7cb04a7e02a4c0de06614 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 10 Oct 2024 12:00:40 -0400 Subject: [PATCH 048/107] Make separate cstddef header --- include/boost/crypt/utility/cstddef.hpp | 44 +++++++++++++++++++++++++ include/boost/crypt/utility/cstdint.hpp | 5 --- 2 files changed, 44 insertions(+), 5 deletions(-) create mode 100644 include/boost/crypt/utility/cstddef.hpp diff --git a/include/boost/crypt/utility/cstddef.hpp b/include/boost/crypt/utility/cstddef.hpp new file mode 100644 index 0000000..3fb2a1c --- /dev/null +++ b/include/boost/crypt/utility/cstddef.hpp @@ -0,0 +1,44 @@ +// Copyright (c) 2024 Matt Borland +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_CRYPT_TOOLS_CSTDDEF +#define BOOST_CRYPT_TOOLS_CSTDDEF + +#include + +#ifdef BOOST_CRYPT_HAS_CUDA + +namespace boost { +namespace crypt { + +using size_t = unsigned long; +using ptrdiff_t = long; +using nullptr_t = void; +using std::max_align_t = double; + + +} // namespace crypt +} // namespace boost + +#else // No cude + +#ifndef BOOST_CRYPT_BUILD_MODULE +#include +#endif + +namespace boost { +namespace crypt { + +using std::size_t; +using std::ptrdiff_t; +using std::nullptr_t; +using std::max_align_t; + +} // namespace crypt +} // namespace boost + +#endif // BOOST_CRYPT_HAS_CUDA + +#endif //BOOST_CSTDDEF_HPP diff --git a/include/boost/crypt/utility/cstdint.hpp b/include/boost/crypt/utility/cstdint.hpp index 975230a..12f512a 100644 --- a/include/boost/crypt/utility/cstdint.hpp +++ b/include/boost/crypt/utility/cstdint.hpp @@ -51,13 +51,10 @@ using cuda::std::uint_least64_t; using cuda::std::uintmax_t; using cuda::std::uintptr_t; -using size_t = unsigned long; - #else #ifndef BOOST_CRYPT_BUILD_MODULE #include -#include #endif namespace boost { @@ -99,8 +96,6 @@ using std::uint_least64_t; using std::uintmax_t; using std::uintptr_t; -using std::size_t; - #endif } // namespace crypt From cd9d907fc91d210786c6b62f4479bcb641ff027e Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 10 Oct 2024 12:22:04 -0400 Subject: [PATCH 049/107] Implement our own array class --- include/boost/crypt/utility/array.hpp | 98 ++++++++++++++++++++++----- 1 file changed, 82 insertions(+), 16 deletions(-) diff --git a/include/boost/crypt/utility/array.hpp b/include/boost/crypt/utility/array.hpp index fdeeee7..60c7a4d 100644 --- a/include/boost/crypt/utility/array.hpp +++ b/include/boost/crypt/utility/array.hpp @@ -7,33 +7,99 @@ #define BOOST_CRYPT_UTILITIES_ARRAY_HPP #include - -#ifdef BOOST_CRYPT_HAS_CUDA - -#include +#include +#include namespace boost { namespace crypt { -using cuda::std::array; +template +class array +{ +public: + using reference = T&; + using const_reference = const T&; + using iterator = T*; + using const_iterator = const T*; + using size_type = boost::crypt::size_t; + using difference_type = boost::crypt::ptrdiff_t; + using value_type = T; + using pointer = T*; + using const_pointer = const T*; -} // namespace crypt -} // namespace boost + T elements[N]; -#else // Use the STL + constexpr array() = default; -#ifndef BOOST_CRYPT_BUILD_MODULE -#include -#endif + // Iterators + constexpr auto begin() noexcept -> iterator { return elements; } + constexpr auto cbegin() const noexcept -> const_iterator { return elements; } + constexpr auto end() noexcept -> iterator { return elements + N; } + constexpr auto cend() const noexcept -> const_iterator { return elements + N; } -namespace boost { -namespace crypt { + // Sizing + constexpr auto size() noexcept -> size_type { return N; } + constexpr auto max_size() noexcept -> size_type { return N; } + + // Accessors + constexpr auto operator[](size_type n) noexcept -> reference + { + BOOST_CRYPT_ASSERT(n < N); + return elements[n]; + } -using std::array; + constexpr auto operator[](size_type n) const noexcept -> const_reference + { + BOOST_CRYPT_ASSERT(n < N); + return elements[n]; + } + + // For at instead of throwing on out of range return the last element since throwing doesn't work on device + constexpr auto at(size_type n) noexcept -> reference + { + if (n >= N) + { + return elements[N - 1U]; + } + return elements[n]; + } + + constexpr auto at(size_type n) const noexcept -> const_reference + { + if (n >= N) + { + return elements[N - 1U]; + } + return elements[n]; + } + + // Front and back + constexpr auto front() noexcept -> reference { return elements[0]; } + constexpr auto front() const noexcept -> const_reference { return elements[0]; } + constexpr auto back() noexcept -> reference { return elements[N - 1]; } + constexpr auto back() const noexcept -> const_reference { return elements[N - 1]; } + + constexpr auto data() noexcept -> pointer { return elements; } + constexpr auto data() const noexcept -> const_pointer { return elements; } + + // Fill and swap + constexpr auto fill(const value_type& v) -> void + { + for (size_type i {}; i < N; ++i) + { + elements[i] = v; + } + } + + constexpr auto swap(array& a) + { + const auto temp {a}; + a = *this; + *this = temp; + } +}; } // namespace crypt } // namespace boost -#endif // CUDA - #endif // BOOST_CRYPT_UTILITIES_ARRAY_HPP From 12478730a2e23e7b63df18e249b80e96637f641f Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 10 Oct 2024 12:51:49 -0400 Subject: [PATCH 050/107] Replace std::array calls with our array --- include/boost/crypt/hash/md5.hpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/include/boost/crypt/hash/md5.hpp b/include/boost/crypt/hash/md5.hpp index 901ec99..c9eb923 100644 --- a/include/boost/crypt/hash/md5.hpp +++ b/include/boost/crypt/hash/md5.hpp @@ -10,6 +10,9 @@ #include #include #include +#include +#include +#include #ifndef BOOST_CRYPT_BUILD_MODULE #include @@ -209,7 +212,7 @@ auto md5_impl(ForwardIterator first, ForwardIterator last) -> ResultType } // namespace detail -template , typename T> +template , typename T> ResultType md5(T begin, T end) { if (end <= begin) @@ -220,7 +223,7 @@ ResultType md5(T begin, T end) return detail::md5_impl(begin, end); } -template > +template > ResultType md5(const char* str) { if (str == nullptr) @@ -232,7 +235,7 @@ ResultType md5(const char* str) return detail::md5_impl(str, str + message_len); } -template > +template > ResultType md5(const std::string& str) { return md5(str.begin(), str.end()); From 6d16853911e620352c877efa926e8e9ee73b167d Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 10 Oct 2024 16:35:31 -0400 Subject: [PATCH 051/107] Add fill --- include/boost/crypt/utility/array.hpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/boost/crypt/utility/array.hpp b/include/boost/crypt/utility/array.hpp index 60c7a4d..0662ef4 100644 --- a/include/boost/crypt/utility/array.hpp +++ b/include/boost/crypt/utility/array.hpp @@ -99,6 +99,15 @@ class array } }; +template +constexpr auto fill_array(ForwardIter first, ForwardIter last, T value) +{ + while (first != last) + { + *first++ = static_cast(value); + } +} + } // namespace crypt } // namespace boost From 44983794735a90e905477502bdad079ec2a25182 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 10 Oct 2024 16:35:42 -0400 Subject: [PATCH 052/107] Add missing type_trait --- include/boost/crypt/utility/type_traits.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/boost/crypt/utility/type_traits.hpp b/include/boost/crypt/utility/type_traits.hpp index 9463549..61033a2 100644 --- a/include/boost/crypt/utility/type_traits.hpp +++ b/include/boost/crypt/utility/type_traits.hpp @@ -488,6 +488,9 @@ BOOST_CRYPT_INLINE_CONSTEXPR bool is_same_v = boost::crypt::is_same::value template BOOST_CRYPT_INLINE_CONSTEXPR bool is_base_of_v = boost::crypt::is_base_of::value; +template +BOOST_CRYPT_INLINE_CONSTEXPR bool is_convertible_v = boost::crypt::is_convertible::value; + } // namespace crypt } // namespace boost From 9f324b74ee95044a0be455487a52e670ea6f7b8f Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 10 Oct 2024 16:35:52 -0400 Subject: [PATCH 053/107] Add concept for conversion --- include/boost/crypt/utility/concepts.hpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/boost/crypt/utility/concepts.hpp b/include/boost/crypt/utility/concepts.hpp index 3c05c3a..47037ea 100644 --- a/include/boost/crypt/utility/concepts.hpp +++ b/include/boost/crypt/utility/concepts.hpp @@ -75,7 +75,7 @@ concept real = boost::crypt::is_floating_point_v; #define BOOST_CRYPT_REQUIRES_TWO_RETURN(X1, T1, X2, T2, ReturnType) -> ReturnType requires X1 && X2 #define BOOST_CRYPT_REQUIRES_THREE(X1, T1, X2, T2, X3, T3) -> detail::promote_args_t requires X1 && X2 && X3 #define BOOST_CRYPT_REQUIRES_RETURN(X, T, ReturnType) -> ReturnType requires X - +#define BOOST_CRYPT_REQUIRES_CONVERSION(T1, T2) -> void requires boost::crypt::is_convertible_v #endif // Has #endif // C++20 @@ -117,4 +117,8 @@ concept real = boost::crypt::is_floating_point_v; # define BOOST_CRYPT_REQUIRES_RETURN(X, T, ReturnType) -> boost::crypt::enable_if_t, ReturnType> #endif +#ifndef BOOST_CRYPT_REQUIRES_CONVERSION +# define BOOST_CRYPT_REQUIRES_CONVERSION(T1, T2) -> boost::crypt::enable_if_t, void> +#endif + #endif //BOOST_CRYPT_UTILITY_CONCEPTS_HPP From 510c53e305189d2d76c148da7332592aea961048 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 10 Oct 2024 16:36:09 -0400 Subject: [PATCH 054/107] Add class based design --- include/boost/crypt/hash/md5.hpp | 180 +++++++++++++++++++++++++++++++ 1 file changed, 180 insertions(+) diff --git a/include/boost/crypt/hash/md5.hpp b/include/boost/crypt/hash/md5.hpp index c9eb923..a5215c3 100644 --- a/include/boost/crypt/hash/md5.hpp +++ b/include/boost/crypt/hash/md5.hpp @@ -102,6 +102,186 @@ auto md5_body(const boost::crypt::array& blocks, d += D; } +class md5 +{ +private: + boost::crypt::uint32_t a0_ {0x67452301}; + boost::crypt::uint32_t b0_ {0xefcdab89}; + boost::crypt::uint32_t c0_ {0x98badcfe}; + boost::crypt::uint32_t d0_ {0x10325476}; + + boost::crypt::size_t low_ {}; + boost::crypt::size_t high_ {}; + + boost::crypt::array buffer_ {}; + boost::crypt::array blocks_ {}; + + template + constexpr auto md5_update(ForwardIter data, boost::crypt::size_t size) noexcept; + + constexpr auto md5_convert_buffer_to_blocks() noexcept; + + template + constexpr auto md5_copy_data(ForwardIter data, boost::crypt::size_t offset, boost::crypt::size_t size) noexcept; + +public: + constexpr auto init() noexcept -> void; + + template + constexpr auto process_byte(ByteType byte) noexcept + BOOST_CRYPT_REQUIRES_CONVERSION(ByteType, boost::crypt::uint8_t); + + template + constexpr auto process_bytes(ForwardIter buffer, boost::crypt::size_t byte_count) noexcept + BOOST_CRYPT_REQUIRES_CONVERSION(boost::crypt::uint8_t, decltype(*buffer)); + + template + constexpr auto get_digest(DigestType digest, boost::crypt::size_t digest_size) noexcept; +}; + +constexpr auto md5::init() noexcept -> void +{ + a0_ = 0x67452301U; + b0_ = 0xefcdab89U; + c0_ = 0x98badcfeU; + d0_ = 0x10325476U; + + low_ = 0U; + high_ = 0U; + + buffer_.fill(static_cast(0)); + blocks_.fill(0U); +} + +constexpr auto md5::md5_convert_buffer_to_blocks() noexcept +{ + boost::crypt::size_t buffer_index {}; + for (auto& block : blocks_) + { + block = static_cast( + static_cast(buffer_[buffer_index]) | + (static_cast(buffer_[buffer_index + 1U]) << 8U) | + (static_cast(buffer_[buffer_index + 2U]) << 16U) | + (static_cast(buffer_[buffer_index + 3U]) << 24U) + ); + + buffer_index += 4U; + } +} + +template +constexpr auto md5::md5_copy_data(ForwardIter data, boost::crypt::size_t offset, boost::crypt::size_t size) noexcept +{ + for (boost::crypt::size_t i {}; i < size; ++i) + { + BOOST_CRYPT_ASSERT(offset + i < buffer_.size()); + buffer_[offset + i] = static_cast(*(data + i)); + } +} + +template +constexpr auto md5::md5_update(ForwardIter data, boost::crypt::size_t size) noexcept +{ + const auto input_bits {size << 3U}; // Convert size to bits + const auto old_low {low_}; + low_ += input_bits; + if (low_ < old_low) + { + ++high_; + } + high_ += size >> 29U; + + auto used {(old_low >> 3U) & 0x3F}; // Number of bytes used in buffer + + if (used) + { + auto available = 64U - used; + if (size < available) + { + md5_copy_data(data, used, size); + return; + } + + md5_copy_data(data, used, available); + md5_convert_buffer_to_blocks(); + md5_body(blocks_, a0_, b0_, c0_, d0_); + data += available; + size -= available; + } + + while (size >= 64U) + { + md5_copy_data(data, 0U, 64U); + md5_convert_buffer_to_blocks(); + md5_body(blocks_, a0_, b0_, c0_, d0_); + data += 64U; + size -= 64U; + } + + if (size > 0) + { + md5_copy_data(data, 0U, size); + } +} + +template +constexpr auto md5::get_digest(DigestType digest, boost::crypt::size_t digest_size) noexcept +{ + auto used {(low_ >> 3U) & 0x3F}; // Number of bytes used in buffer + buffer_[used++] = 0x80; + auto available {buffer_.size() - used}; + + if (available < 8U) + { + fill_array(buffer_.begin() + used, buffer_.end(), static_cast(0)); + md5_convert_buffer_to_blocks(); + md5_body(blocks_, a0_, b0_, c0_, d0_); + used = 0; + buffer_.fill(0); + } + else + { + fill_array(buffer_.begin() + used, buffer_.end() - 8, static_cast(0)); + } + + uint64_t total_bits = (static_cast(high_) << 32) | low_; + + // Append the length in bits as a 64-bit little-endian integer + buffer_[56] = static_cast(total_bits & 0xFF); + buffer_[57] = static_cast((total_bits >> 8) & 0xFF); + buffer_[58] = static_cast((total_bits >> 16) & 0xFF); + buffer_[59] = static_cast((total_bits >> 24) & 0xFF); + buffer_[60] = static_cast((total_bits >> 32) & 0xFF); + buffer_[61] = static_cast((total_bits >> 40) & 0xFF); + buffer_[62] = static_cast((total_bits >> 48) & 0xFF); + buffer_[63] = static_cast((total_bits >> 56) & 0xFF); + + md5_convert_buffer_to_blocks(); + md5_body(blocks_, a0_, b0_, c0_, d0_); + + if (digest_size >= 4) + { + digest[0] = swap_endian(a0_); + digest[1] = swap_endian(b0_); + digest[2] = swap_endian(c0_); + digest[3] = swap_endian(d0_); + } +} + +template +constexpr auto md5::process_byte(ByteType byte) noexcept + BOOST_CRYPT_REQUIRES_CONVERSION(ByteType, boost::crypt::uint8_t) +{ + md5_update(&byte, 1UL); +} + +template +constexpr auto md5::process_bytes(ForwardIter buffer, boost::crypt::size_t byte_count) noexcept + BOOST_CRYPT_REQUIRES_CONVERSION(boost::crypt::uint8_t, decltype(*buffer)) +{ + md5_update(buffer, byte_count); +} + template auto md5_impl(ForwardIterator first, ForwardIterator last) -> ResultType { From 1727a0af32f7def6f74002382d36eff98cba3f83 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 10 Oct 2024 16:45:14 -0400 Subject: [PATCH 055/107] Add class design test --- test/test_md5.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/test_md5.cpp b/test/test_md5.cpp index 04470d4..02a6850 100644 --- a/test/test_md5.cpp +++ b/test/test_md5.cpp @@ -7,6 +7,7 @@ #include #include #include +#include void basic_tests() { @@ -71,11 +72,28 @@ void bad_input() BOOST_TEST_EQ(message_1_result[3], 0x0); } +void test_class() +{ + boost::crypt::detail::md5 hasher; + constexpr auto msg = "The quick brown fox jumps over the lazy dog"; + hasher.process_bytes(msg, std::strlen(msg)); + std::array message_1_result {}; + hasher.get_digest(message_1_result.begin(), message_1_result.size()); + + BOOST_TEST_EQ(message_1_result[0], 0x9e107d9d); + BOOST_TEST_EQ(message_1_result[1], 0x372bb682); + BOOST_TEST_EQ(message_1_result[2], 0x6bd81d35); + BOOST_TEST_EQ(message_1_result[3], 0x42a419d6); +} + + int main() { basic_tests(); string_test(); bad_input(); + test_class(); + return boost::report_errors(); } From fdecb4ba5ab5749d08f58e0ef072cd681b54c6d3 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 10 Oct 2024 18:33:04 -0400 Subject: [PATCH 056/107] Make array an aggregate --- include/boost/crypt/utility/array.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/boost/crypt/utility/array.hpp b/include/boost/crypt/utility/array.hpp index 0662ef4..a70107d 100644 --- a/include/boost/crypt/utility/array.hpp +++ b/include/boost/crypt/utility/array.hpp @@ -29,8 +29,6 @@ class array T elements[N]; - constexpr array() = default; - // Iterators constexpr auto begin() noexcept -> iterator { return elements; } constexpr auto cbegin() const noexcept -> const_iterator { return elements; } From 98a50607c850e9548df652db3ce42f41decaf4b3 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 10 Oct 2024 18:34:51 -0400 Subject: [PATCH 057/107] Remove bad concept --- include/boost/crypt/hash/md5.hpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/include/boost/crypt/hash/md5.hpp b/include/boost/crypt/hash/md5.hpp index a5215c3..8dd4524 100644 --- a/include/boost/crypt/hash/md5.hpp +++ b/include/boost/crypt/hash/md5.hpp @@ -132,8 +132,7 @@ class md5 BOOST_CRYPT_REQUIRES_CONVERSION(ByteType, boost::crypt::uint8_t); template - constexpr auto process_bytes(ForwardIter buffer, boost::crypt::size_t byte_count) noexcept - BOOST_CRYPT_REQUIRES_CONVERSION(boost::crypt::uint8_t, decltype(*buffer)); + constexpr auto process_bytes(ForwardIter buffer, boost::crypt::size_t byte_count) noexcept; template constexpr auto get_digest(DigestType digest, boost::crypt::size_t digest_size) noexcept; @@ -277,7 +276,6 @@ constexpr auto md5::process_byte(ByteType byte) noexcept template constexpr auto md5::process_bytes(ForwardIter buffer, boost::crypt::size_t byte_count) noexcept - BOOST_CRYPT_REQUIRES_CONVERSION(boost::crypt::uint8_t, decltype(*buffer)) { md5_update(buffer, byte_count); } From 2885eb9ec2b5516f7b3dd5e35b7a0611d797acce Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 11 Oct 2024 10:08:11 -0400 Subject: [PATCH 058/107] Fix 0 length string --- include/boost/crypt/hash/md5.hpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/boost/crypt/hash/md5.hpp b/include/boost/crypt/hash/md5.hpp index 8dd4524..b7b2812 100644 --- a/include/boost/crypt/hash/md5.hpp +++ b/include/boost/crypt/hash/md5.hpp @@ -393,10 +393,14 @@ auto md5_impl(ForwardIterator first, ForwardIterator last) -> ResultType template , typename T> ResultType md5(T begin, T end) { - if (end <= begin) + if (end < begin) { return ResultType {0, 0, 0, 0}; } + else if (end == begin) + { + return ResultType{0xd41d8cd9, 0x8f00b204, 0xe9800998, 0xecf8427e}; + } return detail::md5_impl(begin, end); } From 5969bca96879adab7b8b1b3aee1712625b135d16 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 11 Oct 2024 10:08:23 -0400 Subject: [PATCH 059/107] Improve testing methodology --- test/test_md5.cpp | 107 ++++++++++++++++++++++++---------------------- 1 file changed, 55 insertions(+), 52 deletions(-) diff --git a/test/test_md5.cpp b/test/test_md5.cpp index 02a6850..8938764 100644 --- a/test/test_md5.cpp +++ b/test/test_md5.cpp @@ -8,52 +8,54 @@ #include #include #include +#include -void basic_tests() +constexpr std::array, 3> test_values = { - const auto message_1_result {boost::crypt::md5("The quick brown fox jumps over the lazy dog")}; - BOOST_TEST_EQ(message_1_result[0], 0x9e107d9d); - BOOST_TEST_EQ(message_1_result[1], 0x372bb682); - BOOST_TEST_EQ(message_1_result[2], 0x6bd81d35); - BOOST_TEST_EQ(message_1_result[3], 0x42a419d6); - - const auto message_2_result {boost::crypt::md5("The quick brown fox jumps over the lazy dog.")}; - BOOST_TEST_EQ(message_2_result[0], 0xe4d909c2); - BOOST_TEST_EQ(message_2_result[1], 0x90d0fb1c); - BOOST_TEST_EQ(message_2_result[2], 0xa068ffad); - BOOST_TEST_EQ(message_2_result[3], 0xdf22cbd0); + std::make_tuple("The quick brown fox jumps over the lazy dog", 0x9e107d9d, 0x372bb682, 0x6bd81d35, 0x42a419d6), + std::make_tuple("The quick brown fox jumps over the lazy dog.", 0xe4d909c2, 0x90d0fb1c, 0xa068ffad, 0xdf22cbd0), + std::make_tuple("", 0xd41d8cd9, 0x8f00b204, 0xe9800998, 0xecf8427e) +}; - const auto message_3_result {boost::crypt::md5("")}; - BOOST_TEST_EQ(message_3_result[0], 0xd41d8cd9); - BOOST_TEST_EQ(message_3_result[1], 0x8f00b204); - BOOST_TEST_EQ(message_3_result[2], 0xe9800998); - BOOST_TEST_EQ(message_3_result[3], 0xecf8427e); +void basic_tests() +{ + for (const auto& test_value : test_values) + { + const auto message_result {boost::crypt::md5(std::get<0>(test_value))}; + BOOST_TEST_EQ(message_result[0], std::get<1>(test_value)); + BOOST_TEST_EQ(message_result[1], std::get<2>(test_value)); + BOOST_TEST_EQ(message_result[2], std::get<3>(test_value)); + BOOST_TEST_EQ(message_result[3], std::get<4>(test_value)); + } } void string_test() { - std::string message_1 {"The quick brown fox jumps over the lazy dog"}; - const auto message_1_result {boost::crypt::md5(message_1)}; - BOOST_TEST_EQ(message_1_result[0], 0x9e107d9d); - BOOST_TEST_EQ(message_1_result[1], 0x372bb682); - BOOST_TEST_EQ(message_1_result[2], 0x6bd81d35); - BOOST_TEST_EQ(message_1_result[3], 0x42a419d6); + for (const auto& test_value : test_values) + { + const std::string string_message {std::get<0>(test_value)}; + const auto message_result {boost::crypt::md5(string_message)}; + BOOST_TEST_EQ(message_result[0], std::get<1>(test_value)); + BOOST_TEST_EQ(message_result[1], std::get<2>(test_value)); + BOOST_TEST_EQ(message_result[2], std::get<3>(test_value)); + BOOST_TEST_EQ(message_result[3], std::get<4>(test_value)); + } +} +void string_view_test() +{ #ifdef BOOST_CRYPT_HAS_STRING_VIEW - std::string_view view_1 {message_1}; - const auto view_1_result {boost::crypt::md5(view_1)}; - BOOST_TEST_EQ(view_1_result[0], 0x9e107d9d); - BOOST_TEST_EQ(view_1_result[1], 0x372bb682); - BOOST_TEST_EQ(view_1_result[2], 0x6bd81d35); - BOOST_TEST_EQ(view_1_result[3], 0x42a419d6); + 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::md5(string_view_message)}; + BOOST_TEST_EQ(message_result[0], std::get<1>(test_value)); + BOOST_TEST_EQ(message_result[1], std::get<2>(test_value)); + BOOST_TEST_EQ(message_result[2], std::get<3>(test_value)); + BOOST_TEST_EQ(message_result[3], std::get<4>(test_value)); + } #endif - - std::string message_2 {"The quick brown fox jumps over the lazy dog."}; - const auto message_2_result {boost::crypt::md5(message_2.begin(), message_2.end())}; - BOOST_TEST_EQ(message_2_result[0], 0xe4d909c2); - BOOST_TEST_EQ(message_2_result[1], 0x90d0fb1c); - BOOST_TEST_EQ(message_2_result[2], 0xa068ffad); - BOOST_TEST_EQ(message_2_result[3], 0xdf22cbd0); } void bad_input() @@ -63,34 +65,35 @@ void bad_input() BOOST_TEST_EQ(null_message[1], 0x0); BOOST_TEST_EQ(null_message[2], 0x0); BOOST_TEST_EQ(null_message[3], 0x0); - - std::string message_1 {"The quick brown fox jumps over the lazy dog"}; - const auto message_1_result {boost::crypt::md5(message_1.begin(), message_1.begin())}; - BOOST_TEST_EQ(message_1_result[0], 0x0); - BOOST_TEST_EQ(message_1_result[1], 0x0); - BOOST_TEST_EQ(message_1_result[2], 0x0); - BOOST_TEST_EQ(message_1_result[3], 0x0); } void test_class() { boost::crypt::detail::md5 hasher; - constexpr auto msg = "The quick brown fox jumps over the lazy dog"; - hasher.process_bytes(msg, std::strlen(msg)); - std::array message_1_result {}; - hasher.get_digest(message_1_result.begin(), message_1_result.size()); - BOOST_TEST_EQ(message_1_result[0], 0x9e107d9d); - BOOST_TEST_EQ(message_1_result[1], 0x372bb682); - BOOST_TEST_EQ(message_1_result[2], 0x6bd81d35); - BOOST_TEST_EQ(message_1_result[3], 0x42a419d6); -} + for (const auto& test_value : test_values) + { + const auto msg {std::get<0>(test_value)}; + hasher.process_bytes(msg, std::strlen(msg)); + std::array message_result {}; + hasher.get_digest(message_result.begin(), message_result.size()); + + BOOST_TEST_EQ(message_result[0], std::get<1>(test_value)); + BOOST_TEST_EQ(message_result[1], std::get<2>(test_value)); + BOOST_TEST_EQ(message_result[2], std::get<3>(test_value)); + BOOST_TEST_EQ(message_result[3], std::get<4>(test_value)); + hasher.init(); + } +} int main() { basic_tests(); string_test(); + string_test(); + string_view_test(); + bad_input(); test_class(); From d1ffa8eed8068434583d618fe6452c8b9916fd0a Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 11 Oct 2024 10:19:08 -0400 Subject: [PATCH 060/107] Add additional test sets --- test/test_md5.cpp | 55 +++++++++++++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/test/test_md5.cpp b/test/test_md5.cpp index 8938764..c055426 100644 --- a/test/test_md5.cpp +++ b/test/test_md5.cpp @@ -6,15 +6,22 @@ #include #include +#include #include #include #include -constexpr std::array, 3> test_values = +constexpr std::array, 9> test_values = { std::make_tuple("The quick brown fox jumps over the lazy dog", 0x9e107d9d, 0x372bb682, 0x6bd81d35, 0x42a419d6), std::make_tuple("The quick brown fox jumps over the lazy dog.", 0xe4d909c2, 0x90d0fb1c, 0xa068ffad, 0xdf22cbd0), - std::make_tuple("", 0xd41d8cd9, 0x8f00b204, 0xe9800998, 0xecf8427e) + std::make_tuple("", 0xd41d8cd9, 0x8f00b204, 0xe9800998, 0xecf8427e), + std::make_tuple("ddcc8542894a27456bbeb43f51f38764c32f72ae", 0x3b340f00, 0x97312ec8, 0x2fa4da0d, 0x7da53002), + std::make_tuple("webmin1980", 0xb78aae35, 0x6709f8c3, 0x1118ea61, 0x3980954b), + std::make_tuple("$2y$10$EQAmcJw0cg.rt.6..SJ2bulFhDo0eWtuMhkfDMPGsNdap4xrOY61K", 0x40bbe664, 0x4efd9354, 0x078d8c70, 0xfb6c9f42), + std::make_tuple("pkirsanov", 0x8793ce04, 0xf0c5f1e8, 0xed1e0c78, 0xf249fe1b), + std::make_tuple("Eleanor", 0xd37e4317, 0x4905de70, 0xfbb5b038, 0xd7247f57), + std::make_tuple("The Whirlpool Galaxy is about 88% the size of the Milky Way, with a diameter of 76,900 light-years", 0xd5dfd7b4, 0x1235abc7, 0xa9a3205b, 0x6896f34d), }; void basic_tests() @@ -22,10 +29,13 @@ void basic_tests() for (const auto& test_value : test_values) { const auto message_result {boost::crypt::md5(std::get<0>(test_value))}; - BOOST_TEST_EQ(message_result[0], std::get<1>(test_value)); - BOOST_TEST_EQ(message_result[1], std::get<2>(test_value)); - BOOST_TEST_EQ(message_result[2], std::get<3>(test_value)); - BOOST_TEST_EQ(message_result[3], std::get<4>(test_value)); + if (!(BOOST_TEST_EQ(message_result[0], std::get<1>(test_value)) && + BOOST_TEST_EQ(message_result[1], std::get<2>(test_value)) && + BOOST_TEST_EQ(message_result[2], std::get<3>(test_value)) && + BOOST_TEST_EQ(message_result[3], std::get<4>(test_value)))) + { + std::cerr << "Failure with message: " << std::get<0>(test_value) << '\n'; + } } } @@ -35,10 +45,13 @@ void string_test() { const std::string string_message {std::get<0>(test_value)}; const auto message_result {boost::crypt::md5(string_message)}; - BOOST_TEST_EQ(message_result[0], std::get<1>(test_value)); - BOOST_TEST_EQ(message_result[1], std::get<2>(test_value)); - BOOST_TEST_EQ(message_result[2], std::get<3>(test_value)); - BOOST_TEST_EQ(message_result[3], std::get<4>(test_value)); + if (!(BOOST_TEST_EQ(message_result[0], std::get<1>(test_value)) && + BOOST_TEST_EQ(message_result[1], std::get<2>(test_value)) && + BOOST_TEST_EQ(message_result[2], std::get<3>(test_value)) && + BOOST_TEST_EQ(message_result[3], std::get<4>(test_value)))) + { + std::cerr << "Failure with message: " << std::get<0>(test_value) << '\n'; + } } } @@ -50,10 +63,13 @@ void string_view_test() 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::md5(string_view_message)}; - BOOST_TEST_EQ(message_result[0], std::get<1>(test_value)); - BOOST_TEST_EQ(message_result[1], std::get<2>(test_value)); - BOOST_TEST_EQ(message_result[2], std::get<3>(test_value)); - BOOST_TEST_EQ(message_result[3], std::get<4>(test_value)); + if (!(BOOST_TEST_EQ(message_result[0], std::get<1>(test_value)) && + BOOST_TEST_EQ(message_result[1], std::get<2>(test_value)) && + BOOST_TEST_EQ(message_result[2], std::get<3>(test_value)) && + BOOST_TEST_EQ(message_result[3], std::get<4>(test_value)))) + { + std::cerr << "Failure with message: " << std::get<0>(test_value) << '\n'; + } } #endif } @@ -78,10 +94,13 @@ void test_class() std::array message_result {}; hasher.get_digest(message_result.begin(), message_result.size()); - BOOST_TEST_EQ(message_result[0], std::get<1>(test_value)); - BOOST_TEST_EQ(message_result[1], std::get<2>(test_value)); - BOOST_TEST_EQ(message_result[2], std::get<3>(test_value)); - BOOST_TEST_EQ(message_result[3], std::get<4>(test_value)); + if (!(BOOST_TEST_EQ(message_result[0], std::get<1>(test_value)) && + BOOST_TEST_EQ(message_result[1], std::get<2>(test_value)) && + BOOST_TEST_EQ(message_result[2], std::get<3>(test_value)) && + BOOST_TEST_EQ(message_result[3], std::get<4>(test_value)))) + { + std::cerr << "Failure with message: " << std::get<0>(test_value) << '\n'; + } hasher.init(); } From fa72b53bf1ec57548093689c4ab170c924c672e5 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 11 Oct 2024 10:39:45 -0400 Subject: [PATCH 061/107] Convert all usage to the class --- include/boost/crypt/hash/md5.hpp | 235 +++++++++---------------------- test/test_md5.cpp | 2 +- 2 files changed, 67 insertions(+), 170 deletions(-) diff --git a/include/boost/crypt/hash/md5.hpp b/include/boost/crypt/hash/md5.hpp index b7b2812..39c9d04 100644 --- a/include/boost/crypt/hash/md5.hpp +++ b/include/boost/crypt/hash/md5.hpp @@ -51,58 +51,9 @@ static constexpr boost::crypt::array K { 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 }; -// TODO(mborland): Replace the loop with the known statements -auto md5_body(const boost::crypt::array& blocks, - boost::crypt::uint32_t& a, boost::crypt::uint32_t& b, - boost::crypt::uint32_t& c, boost::crypt::uint32_t& d) noexcept -{ - boost::crypt::uint32_t A {a}; - boost::crypt::uint32_t B {b}; - boost::crypt::uint32_t C {c}; - boost::crypt::uint32_t D {d}; - - for (boost::crypt::uint32_t i {}; i < 64U; ++i) - { - boost::crypt::uint32_t F {}; - boost::crypt::uint32_t g {}; - - if (i <= 15U) - { - F = (B & C) | ((~B) & D); - g = i; - } - else if (i <= 31U) - { - F = (D & B) | ((~D) & C); - g = (5U * i + 1U) % 16U; - } - else if (i <= 47U) - { - F = B ^ C ^ D; - g = (3U * i + 5U) % 16U; - } - else - { - F = C ^ (B | (~D)); - g = (7U * i) % 16U; - } - - BOOST_CRYPT_ASSERT(i <= 63U); - - F = F + A + K[i] + blocks[g]; - A = D; - D = C; - C = B; - B = B + rotl(F, S[i]); - } - - a += A; - b += B; - c += C; - d += D; -} +} // namespace detail -class md5 +class md5_hasher { private: boost::crypt::uint32_t a0_ {0x67452301}; @@ -124,6 +75,8 @@ class md5 template constexpr auto md5_copy_data(ForwardIter data, boost::crypt::size_t offset, boost::crypt::size_t size) noexcept; + constexpr auto md5_body() noexcept -> void; + public: constexpr auto init() noexcept -> void; @@ -138,7 +91,7 @@ class md5 constexpr auto get_digest(DigestType digest, boost::crypt::size_t digest_size) noexcept; }; -constexpr auto md5::init() noexcept -> void +constexpr auto md5_hasher::init() noexcept -> void { a0_ = 0x67452301U; b0_ = 0xefcdab89U; @@ -152,7 +105,7 @@ constexpr auto md5::init() noexcept -> void blocks_.fill(0U); } -constexpr auto md5::md5_convert_buffer_to_blocks() noexcept +constexpr auto md5_hasher::md5_convert_buffer_to_blocks() noexcept { boost::crypt::size_t buffer_index {}; for (auto& block : blocks_) @@ -169,17 +122,17 @@ constexpr auto md5::md5_convert_buffer_to_blocks() noexcept } template -constexpr auto md5::md5_copy_data(ForwardIter data, boost::crypt::size_t offset, boost::crypt::size_t size) noexcept +constexpr auto md5_hasher::md5_copy_data(ForwardIter data, boost::crypt::size_t offset, boost::crypt::size_t size) noexcept { for (boost::crypt::size_t i {}; i < size; ++i) { BOOST_CRYPT_ASSERT(offset + i < buffer_.size()); - buffer_[offset + i] = static_cast(*(data + i)); + buffer_[offset + i] = static_cast(*(data + static_cast(i))); } } template -constexpr auto md5::md5_update(ForwardIter data, boost::crypt::size_t size) noexcept +constexpr auto md5_hasher::md5_update(ForwardIter data, boost::crypt::size_t size) noexcept { const auto input_bits {size << 3U}; // Convert size to bits const auto old_low {low_}; @@ -203,8 +156,8 @@ constexpr auto md5::md5_update(ForwardIter data, boost::crypt::size_t size) noex md5_copy_data(data, used, available); md5_convert_buffer_to_blocks(); - md5_body(blocks_, a0_, b0_, c0_, d0_); - data += available; + md5_body(); + data += static_cast(available); size -= available; } @@ -212,7 +165,7 @@ constexpr auto md5::md5_update(ForwardIter data, boost::crypt::size_t size) noex { md5_copy_data(data, 0U, 64U); md5_convert_buffer_to_blocks(); - md5_body(blocks_, a0_, b0_, c0_, d0_); + md5_body(); data += 64U; size -= 64U; } @@ -224,7 +177,7 @@ constexpr auto md5::md5_update(ForwardIter data, boost::crypt::size_t size) noex } template -constexpr auto md5::get_digest(DigestType digest, boost::crypt::size_t digest_size) noexcept +constexpr auto md5_hasher::get_digest(DigestType digest, boost::crypt::size_t digest_size) noexcept { auto used {(low_ >> 3U) & 0x3F}; // Number of bytes used in buffer buffer_[used++] = 0x80; @@ -234,7 +187,7 @@ constexpr auto md5::get_digest(DigestType digest, boost::crypt::size_t digest_si { fill_array(buffer_.begin() + used, buffer_.end(), static_cast(0)); md5_convert_buffer_to_blocks(); - md5_body(blocks_, a0_, b0_, c0_, d0_); + md5_body(); used = 0; buffer_.fill(0); } @@ -256,140 +209,79 @@ constexpr auto md5::get_digest(DigestType digest, boost::crypt::size_t digest_si buffer_[63] = static_cast((total_bits >> 56) & 0xFF); md5_convert_buffer_to_blocks(); - md5_body(blocks_, a0_, b0_, c0_, d0_); + md5_body(); if (digest_size >= 4) { - digest[0] = swap_endian(a0_); - digest[1] = swap_endian(b0_); - digest[2] = swap_endian(c0_); - digest[3] = swap_endian(d0_); + digest[0] = detail::swap_endian(a0_); + digest[1] = detail::swap_endian(b0_); + digest[2] = detail::swap_endian(c0_); + digest[3] = detail::swap_endian(d0_); } } template -constexpr auto md5::process_byte(ByteType byte) noexcept +constexpr auto md5_hasher::process_byte(ByteType byte) noexcept BOOST_CRYPT_REQUIRES_CONVERSION(ByteType, boost::crypt::uint8_t) { md5_update(&byte, 1UL); } template -constexpr auto md5::process_bytes(ForwardIter buffer, boost::crypt::size_t byte_count) noexcept +constexpr auto md5_hasher::process_bytes(ForwardIter buffer, boost::crypt::size_t byte_count) noexcept { md5_update(buffer, byte_count); } -template -auto md5_impl(ForwardIterator first, ForwardIterator last) -> ResultType +// TODO(mborland): Replace the loop with the known statements +constexpr auto md5_hasher::md5_body() noexcept -> void { - // Initial MD5 buffer values - boost::crypt::uint32_t a0 {0x67452301}; - boost::crypt::uint32_t b0 {0xefcdab89}; - boost::crypt::uint32_t c0 {0x98badcfe}; - boost::crypt::uint32_t d0 {0x10325476}; - - boost::crypt::array blocks {}; - - // Store the original 'first' to compute the total message length - const auto total_message_length {static_cast(last - first) * 8UL}; - - // Handles the empty case with known values - if (first == last) - { - return ResultType{0xd41d8cd9, 0x8f00b204, 0xe9800998, 0xecf8427e}; - } + boost::crypt::uint32_t A {a0_}; + boost::crypt::uint32_t B {b0_}; + boost::crypt::uint32_t C {c0_}; + boost::crypt::uint32_t D {d0_}; - while (first != last) + for (boost::crypt::uint32_t i {}; i < 64U; ++i) { - boost::crypt::size_t current_block = 0; + boost::crypt::uint32_t F {}; + boost::crypt::uint32_t g {}; - // Process as many full 64-byte blocks as possible - if (last - first >= 64) + if (i <= 15U) + { + F = (B & C) | ((~B) & D); + g = i; + } + else if (i <= 31U) { - for (auto& block : blocks) - { - block = static_cast( - static_cast(*first) + - (static_cast(*(first + 1U)) << 8U) + - (static_cast(*(first + 2U)) << 16U) + - (static_cast(*(first + 3U)) << 24U) - ); - - first += 4U; - } - md5_body(blocks, a0, b0, c0, d0); + F = (D & B) | ((~D) & C); + g = (5U * i + 1U) % 16U; + } + else if (i <= 47U) + { + F = B ^ C ^ D; + g = (3U * i + 5U) % 16U; } else { - // Process remaining bytes - // Initialize blocks to zero - blocks.fill(0); - - // Process complete 4-byte chunks - while (last - first >= 4) - { - blocks[current_block] = static_cast( - static_cast(*first) + - (static_cast(*(first + 1U)) << 8U) + - (static_cast(*(first + 2U)) << 16U) + - (static_cast(*(first + 3U)) << 24U) - ); - - first += 4U; - ++current_block; - } - - // Process remaining bytes (less than 4) - blocks[current_block] = 0; - auto byte_offset = 0U; - while (first != last) - { - blocks[current_block] |= static_cast(*first) << (8U * byte_offset); - ++first; - ++byte_offset; - } - - // Append the '1' bit (0x80) after the last byte - blocks[current_block] |= static_cast(0x80) << (8U * byte_offset); - ++current_block; - - // Check if there is enough space to append the length - if (current_block > 14U) - { - // Not enough space, process this block and start a new one - md5_body(blocks, a0, b0, c0, d0); - blocks.fill(0); - current_block = 0; - } - - // Pad with zeros until block[14] - while (current_block < 14U) - { - blocks[current_block] = 0; - ++current_block; - } - - // Append the 64-bit length in bits in little-endian format - blocks[14] = static_cast(total_message_length & 0xFFFFFFFF); - blocks[15] = static_cast((total_message_length >> 32) & 0xFFFFFFFF); - - // Process the final block - md5_body(blocks, a0, b0, c0, d0); - - // Break out of the loop as we've processed all data - break; + F = C ^ (B | (~D)); + g = (7U * i) % 16U; } + + BOOST_CRYPT_ASSERT(i <= 63U); + + F = F + A + detail::K[i] + blocks_[g]; + A = D; + D = C; + C = B; + B = B + detail::rotl(F, detail::S[i]); } - return ResultType {swap_endian(a0), - swap_endian(b0), - swap_endian(c0), - swap_endian(d0)}; + a0_ += A; + b0_ += B; + c0_ += C; + d0_ += D; } -} // namespace detail - template , typename T> ResultType md5(T begin, T end) { @@ -402,7 +294,12 @@ ResultType md5(T begin, T end) return ResultType{0xd41d8cd9, 0x8f00b204, 0xe9800998, 0xecf8427e}; } - return detail::md5_impl(begin, end); + boost::crypt::md5_hasher hasher; + hasher.process_bytes(begin, static_cast(end - begin)); + ResultType result; + hasher.get_digest(result.begin(), result.size()); + + return result; } template > @@ -414,20 +311,20 @@ ResultType md5(const char* str) } const auto message_len {std::strlen(str)}; - return detail::md5_impl(str, str + message_len); + return md5(str, str + message_len); } template > ResultType md5(const std::string& str) { - return md5(str.begin(), str.end()); + return md5(str.begin(), str.end()); } #ifdef BOOST_CRYPT_HAS_STRING_VIEW template > ResultType md5(const std::string_view& str) { - return md5(str.begin(), str.end()); + return md5(str.begin(), str.end()); } #endif diff --git a/test/test_md5.cpp b/test/test_md5.cpp index c055426..870c1e4 100644 --- a/test/test_md5.cpp +++ b/test/test_md5.cpp @@ -85,7 +85,7 @@ void bad_input() void test_class() { - boost::crypt::detail::md5 hasher; + boost::crypt::md5_hasher hasher; for (const auto& test_value : test_values) { From a7bf2475950e6125f4e19e6e13b4eb0699972914 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 11 Oct 2024 10:45:50 -0400 Subject: [PATCH 062/107] Add GPU markers --- include/boost/crypt/hash/md5.hpp | 42 ++++++++++++++------------ include/boost/crypt/utility/array.hpp | 38 +++++++++++------------ include/boost/crypt/utility/bit.hpp | 18 +++++------ include/boost/crypt/utility/strlen.hpp | 2 +- 4 files changed, 51 insertions(+), 49 deletions(-) diff --git a/include/boost/crypt/hash/md5.hpp b/include/boost/crypt/hash/md5.hpp index 39c9d04..91deb09 100644 --- a/include/boost/crypt/hash/md5.hpp +++ b/include/boost/crypt/hash/md5.hpp @@ -68,30 +68,30 @@ class md5_hasher boost::crypt::array blocks_ {}; template - constexpr auto md5_update(ForwardIter data, boost::crypt::size_t size) noexcept; + BOOST_CRYPT_GPU_ENABLED constexpr auto md5_update(ForwardIter data, boost::crypt::size_t size) noexcept; - constexpr auto md5_convert_buffer_to_blocks() noexcept; + BOOST_CRYPT_GPU_ENABLED constexpr auto md5_convert_buffer_to_blocks() noexcept; template - constexpr auto md5_copy_data(ForwardIter data, boost::crypt::size_t offset, boost::crypt::size_t size) noexcept; + BOOST_CRYPT_GPU_ENABLED constexpr auto md5_copy_data(ForwardIter data, boost::crypt::size_t offset, boost::crypt::size_t size) noexcept; - constexpr auto md5_body() noexcept -> void; + BOOST_CRYPT_GPU_ENABLED constexpr auto md5_body() noexcept -> void; public: - constexpr auto init() noexcept -> void; + BOOST_CRYPT_GPU_ENABLED constexpr auto init() noexcept -> void; template - constexpr auto process_byte(ByteType byte) noexcept + BOOST_CRYPT_GPU_ENABLED constexpr auto process_byte(ByteType byte) noexcept BOOST_CRYPT_REQUIRES_CONVERSION(ByteType, boost::crypt::uint8_t); template - constexpr auto process_bytes(ForwardIter buffer, boost::crypt::size_t byte_count) noexcept; + BOOST_CRYPT_GPU_ENABLED constexpr auto process_bytes(ForwardIter buffer, boost::crypt::size_t byte_count) noexcept; template - constexpr auto get_digest(DigestType digest, boost::crypt::size_t digest_size) noexcept; + BOOST_CRYPT_GPU_ENABLED constexpr auto get_digest(DigestType digest, boost::crypt::size_t digest_size) noexcept; }; -constexpr auto md5_hasher::init() noexcept -> void +BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::init() noexcept -> void { a0_ = 0x67452301U; b0_ = 0xefcdab89U; @@ -105,7 +105,7 @@ constexpr auto md5_hasher::init() noexcept -> void blocks_.fill(0U); } -constexpr auto md5_hasher::md5_convert_buffer_to_blocks() noexcept +BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::md5_convert_buffer_to_blocks() noexcept { boost::crypt::size_t buffer_index {}; for (auto& block : blocks_) @@ -122,7 +122,7 @@ constexpr auto md5_hasher::md5_convert_buffer_to_blocks() noexcept } template -constexpr auto md5_hasher::md5_copy_data(ForwardIter data, boost::crypt::size_t offset, boost::crypt::size_t size) noexcept +BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::md5_copy_data(ForwardIter data, boost::crypt::size_t offset, boost::crypt::size_t size) noexcept { for (boost::crypt::size_t i {}; i < size; ++i) { @@ -132,7 +132,7 @@ constexpr auto md5_hasher::md5_copy_data(ForwardIter data, boost::crypt::size_t } template -constexpr auto md5_hasher::md5_update(ForwardIter data, boost::crypt::size_t size) noexcept +BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::md5_update(ForwardIter data, boost::crypt::size_t size) noexcept { const auto input_bits {size << 3U}; // Convert size to bits const auto old_low {low_}; @@ -177,7 +177,7 @@ constexpr auto md5_hasher::md5_update(ForwardIter data, boost::crypt::size_t siz } template -constexpr auto md5_hasher::get_digest(DigestType digest, boost::crypt::size_t digest_size) noexcept +BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::get_digest(DigestType digest, boost::crypt::size_t digest_size) noexcept { auto used {(low_ >> 3U) & 0x3F}; // Number of bytes used in buffer buffer_[used++] = 0x80; @@ -221,20 +221,20 @@ constexpr auto md5_hasher::get_digest(DigestType digest, boost::crypt::size_t di } template -constexpr auto md5_hasher::process_byte(ByteType byte) noexcept +BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::process_byte(ByteType byte) noexcept BOOST_CRYPT_REQUIRES_CONVERSION(ByteType, boost::crypt::uint8_t) { md5_update(&byte, 1UL); } template -constexpr auto md5_hasher::process_bytes(ForwardIter buffer, boost::crypt::size_t byte_count) noexcept +BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::process_bytes(ForwardIter buffer, boost::crypt::size_t byte_count) noexcept { md5_update(buffer, byte_count); } // TODO(mborland): Replace the loop with the known statements -constexpr auto md5_hasher::md5_body() noexcept -> void +BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::md5_body() noexcept -> void { boost::crypt::uint32_t A {a0_}; boost::crypt::uint32_t B {b0_}; @@ -283,7 +283,7 @@ constexpr auto md5_hasher::md5_body() noexcept -> void } template , typename T> -ResultType md5(T begin, T end) +BOOST_CRYPT_GPU_ENABLED constexpr ResultType md5(T begin, T end) noexcept { if (end < begin) { @@ -303,7 +303,7 @@ ResultType md5(T begin, T end) } template > -ResultType md5(const char* str) +BOOST_CRYPT_GPU_ENABLED ResultType md5(const char* str) noexcept { if (str == nullptr) { @@ -314,15 +314,17 @@ ResultType md5(const char* str) return md5(str, str + message_len); } +// ----- String and String view aren't in the libcu++ STL so they so not have device markers ----- + template > -ResultType md5(const std::string& str) +constexpr ResultType md5(const std::string& str) noexcept { return md5(str.begin(), str.end()); } #ifdef BOOST_CRYPT_HAS_STRING_VIEW template > -ResultType md5(const std::string_view& str) +constexpr ResultType md5(const std::string_view& str) { return md5(str.begin(), str.end()); } diff --git a/include/boost/crypt/utility/array.hpp b/include/boost/crypt/utility/array.hpp index a70107d..1a41c68 100644 --- a/include/boost/crypt/utility/array.hpp +++ b/include/boost/crypt/utility/array.hpp @@ -30,30 +30,30 @@ class array T elements[N]; // Iterators - constexpr auto begin() noexcept -> iterator { return elements; } - constexpr auto cbegin() const noexcept -> const_iterator { return elements; } - constexpr auto end() noexcept -> iterator { return elements + N; } - constexpr auto cend() const noexcept -> const_iterator { return elements + N; } + BOOST_CRYPT_GPU_ENABLED constexpr auto begin() noexcept -> iterator { return elements; } + BOOST_CRYPT_GPU_ENABLED constexpr auto cbegin() const noexcept -> const_iterator { return elements; } + BOOST_CRYPT_GPU_ENABLED constexpr auto end() noexcept -> iterator { return elements + N; } + BOOST_CRYPT_GPU_ENABLED constexpr auto cend() const noexcept -> const_iterator { return elements + N; } // Sizing - constexpr auto size() noexcept -> size_type { return N; } - constexpr auto max_size() noexcept -> size_type { return N; } + BOOST_CRYPT_GPU_ENABLED constexpr auto size() noexcept -> size_type { return N; } + BOOST_CRYPT_GPU_ENABLED constexpr auto max_size() noexcept -> size_type { return N; } // Accessors - constexpr auto operator[](size_type n) noexcept -> reference + BOOST_CRYPT_GPU_ENABLED constexpr auto operator[](size_type n) noexcept -> reference { BOOST_CRYPT_ASSERT(n < N); return elements[n]; } - constexpr auto operator[](size_type n) const noexcept -> const_reference + BOOST_CRYPT_GPU_ENABLED constexpr auto operator[](size_type n) const noexcept -> const_reference { BOOST_CRYPT_ASSERT(n < N); return elements[n]; } // For at instead of throwing on out of range return the last element since throwing doesn't work on device - constexpr auto at(size_type n) noexcept -> reference + BOOST_CRYPT_GPU_ENABLED constexpr auto at(size_type n) noexcept -> reference { if (n >= N) { @@ -62,7 +62,7 @@ class array return elements[n]; } - constexpr auto at(size_type n) const noexcept -> const_reference + BOOST_CRYPT_GPU_ENABLED constexpr auto at(size_type n) const noexcept -> const_reference { if (n >= N) { @@ -72,16 +72,16 @@ class array } // Front and back - constexpr auto front() noexcept -> reference { return elements[0]; } - constexpr auto front() const noexcept -> const_reference { return elements[0]; } - constexpr auto back() noexcept -> reference { return elements[N - 1]; } - constexpr auto back() const noexcept -> const_reference { return elements[N - 1]; } + BOOST_CRYPT_GPU_ENABLED constexpr auto front() noexcept -> reference { return elements[0]; } + BOOST_CRYPT_GPU_ENABLED constexpr auto front() const noexcept -> const_reference { return elements[0]; } + BOOST_CRYPT_GPU_ENABLED constexpr auto back() noexcept -> reference { return elements[N - 1]; } + BOOST_CRYPT_GPU_ENABLED constexpr auto back() const noexcept -> const_reference { return elements[N - 1]; } - constexpr auto data() noexcept -> pointer { return elements; } - constexpr auto data() const noexcept -> const_pointer { return elements; } + BOOST_CRYPT_GPU_ENABLED constexpr auto data() noexcept -> pointer { return elements; } + BOOST_CRYPT_GPU_ENABLED constexpr auto data() const noexcept -> const_pointer { return elements; } // Fill and swap - constexpr auto fill(const value_type& v) -> void + BOOST_CRYPT_GPU_ENABLED constexpr auto fill(const value_type& v) -> void { for (size_type i {}; i < N; ++i) { @@ -89,7 +89,7 @@ class array } } - constexpr auto swap(array& a) + BOOST_CRYPT_GPU_ENABLED constexpr auto swap(array& a) { const auto temp {a}; a = *this; @@ -98,7 +98,7 @@ class array }; template -constexpr auto fill_array(ForwardIter first, ForwardIter last, T value) +BOOST_CRYPT_GPU_ENABLED constexpr auto fill_array(ForwardIter first, ForwardIter last, T value) { while (first != last) { diff --git a/include/boost/crypt/utility/bit.hpp b/include/boost/crypt/utility/bit.hpp index 55b2ec4..b0d679f 100644 --- a/include/boost/crypt/utility/bit.hpp +++ b/include/boost/crypt/utility/bit.hpp @@ -16,18 +16,18 @@ namespace detail { // Forward decls template ::value, bool> = true> -constexpr T rotl(T x, U s) noexcept; +BOOST_CRYPT_GPU_ENABLED constexpr T rotl(T x, U s) noexcept; template ::value, bool> = true> -constexpr T rotl(T x, U s) noexcept; +BOOST_CRYPT_GPU_ENABLED constexpr T rotl(T x, U s) noexcept; template ::value, bool> = true> -constexpr T rotr(T x, U s) noexcept; +BOOST_CRYPT_GPU_ENABLED constexpr T rotr(T x, U s) noexcept; template ::value, bool> = true> -constexpr T rotr(T x, U s) noexcept; +BOOST_CRYPT_GPU_ENABLED constexpr T rotr(T x, U s) noexcept; // Only works for unsigned s so we can optimize away the call to rotr template ::value, bool>> -constexpr T rotl(T x, U s) noexcept +BOOST_CRYPT_GPU_ENABLED constexpr T rotl(T x, U s) noexcept { constexpr auto N {boost::crypt::numeric_limits::digits}; const auto r {s % N}; @@ -41,7 +41,7 @@ constexpr T rotl(T x, U s) noexcept } template ::value, bool>> -constexpr T rotl(T x, U s) noexcept +BOOST_CRYPT_GPU_ENABLED constexpr T rotl(T x, U s) noexcept { constexpr auto N {boost::crypt::numeric_limits::digits}; const auto r {s % N}; @@ -59,7 +59,7 @@ constexpr T rotl(T x, U s) noexcept } template ::value, bool>> -constexpr T rotr(T x, U s) noexcept +BOOST_CRYPT_GPU_ENABLED constexpr T rotr(T x, U s) noexcept { constexpr auto N {boost::crypt::numeric_limits::digits}; const auto r {s % N}; @@ -73,7 +73,7 @@ constexpr T rotr(T x, U s) noexcept } template ::value, bool>> -constexpr T rotr(T x, U s) noexcept +BOOST_CRYPT_GPU_ENABLED constexpr T rotr(T x, U s) noexcept { constexpr auto N {boost::crypt::numeric_limits::digits}; const auto r {s % N}; @@ -90,7 +90,7 @@ constexpr T rotr(T x, U s) noexcept return (x >> r) | (x << (N - r)); } -constexpr auto swap_endian(const boost::crypt::uint32_t val) -> boost::crypt::uint32_t +BOOST_CRYPT_GPU_ENABLED constexpr auto swap_endian(const boost::crypt::uint32_t val) -> boost::crypt::uint32_t { return ((val & 0xFF000000) >> 24U) | ((val & 0x00FF0000) >> 8U) | diff --git a/include/boost/crypt/utility/strlen.hpp b/include/boost/crypt/utility/strlen.hpp index e81acd4..6f6e385 100644 --- a/include/boost/crypt/utility/strlen.hpp +++ b/include/boost/crypt/utility/strlen.hpp @@ -12,7 +12,7 @@ namespace crypt { namespace utility { template -constexpr auto strlen(ForwardIter str) noexcept -> boost::crypt::size_t +BOOST_CRYPT_GPU_ENABLED constexpr auto strlen(ForwardIter str) noexcept -> boost::crypt::size_t { boost::crypt::size_t len {}; while (*(str + len) != static_cast('\0')) From 5887c9376ee7681c05f0a67a2739a9f920413b70 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 11 Oct 2024 14:04:24 -0400 Subject: [PATCH 063/107] Switch test over to 8 bits instead of 32 --- test/test_md5.cpp | 73 ++++++++++++++++++++++++++++------------------- 1 file changed, 43 insertions(+), 30 deletions(-) diff --git a/test/test_md5.cpp b/test/test_md5.cpp index 870c1e4..838eee3 100644 --- a/test/test_md5.cpp +++ b/test/test_md5.cpp @@ -11,17 +11,26 @@ #include #include -constexpr std::array, 9> test_values = +constexpr std::array>, 9> test_values = { - std::make_tuple("The quick brown fox jumps over the lazy dog", 0x9e107d9d, 0x372bb682, 0x6bd81d35, 0x42a419d6), - std::make_tuple("The quick brown fox jumps over the lazy dog.", 0xe4d909c2, 0x90d0fb1c, 0xa068ffad, 0xdf22cbd0), - std::make_tuple("", 0xd41d8cd9, 0x8f00b204, 0xe9800998, 0xecf8427e), - std::make_tuple("ddcc8542894a27456bbeb43f51f38764c32f72ae", 0x3b340f00, 0x97312ec8, 0x2fa4da0d, 0x7da53002), - std::make_tuple("webmin1980", 0xb78aae35, 0x6709f8c3, 0x1118ea61, 0x3980954b), - std::make_tuple("$2y$10$EQAmcJw0cg.rt.6..SJ2bulFhDo0eWtuMhkfDMPGsNdap4xrOY61K", 0x40bbe664, 0x4efd9354, 0x078d8c70, 0xfb6c9f42), - std::make_tuple("pkirsanov", 0x8793ce04, 0xf0c5f1e8, 0xed1e0c78, 0xf249fe1b), - std::make_tuple("Eleanor", 0xd37e4317, 0x4905de70, 0xfbb5b038, 0xd7247f57), - std::make_tuple("The Whirlpool Galaxy is about 88% the size of the Milky Way, with a diameter of 76,900 light-years", 0xd5dfd7b4, 0x1235abc7, 0xa9a3205b, 0x6896f34d), + std::make_tuple("The quick brown fox jumps over the lazy dog", + std::array{0x9e, 0x10, 0x7d, 0x9d, 0x37, 0x2b, 0xb6, 0x82, 0x6b, 0xd8, 0x1d, 0x35, 0x42, 0xa4, 0x19, 0xd6}), + std::make_tuple("The quick brown fox jumps over the lazy dog.", + std::array{0xe4, 0xd9, 0x09, 0xc2, 0x90, 0xd0, 0xfb, 0x1c, 0xa0, 0x68, 0xff, 0xad, 0xdf, 0x22, 0xcb, 0xd0}), + std::make_tuple("", + std::array{0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04, 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e}), + std::make_tuple("ddcc8542894a27456bbeb43f51f38764c32f72ae", + std::array{0x3b, 0x34, 0x0f, 0x00, 0x97, 0x31, 0x2e, 0xc8, 0x2f, 0xa4, 0xda, 0x0d, 0x7d, 0xa5, 0x30, 0x02}), + std::make_tuple("webmin1980", + std::array{0xb7, 0x8a, 0xae, 0x35, 0x67, 0x09, 0xf8, 0xc3, 0x11, 0x18, 0xea, 0x61, 0x39, 0x80, 0x95, 0x4b}), + std::make_tuple("$2y$10$EQAmcJw0cg.rt.6..SJ2bulFhDo0eWtuMhkfDMPGsNdap4xrOY61K", + std::array{0x40, 0xbb, 0xe6, 0x64, 0x4e, 0xfd, 0x93, 0x54, 0x07, 0x8d, 0x8c, 0x70, 0xfb, 0x6c, 0x9f, 0x42}), + std::make_tuple("pkirsanov", + std::array{0x87, 0x93, 0xce, 0x04, 0xf0, 0xc5, 0xf1, 0xe8, 0xed, 0x1e, 0x0c, 0x78, 0xf2, 0x49, 0xfe, 0x1b}), + std::make_tuple("Eleanor", + std::array{0xd3, 0x7e, 0x43, 0x17, 0x49, 0x05, 0xde, 0x70, 0xfb, 0xb5, 0xb0, 0x38, 0xd7, 0x24, 0x7f, 0x57}), + std::make_tuple("The Whirlpool Galaxy is about 88% the size of the Milky Way, with a diameter of 76,900 light-years", + std::array{0xd5, 0xdf, 0xd7, 0xb4, 0x12, 0x35, 0xab, 0xc7, 0xa9, 0xa3, 0x20, 0x5b, 0x68, 0x96, 0xf3, 0x4d}), }; void basic_tests() @@ -29,12 +38,13 @@ void basic_tests() for (const auto& test_value : test_values) { const auto message_result {boost::crypt::md5(std::get<0>(test_value))}; - if (!(BOOST_TEST_EQ(message_result[0], std::get<1>(test_value)) && - BOOST_TEST_EQ(message_result[1], std::get<2>(test_value)) && - BOOST_TEST_EQ(message_result[2], std::get<3>(test_value)) && - BOOST_TEST_EQ(message_result[3], std::get<4>(test_value)))) + const auto valid_result {std::get<1>(test_value)}; + for (std::size_t i {}; i < message_result.size(); ++i) { - std::cerr << "Failure with message: " << std::get<0>(test_value) << '\n'; + if (!BOOST_TEST_EQ(message_result[i], valid_result[i])) + { + std::cerr << "Failure with: " << std::get<0>(test_value) << '\n'; + } } } } @@ -45,12 +55,13 @@ void string_test() { const std::string string_message {std::get<0>(test_value)}; const auto message_result {boost::crypt::md5(string_message)}; - if (!(BOOST_TEST_EQ(message_result[0], std::get<1>(test_value)) && - BOOST_TEST_EQ(message_result[1], std::get<2>(test_value)) && - BOOST_TEST_EQ(message_result[2], std::get<3>(test_value)) && - BOOST_TEST_EQ(message_result[3], std::get<4>(test_value)))) + const auto valid_result {std::get<1>(test_value)}; + for (std::size_t i {}; i < message_result.size(); ++i) { - std::cerr << "Failure with message: " << std::get<0>(test_value) << '\n'; + if (!BOOST_TEST_EQ(message_result[i], valid_result[i])) + { + std::cerr << "Failure with: " << std::get<0>(test_value) << '\n'; + } } } } @@ -63,12 +74,13 @@ void string_view_test() 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::md5(string_view_message)}; - if (!(BOOST_TEST_EQ(message_result[0], std::get<1>(test_value)) && - BOOST_TEST_EQ(message_result[1], std::get<2>(test_value)) && - BOOST_TEST_EQ(message_result[2], std::get<3>(test_value)) && - BOOST_TEST_EQ(message_result[3], std::get<4>(test_value)))) + const auto valid_result {std::get<1>(test_value)}; + for (std::size_t i {}; i < message_result.size(); ++i) { - std::cerr << "Failure with message: " << std::get<0>(test_value) << '\n'; + if (!BOOST_TEST_EQ(message_result[i], valid_result[i])) + { + std::cerr << "Failure with: " << std::get<0>(test_value) << '\n'; + } } } #endif @@ -94,12 +106,13 @@ void test_class() std::array message_result {}; hasher.get_digest(message_result.begin(), message_result.size()); - if (!(BOOST_TEST_EQ(message_result[0], std::get<1>(test_value)) && - BOOST_TEST_EQ(message_result[1], std::get<2>(test_value)) && - BOOST_TEST_EQ(message_result[2], std::get<3>(test_value)) && - BOOST_TEST_EQ(message_result[3], std::get<4>(test_value)))) + const auto valid_result {std::get<1>(test_value)}; + for (std::size_t i {}; i < message_result.size(); ++i) { - std::cerr << "Failure with message: " << std::get<0>(test_value) << '\n'; + if (!BOOST_TEST_EQ(message_result[i], valid_result[i])) + { + std::cerr << "Failure with: " << std::get<0>(test_value) << '\n'; + } } hasher.init(); From 019f2c543252447fbd661c431753010962119216 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 11 Oct 2024 14:04:37 -0400 Subject: [PATCH 064/107] Add more const markers --- include/boost/crypt/utility/array.hpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/boost/crypt/utility/array.hpp b/include/boost/crypt/utility/array.hpp index 1a41c68..302aefa 100644 --- a/include/boost/crypt/utility/array.hpp +++ b/include/boost/crypt/utility/array.hpp @@ -31,13 +31,15 @@ class array // Iterators BOOST_CRYPT_GPU_ENABLED constexpr auto begin() noexcept -> iterator { return elements; } + BOOST_CRYPT_GPU_ENABLED constexpr auto begin() const noexcept -> iterator { return elements; } BOOST_CRYPT_GPU_ENABLED constexpr auto cbegin() const noexcept -> const_iterator { return elements; } BOOST_CRYPT_GPU_ENABLED constexpr auto end() noexcept -> iterator { return elements + N; } + BOOST_CRYPT_GPU_ENABLED constexpr auto end() const noexcept -> iterator { return elements + N; } BOOST_CRYPT_GPU_ENABLED constexpr auto cend() const noexcept -> const_iterator { return elements + N; } // Sizing - BOOST_CRYPT_GPU_ENABLED constexpr auto size() noexcept -> size_type { return N; } - BOOST_CRYPT_GPU_ENABLED constexpr auto max_size() noexcept -> size_type { return N; } + BOOST_CRYPT_GPU_ENABLED constexpr auto size() const noexcept -> size_type { return N; } + BOOST_CRYPT_GPU_ENABLED constexpr auto max_size() const noexcept -> size_type { return N; } // Accessors BOOST_CRYPT_GPU_ENABLED constexpr auto operator[](size_type n) noexcept -> reference From f777ff60bd1ee83e12a6cf41c89d3dbd172563d0 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 11 Oct 2024 14:16:51 -0400 Subject: [PATCH 065/107] Always return an array of bytes --- include/boost/crypt/hash/md5.hpp | 50 +++++++++++++++----------------- test/test_md5.cpp | 7 +++-- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/include/boost/crypt/hash/md5.hpp b/include/boost/crypt/hash/md5.hpp index 91deb09..edf3e8c 100644 --- a/include/boost/crypt/hash/md5.hpp +++ b/include/boost/crypt/hash/md5.hpp @@ -87,8 +87,7 @@ class md5_hasher template BOOST_CRYPT_GPU_ENABLED constexpr auto process_bytes(ForwardIter buffer, boost::crypt::size_t byte_count) noexcept; - template - BOOST_CRYPT_GPU_ENABLED constexpr auto get_digest(DigestType digest, boost::crypt::size_t digest_size) noexcept; + BOOST_CRYPT_GPU_ENABLED constexpr auto get_digest() noexcept -> boost::crypt::array; }; BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::init() noexcept -> void @@ -176,9 +175,9 @@ BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::md5_update(ForwardIter data, } } -template -BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::get_digest(DigestType digest, boost::crypt::size_t digest_size) noexcept +BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::get_digest() noexcept -> boost::crypt::array { + boost::crypt::array digest {}; auto used {(low_ >> 3U) & 0x3F}; // Number of bytes used in buffer buffer_[used++] = 0x80; auto available {buffer_.size() - used}; @@ -196,7 +195,7 @@ BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::get_digest(DigestType digest, fill_array(buffer_.begin() + used, buffer_.end() - 8, static_cast(0)); } - uint64_t total_bits = (static_cast(high_) << 32) | low_; + const auto total_bits {(static_cast(high_) << 32) | low_}; // Append the length in bits as a 64-bit little-endian integer buffer_[56] = static_cast(total_bits & 0xFF); @@ -211,13 +210,16 @@ BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::get_digest(DigestType digest, md5_convert_buffer_to_blocks(); md5_body(); - if (digest_size >= 4) + for (boost::crypt::size_t i = 0; i < 4; ++i) { - digest[0] = detail::swap_endian(a0_); - digest[1] = detail::swap_endian(b0_); - digest[2] = detail::swap_endian(c0_); - digest[3] = detail::swap_endian(d0_); + const auto value {(i == 0 ? a0_ : (i == 1 ? b0_ : (i == 2 ? c0_ : d0_)))}; + digest[i*4] = static_cast(value & 0xFF); + digest[i*4 + 1] = static_cast((value >> 8U) & 0xFF); + digest[i*4 + 2] = static_cast((value >> 16U) & 0xFF); + digest[i*4 + 3] = static_cast((value >> 24U) & 0xFF); } + + return digest; } template @@ -282,51 +284,47 @@ BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::md5_body() noexcept -> void d0_ += D; } -template , typename T> -BOOST_CRYPT_GPU_ENABLED constexpr ResultType md5(T begin, T end) noexcept +template +BOOST_CRYPT_GPU_ENABLED constexpr auto md5(T begin, T end) noexcept -> boost::crypt::array { if (end < begin) { - return ResultType {0, 0, 0, 0}; + return boost::crypt::array {}; } else if (end == begin) { - return ResultType{0xd41d8cd9, 0x8f00b204, 0xe9800998, 0xecf8427e}; + return boost::crypt::array{0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04, 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e}; } boost::crypt::md5_hasher hasher; hasher.process_bytes(begin, static_cast(end - begin)); - ResultType result; - hasher.get_digest(result.begin(), result.size()); + auto result {hasher.get_digest()}; return result; } -template > -BOOST_CRYPT_GPU_ENABLED ResultType md5(const char* str) noexcept +BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const char* str) noexcept -> boost::crypt::array { if (str == nullptr) { - return ResultType {0, 0, 0, 0}; + return boost::crypt::array{}; } const auto message_len {std::strlen(str)}; - return md5(str, str + message_len); + return md5(str, str + message_len); } // ----- String and String view aren't in the libcu++ STL so they so not have device markers ----- -template > -constexpr ResultType md5(const std::string& str) noexcept +inline auto md5(const std::string& str) noexcept -> boost::crypt::array { - return md5(str.begin(), str.end()); + return md5(str.begin(), str.end()); } #ifdef BOOST_CRYPT_HAS_STRING_VIEW -template > -constexpr ResultType md5(const std::string_view& str) +inline auto md5(const std::string_view& str) -> boost::crypt::array { - return md5(str.begin(), str.end()); + return md5(str.begin(), str.end()); } #endif diff --git a/test/test_md5.cpp b/test/test_md5.cpp index 838eee3..365375b 100644 --- a/test/test_md5.cpp +++ b/test/test_md5.cpp @@ -44,6 +44,7 @@ void basic_tests() if (!BOOST_TEST_EQ(message_result[i], valid_result[i])) { std::cerr << "Failure with: " << std::get<0>(test_value) << '\n'; + break; } } } @@ -61,6 +62,7 @@ void string_test() if (!BOOST_TEST_EQ(message_result[i], valid_result[i])) { std::cerr << "Failure with: " << std::get<0>(test_value) << '\n'; + break; } } } @@ -80,6 +82,7 @@ void string_view_test() if (!BOOST_TEST_EQ(message_result[i], valid_result[i])) { std::cerr << "Failure with: " << std::get<0>(test_value) << '\n'; + break; } } } @@ -103,8 +106,7 @@ void test_class() { const auto msg {std::get<0>(test_value)}; hasher.process_bytes(msg, std::strlen(msg)); - std::array message_result {}; - hasher.get_digest(message_result.begin(), message_result.size()); + const auto message_result {hasher.get_digest()}; const auto valid_result {std::get<1>(test_value)}; for (std::size_t i {}; i < message_result.size(); ++i) @@ -112,6 +114,7 @@ void test_class() if (!BOOST_TEST_EQ(message_result[i], valid_result[i])) { std::cerr << "Failure with: " << std::get<0>(test_value) << '\n'; + break; } } From 5269ece9ab13bb5aaa327e42167348f9518a8aeb Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 11 Oct 2024 16:45:00 -0400 Subject: [PATCH 066/107] Unroll the hash loop --- include/boost/crypt/hash/md5.hpp | 204 ++++++++++++++++++++----------- 1 file changed, 133 insertions(+), 71 deletions(-) diff --git a/include/boost/crypt/hash/md5.hpp b/include/boost/crypt/hash/md5.hpp index edf3e8c..a8f3099 100644 --- a/include/boost/crypt/hash/md5.hpp +++ b/include/boost/crypt/hash/md5.hpp @@ -23,36 +23,6 @@ namespace boost { namespace crypt { -namespace detail { - -static constexpr boost::crypt::array S { - 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, - 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, - 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, - 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 -}; - -static constexpr boost::crypt::array K { - 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, - 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, - 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, - 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, - 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, - 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, - 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, - 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, - 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, - 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, - 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, - 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, - 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, - 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, - 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, - 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 -}; - -} // namespace detail - class md5_hasher { private: @@ -235,53 +205,145 @@ BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::process_bytes(ForwardIter buf md5_update(buffer, byte_count); } -// TODO(mborland): Replace the loop with the known statements -BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::md5_body() noexcept -> void +// See: Applied Cryptography - Bruce Schneier +// Section 18.5 +namespace md5_body_detail { + +BOOST_CRYPT_GPU_ENABLED constexpr auto F(boost::crypt::uint32_t x, boost::crypt::uint32_t y, boost::crypt::uint32_t z) noexcept { - boost::crypt::uint32_t A {a0_}; - boost::crypt::uint32_t B {b0_}; - boost::crypt::uint32_t C {c0_}; - boost::crypt::uint32_t D {d0_}; + return (x & y) | ((~x) & z); +} - for (boost::crypt::uint32_t i {}; i < 64U; ++i) - { - boost::crypt::uint32_t F {}; - boost::crypt::uint32_t g {}; +BOOST_CRYPT_GPU_ENABLED constexpr auto G(boost::crypt::uint32_t x, boost::crypt::uint32_t y, boost::crypt::uint32_t z) noexcept +{ + return (x & z) | (y & (~z)); +} - if (i <= 15U) - { - F = (B & C) | ((~B) & D); - g = i; - } - else if (i <= 31U) - { - F = (D & B) | ((~D) & C); - g = (5U * i + 1U) % 16U; - } - else if (i <= 47U) - { - F = B ^ C ^ D; - g = (3U * i + 5U) % 16U; - } - else - { - F = C ^ (B | (~D)); - g = (7U * i) % 16U; - } +BOOST_CRYPT_GPU_ENABLED constexpr auto H(boost::crypt::uint32_t x, boost::crypt::uint32_t y, boost::crypt::uint32_t z) noexcept +{ + return x ^ y ^ z; +} - BOOST_CRYPT_ASSERT(i <= 63U); +BOOST_CRYPT_GPU_ENABLED constexpr auto I(boost::crypt::uint32_t x, boost::crypt::uint32_t y, boost::crypt::uint32_t z) noexcept +{ + return y ^ (x | (~z)); +} - F = F + A + detail::K[i] + blocks_[g]; - A = D; - D = C; - C = B; - B = B + detail::rotl(F, detail::S[i]); - } +BOOST_CRYPT_GPU_ENABLED constexpr auto FF(boost::crypt::uint32_t& a, boost::crypt::uint32_t b, boost::crypt::uint32_t c, + boost::crypt::uint32_t d, boost::crypt::uint32_t Mj, boost::crypt::uint32_t si, + boost::crypt::uint32_t ti) noexcept +{ + a = b + detail::rotl((a + F(b, c, d) + Mj + ti), si); +} + +BOOST_CRYPT_GPU_ENABLED constexpr auto GG(boost::crypt::uint32_t& a, boost::crypt::uint32_t b, boost::crypt::uint32_t c, + boost::crypt::uint32_t d, boost::crypt::uint32_t Mj, boost::crypt::uint32_t si, + boost::crypt::uint32_t ti) noexcept +{ + a = b + detail::rotl((a + G(b, c, d) + Mj + ti), si); +} - a0_ += A; - b0_ += B; - c0_ += C; - d0_ += D; +BOOST_CRYPT_GPU_ENABLED constexpr auto HH(boost::crypt::uint32_t& a, boost::crypt::uint32_t b, boost::crypt::uint32_t c, + boost::crypt::uint32_t d, boost::crypt::uint32_t Mj, boost::crypt::uint32_t si, + boost::crypt::uint32_t ti) noexcept +{ + a = b + detail::rotl((a + H(b, c, d) + Mj + ti), si); +} + +BOOST_CRYPT_GPU_ENABLED constexpr auto II(boost::crypt::uint32_t& a, boost::crypt::uint32_t b, boost::crypt::uint32_t c, + boost::crypt::uint32_t d, boost::crypt::uint32_t Mj, boost::crypt::uint32_t si, + boost::crypt::uint32_t ti) noexcept +{ + a = b + detail::rotl((a + I(b, c, d) + Mj + ti), si); +} + +} // md5_body_detail + +BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::md5_body() noexcept -> void +{ + using namespace md5_body_detail; + + boost::crypt::uint32_t a {a0_}; + boost::crypt::uint32_t b {b0_}; + boost::crypt::uint32_t c {c0_}; + boost::crypt::uint32_t d {d0_}; + + // Round 1 + FF(a, b, c, d, blocks_[0], 7, 0xd76aa478); + FF(d, a, b, c, blocks_[1], 12, 0xe8c7b756); + FF(c, d, a, b, blocks_[2], 17, 0x242070db); + FF(b, c, d, a, blocks_[3], 22, 0xc1bdceee); + FF(a, b, c, d, blocks_[4], 7, 0xf57c0faf); + FF(d, a, b, c, blocks_[5], 12, 0x4787c62a); + FF(c, d, a, b, blocks_[6], 17, 0xa8304613); + FF(b, c, d, a, blocks_[7], 22, 0xfd469501); + FF(a, b, c, d, blocks_[8], 7, 0x698098d8); + FF(d, a, b, c, blocks_[9], 12, 0x8b44f7af); + FF(c, d, a, b, blocks_[10], 17, 0xffff5bb1); + FF(b, c, d, a, blocks_[11], 22, 0x895cd7be); + FF(a, b, c, d, blocks_[12], 7, 0x6b901122); + FF(d, a, b, c, blocks_[13], 12, 0xfd987193); + FF(c, d, a, b, blocks_[14], 17, 0xa679438e); + FF(b, c, d, a, blocks_[15], 22, 0x49b40821); + + // Round 2 + GG(a, b, c, d, blocks_[1], 5, 0xf61e2562); + GG(d, a, b, c, blocks_[6], 9, 0xc040b340); + GG(c, d, a, b, blocks_[11], 14, 0x265e5a51); + GG(b, c, d, a, blocks_[0], 20, 0xe9b6c7aa); + GG(a, b, c, d, blocks_[5], 5, 0xd62f105d); + GG(d, a, b, c, blocks_[10], 9, 0x02441453); + GG(c, d, a, b, blocks_[15], 14, 0xd8a1e681); + GG(b, c, d, a, blocks_[4], 20, 0xe7d3fbc8); + GG(a, b, c, d, blocks_[9], 5, 0x21e1cde6); + GG(d, a, b, c, blocks_[14], 9, 0xc33707d6); + GG(c, d, a, b, blocks_[3], 14, 0xf4d50d87); + GG(b, c, d, a, blocks_[8], 20, 0x455a14ed); + GG(a, b, c, d, blocks_[13], 5, 0xa9e3e905); + GG(d, a, b, c, blocks_[2], 9, 0xfcefa3f8); + GG(c, d, a, b, blocks_[7], 14, 0x676f02d9); + GG(b, c, d, a, blocks_[12], 20, 0x8d2a4c8a); + + // Round 3 + HH(a, b, c, d, blocks_[5], 4, 0xfffa3942); + HH(d, a, b, c, blocks_[8], 11, 0x8771f681); + HH(c, d, a, b, blocks_[11], 16, 0x6d9d6122); + HH(b, c, d, a, blocks_[14], 23, 0xfde5380c); + HH(a, b, c, d, blocks_[1], 4, 0xa4beea44); + HH(d, a, b, c, blocks_[4], 11, 0x4bdecfa9); + HH(c, d, a, b, blocks_[7], 16, 0xf6bb4b60); + HH(b, c, d, a, blocks_[10], 23, 0xbebfbc70); + HH(a, b, c, d, blocks_[13], 4, 0x289b7ec6); + HH(d, a, b, c, blocks_[0], 11, 0xeaa127fa); + HH(c, d, a, b, blocks_[3], 16, 0xd4ef3085); + HH(b, c, d, a, blocks_[6], 23, 0x04881d05); + HH(a, b, c, d, blocks_[9], 4, 0xd9d4d039); + HH(d, a, b, c, blocks_[12], 11, 0xe6db99e5); + HH(c, d, a, b, blocks_[15], 16, 0x1fa27cf8); + HH(b, c, d, a, blocks_[2], 23, 0xc4ac5665); + + // Round 4 + II(a, b, c, d, blocks_[0], 6, 0xf4292244); + II(d, a, b, c, blocks_[7], 10, 0x432aff97); + II(c, d, a, b, blocks_[14], 15, 0xab9423a7); + II(b, c, d, a, blocks_[5], 21, 0xfc93a039); + II(a, b, c, d, blocks_[12], 6, 0x655b59c3); + II(d, a, b, c, blocks_[3], 10, 0x8f0ccc92); + II(c, d, a, b, blocks_[10], 15, 0xffeff47d); + II(b, c, d, a, blocks_[1], 21, 0x85845dd1); + II(a, b, c, d, blocks_[8], 6, 0x6fa87e4f); + II(d, a, b, c, blocks_[15], 10, 0xfe2ce6e0); + II(c, d, a, b, blocks_[6], 15, 0xa3014314); + II(b, c, d, a, blocks_[13], 21, 0x4e0811a1); + II(a, b, c, d, blocks_[4], 6, 0xf7537e82); + II(d, a, b, c, blocks_[11], 10, 0xbd3af235); + II(c, d, a, b, blocks_[2], 15, 0x2ad7d2bb); + II(b, c, d, a, blocks_[9], 21, 0xeb86d391); + + a0_ += a; + b0_ += b; + c0_ += c; + d0_ += d; } template From 241961a680c64044266d59d39996fe484f5def60 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 11 Oct 2024 16:50:38 -0400 Subject: [PATCH 067/107] Add pointer + len interface --- include/boost/crypt/hash/md5.hpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/include/boost/crypt/hash/md5.hpp b/include/boost/crypt/hash/md5.hpp index a8f3099..680722a 100644 --- a/include/boost/crypt/hash/md5.hpp +++ b/include/boost/crypt/hash/md5.hpp @@ -372,10 +372,20 @@ BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const char* str) noexcept -> boost::c return boost::crypt::array{}; } - const auto message_len {std::strlen(str)}; + const auto message_len {utility::strlen(str)}; return md5(str, str + message_len); } +BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const char* str, boost::crypt::size_t len) noexcept -> boost::crypt::array +{ + if (str == nullptr) + { + return boost::crypt::array{}; + } + + return md5(str, str + len); +} + // ----- String and String view aren't in the libcu++ STL so they so not have device markers ----- inline auto md5(const std::string& str) noexcept -> boost::crypt::array From ebc10a32e8f2a63f58f341f008faac5b7049f2d4 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 11 Oct 2024 16:51:08 -0400 Subject: [PATCH 068/107] Adding fuzzing to additional interfaces --- fuzzing/fuzz_md5.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fuzzing/fuzz_md5.cpp b/fuzzing/fuzz_md5.cpp index ee70888..a204427 100644 --- a/fuzzing/fuzz_md5.cpp +++ b/fuzzing/fuzz_md5.cpp @@ -15,6 +15,12 @@ extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t* data, std::size_t size std::string c_data_str {c_data, size}; // Guarantee null termination since we can't pass the size argument boost::crypt::md5(c_data_str); + boost::crypt::md5(c_data, size); + + #ifdef BOOST_CRYPT_HAS_STRING_VIEW + std::string_view view {c_data_str}; + boost::crypt::md5(view); + #endif } catch(...) { From dd7e9ae45d0ae4d62a87b7bd754ad32d437070ef Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 11 Oct 2024 16:59:30 -0400 Subject: [PATCH 069/107] Move template pair into detail namespace so we can do u16, u32, etc --- include/boost/crypt/hash/md5.hpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/include/boost/crypt/hash/md5.hpp b/include/boost/crypt/hash/md5.hpp index 680722a..d290a1f 100644 --- a/include/boost/crypt/hash/md5.hpp +++ b/include/boost/crypt/hash/md5.hpp @@ -346,6 +346,8 @@ BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::md5_body() noexcept -> void d0_ += d; } +namespace detail { + template BOOST_CRYPT_GPU_ENABLED constexpr auto md5(T begin, T end) noexcept -> boost::crypt::array { @@ -355,7 +357,9 @@ BOOST_CRYPT_GPU_ENABLED constexpr auto md5(T begin, T end) noexcept -> boost::cr } else if (end == begin) { - return boost::crypt::array{0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04, 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e}; + return boost::crypt::array { + 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04, 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e + }; } boost::crypt::md5_hasher hasher; @@ -365,6 +369,8 @@ BOOST_CRYPT_GPU_ENABLED constexpr auto md5(T begin, T end) noexcept -> boost::cr return result; } +} // Namespace detail + BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const char* str) noexcept -> boost::crypt::array { if (str == nullptr) @@ -373,7 +379,7 @@ BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const char* str) noexcept -> boost::c } const auto message_len {utility::strlen(str)}; - return md5(str, str + message_len); + return detail::md5(str, str + message_len); } BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const char* str, boost::crypt::size_t len) noexcept -> boost::crypt::array @@ -383,20 +389,20 @@ BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const char* str, boost::crypt::size_t return boost::crypt::array{}; } - return md5(str, str + len); + return detail::md5(str, str + len); } // ----- String and String view aren't in the libcu++ STL so they so not have device markers ----- inline auto md5(const std::string& str) noexcept -> boost::crypt::array { - return md5(str.begin(), str.end()); + return detail::md5(str.begin(), str.end()); } #ifdef BOOST_CRYPT_HAS_STRING_VIEW inline auto md5(const std::string_view& str) -> boost::crypt::array { - return md5(str.begin(), str.end()); + return detail::md5(str.begin(), str.end()); } #endif From efa66d0a3c468de643101ec0514f86a9ba9ffe60 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 15 Oct 2024 10:13:46 -0400 Subject: [PATCH 070/107] Add std::uint8_t* interface --- include/boost/crypt/hash/md5.hpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/include/boost/crypt/hash/md5.hpp b/include/boost/crypt/hash/md5.hpp index d290a1f..2fe3e9f 100644 --- a/include/boost/crypt/hash/md5.hpp +++ b/include/boost/crypt/hash/md5.hpp @@ -392,6 +392,27 @@ BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const char* str, boost::crypt::size_t return detail::md5(str, str + len); } +BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const boost::crypt::uint8_t* str) noexcept -> boost::crypt::array +{ + if (str == nullptr) + { + return boost::crypt::array{}; + } + + const auto message_len {utility::strlen(str)}; + return detail::md5(str, str + message_len); +} + +BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const boost::crypt::uint8_t* str, boost::crypt::size_t len) noexcept -> boost::crypt::array +{ + if (str == nullptr) + { + return boost::crypt::array{}; + } + + return detail::md5(str, str + len); +} + // ----- String and String view aren't in the libcu++ STL so they so not have device markers ----- inline auto md5(const std::string& str) noexcept -> boost::crypt::array From 6a300ae13810a996313738fea4eb316e53871540 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 15 Oct 2024 10:13:55 -0400 Subject: [PATCH 071/107] Fuzz and test additional interface --- fuzzing/fuzz_md5.cpp | 1 + test/test_md5.cpp | 20 +++++++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/fuzzing/fuzz_md5.cpp b/fuzzing/fuzz_md5.cpp index a204427..584ccce 100644 --- a/fuzzing/fuzz_md5.cpp +++ b/fuzzing/fuzz_md5.cpp @@ -16,6 +16,7 @@ extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t* data, std::size_t size boost::crypt::md5(c_data_str); boost::crypt::md5(c_data, size); + boost::crypt::md5(data, size); #ifdef BOOST_CRYPT_HAS_STRING_VIEW std::string_view view {c_data_str}; diff --git a/test/test_md5.cpp b/test/test_md5.cpp index 365375b..c757e87 100644 --- a/test/test_md5.cpp +++ b/test/test_md5.cpp @@ -91,11 +91,29 @@ void string_view_test() void bad_input() { - const auto null_message {boost::crypt::md5(nullptr)}; + const auto null_message {boost::crypt::md5(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::md5(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::md5(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::md5(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); } void test_class() From bb860641f114e56cf27e3e00f53e103d6caad730 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 15 Oct 2024 10:41:50 -0400 Subject: [PATCH 072/107] Add random values testing --- test/CMakeLists.txt | 2 +- test/Jamfile | 2 + test/test_md5.cpp | 102 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+), 1 deletion(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index eb31095..6076795 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -7,6 +7,6 @@ include(BoostTestJamfile OPTIONAL RESULT_VARIABLE HAVE_BOOST_TEST) if(HAVE_BOOST_TEST) - boost_test_jamfile(FILE Jamfile LINK_LIBRARIES Boost::crypt Boost::core) + boost_test_jamfile(FILE Jamfile LINK_LIBRARIES Boost::crypt Boost::core Boost::uuid) endif() diff --git a/test/Jamfile b/test/Jamfile index 201cf17..37a5fd3 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -11,6 +11,8 @@ import testing ; project : requirements + /boost/uuid//boost_uuid + gcc:-Wall gcc:-Wextra diff --git a/test/test_md5.cpp b/test/test_md5.cpp index c757e87..97c724b 100644 --- a/test/test_md5.cpp +++ b/test/test_md5.cpp @@ -6,10 +6,71 @@ #include #include + +#ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wconversion" +# pragma clang diagnostic ignored "-Wold-style-cast" +#elif defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wconversion" +# pragma GCC diagnostic ignored "-Wold-style-cast" +#endif + +#include + +#ifdef __clang__ +# pragma clang diagnostic pop +#elif defined(__GNUC__) +# pragma GCC diagnostic pop +#endif + + +#include #include #include #include #include +#include +#include +#include + +void generate_random_cstring(char* str, std::size_t length) +{ + + const char charset[] = "0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz"; + + const std::size_t charset_size = sizeof(charset) - 1; + + std::mt19937_64 rng(42); + std::uniform_int_distribution dist(0, charset_size); + + for (std::size_t i = 0; i < length - 1; ++i) + { + int index = dist(rng); + str[i] = charset[index]; + } + + str[length - 1] = '\0'; +} + +auto get_boost_uuid_result(const char* str, size_t length) +{ + unsigned char digest[16]; + boost::uuids::detail::md5 hasher; + hasher.process_bytes(str, length); + hasher.get_digest(digest); + + std::array return_array {}; + for (std::size_t i {}; i < 16U; ++i) + { + return_array[i] = digest[i]; + } + + return return_array; +} constexpr std::array>, 9> test_values = { @@ -43,8 +104,10 @@ void basic_tests() { if (!BOOST_TEST_EQ(message_result[i], valid_result[i])) { + // LCOV_EXCL_START std::cerr << "Failure with: " << std::get<0>(test_value) << '\n'; break; + // LCOV_EXCL_STOP } } } @@ -61,8 +124,10 @@ void string_test() { if (!BOOST_TEST_EQ(message_result[i], valid_result[i])) { + // LCOV_EXCL_START std::cerr << "Failure with: " << std::get<0>(test_value) << '\n'; break; + // LCOV_EXCL_STOP } } } @@ -81,8 +146,10 @@ void string_view_test() { if (!BOOST_TEST_EQ(message_result[i], valid_result[i])) { + // LCOV_EXCL_START std::cerr << "Failure with: " << std::get<0>(test_value) << '\n'; break; + // LCOV_EXCL_STOP } } } @@ -131,8 +198,10 @@ void test_class() { if (!BOOST_TEST_EQ(message_result[i], valid_result[i])) { + // LCOV_EXCL_START std::cerr << "Failure with: " << std::get<0>(test_value) << '\n'; break; + // LCOV_EXCL_STOP } } @@ -140,6 +209,37 @@ void test_class() } } +void test_random_values() +{ + constexpr std::size_t max_str_len {65535U}; + std::mt19937_64 rng(42); + std::uniform_int_distribution str_len(1, max_str_len - 1); + + char* str {new char[max_str_len]}; + + for (std::size_t i {}; i < 1024; ++i) + { + std::memset(str, '\0', max_str_len); + const std::size_t current_str_len {str_len(rng)}; + generate_random_cstring(str, current_str_len); + const auto uuid_res {get_boost_uuid_result(str, current_str_len)}; + const auto crypt_res {boost::crypt::md5(str, current_str_len)}; + + for (std::size_t j {}; j < crypt_res.size(); ++j) + { + if (!BOOST_TEST_EQ(uuid_res[j], crypt_res[j])) + { + // LCOV_EXCL_START + std::cerr << "Failure with string: " << str << std::endl; + break; + // LCOV_EXCL_STOP + } + } + } + + delete[] str; +} + int main() { basic_tests(); @@ -151,5 +251,7 @@ int main() test_class(); + test_random_values(); + return boost::report_errors(); } From 261461436323942fe6e11866dc856639e28e2b5f Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 15 Oct 2024 11:20:53 -0400 Subject: [PATCH 073/107] Add missing codecov lib --- .github/workflows/codecov.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index e37414c..00694ba 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -49,6 +49,9 @@ jobs: git submodule update --init libs/predef git submodule update --init libs/static_assert git submodule update --init libs/test + git submodule update --init libs/uuid + git submodule update --init libs/throw_exception + git submodule update --init libs/type_traits ./bootstrap.sh ./b2 headers - name: gcc-gcov-native From 70e04ab87fbee70678de5a6368330a388c3042b5 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 15 Oct 2024 11:40:58 -0400 Subject: [PATCH 074/107] Exclude LCOV constexpr lines --- include/boost/crypt/hash/md5.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/boost/crypt/hash/md5.hpp b/include/boost/crypt/hash/md5.hpp index 2fe3e9f..d74061d 100644 --- a/include/boost/crypt/hash/md5.hpp +++ b/include/boost/crypt/hash/md5.hpp @@ -375,7 +375,7 @@ BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const char* str) noexcept -> boost::c { if (str == nullptr) { - return boost::crypt::array{}; + return boost::crypt::array{}; // LCOV_EXCL_LINE } const auto message_len {utility::strlen(str)}; @@ -386,7 +386,7 @@ BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const char* str, boost::crypt::size_t { if (str == nullptr) { - return boost::crypt::array{}; + return boost::crypt::array{}; // LCOV_EXCL_LINE } return detail::md5(str, str + len); @@ -396,7 +396,7 @@ BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const boost::crypt::uint8_t* str) noe { if (str == nullptr) { - return boost::crypt::array{}; + return boost::crypt::array{}; // LCOV_EXCL_LINE } const auto message_len {utility::strlen(str)}; @@ -407,7 +407,7 @@ BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const boost::crypt::uint8_t* str, boo { if (str == nullptr) { - return boost::crypt::array{}; + return boost::crypt::array{}; // LCOV_EXCL_LINE } return detail::md5(str, str + len); From 0dfd72c6ddabf0e3b4f8aed0356b30516c331d73 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 15 Oct 2024 11:41:15 -0400 Subject: [PATCH 075/107] Add piecewise parsing test --- test/test_md5.cpp | 53 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/test/test_md5.cpp b/test/test_md5.cpp index 97c724b..dfd9107 100644 --- a/test/test_md5.cpp +++ b/test/test_md5.cpp @@ -240,6 +240,58 @@ void test_random_values() delete[] str; } +void test_random_piecewise_values() +{ + constexpr std::size_t max_str_len {65535U}; + std::mt19937_64 rng(42); + std::uniform_int_distribution str_len(1, max_str_len - 1); + + char* str {new char[max_str_len]}; + char* str_2 {new char[max_str_len]}; + + for (std::size_t i {}; i < 1024; ++i) + { + boost::uuids::detail::md5 boost_hasher; + boost::crypt::md5_hasher md5_hasher; + + std::memset(str, '\0', max_str_len); + std::memset(str_2, '\0', max_str_len); + + const std::size_t current_str_len {str_len(rng)}; + generate_random_cstring(str, current_str_len); + generate_random_cstring(str_2, current_str_len); + + boost_hasher.process_bytes(str, current_str_len); + boost_hasher.process_bytes(str_2, current_str_len); + unsigned char digest[16]; + boost_hasher.get_digest(digest); + + std::array uuid_res {}; + for (std::size_t j {}; j < 16U; ++j) + { + uuid_res[j] = digest[j]; + } + + md5_hasher.process_bytes(str, current_str_len); + md5_hasher.process_bytes(str_2, current_str_len); + const auto crypt_res {md5_hasher.get_digest()}; + + for (std::size_t j {}; j < crypt_res.size(); ++j) + { + if (!BOOST_TEST_EQ(uuid_res[j], crypt_res[j])) + { + // LCOV_EXCL_START + std::cerr << "Failure with string: " << str << std::endl; + break; + // LCOV_EXCL_STOP + } + } + } + + delete[] str; + delete[] str_2; +} + int main() { basic_tests(); @@ -252,6 +304,7 @@ int main() test_class(); test_random_values(); + test_random_piecewise_values(); return boost::report_errors(); } From 21def3862776e6b4e876dbcf60182186ff37ed17 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 15 Oct 2024 11:58:14 -0400 Subject: [PATCH 076/107] Improve coverage --- test/test_md5.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/test_md5.cpp b/test/test_md5.cpp index dfd9107..67c1e3a 100644 --- a/test/test_md5.cpp +++ b/test/test_md5.cpp @@ -181,6 +181,13 @@ void bad_input() 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::md5(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() @@ -263,6 +270,7 @@ void test_random_piecewise_values() boost_hasher.process_bytes(str, current_str_len); boost_hasher.process_bytes(str_2, current_str_len); + boost_hasher.process_byte(52); // "4" unsigned char digest[16]; boost_hasher.get_digest(digest); @@ -274,6 +282,7 @@ void test_random_piecewise_values() md5_hasher.process_bytes(str, current_str_len); md5_hasher.process_bytes(str_2, current_str_len); + md5_hasher.process_byte(52); // "4" const auto crypt_res {md5_hasher.get_digest()}; for (std::size_t j {}; j < crypt_res.size(); ++j) From 1588ba9eeb4dee5ff5e08e22d7a30665f9928623 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 15 Oct 2024 14:02:09 -0400 Subject: [PATCH 077/107] Add CUDA context definition of iterator traits --- include/boost/crypt/utility/iterator.hpp | 48 ++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 include/boost/crypt/utility/iterator.hpp diff --git a/include/boost/crypt/utility/iterator.hpp b/include/boost/crypt/utility/iterator.hpp new file mode 100644 index 0000000..8b28764 --- /dev/null +++ b/include/boost/crypt/utility/iterator.hpp @@ -0,0 +1,48 @@ +// Copyright 2024 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CRYPT_UTILITES_ITERATOR_HPP +#define BOOST_CRYPT_UTILITES_ITERATOR_HPP + +#include + +#ifdef BOOST_CRYPT_HAS_CUDA + +#include + +namespace boost { +namespace crypt { + +template +struct iterator_traits : public cuda::std::iterator_traits {}; + +template +struct iterator_traits : public cuda::std::iterator_traits {}; + +} // namespace crypt +} // namespace boost + +#else + +#ifndef BOOST_CRYPT_BUILD_MODULE +#include +#endif + +namespace boost { +namespace crypt { +namespace utility { + +template +struct iterator_traits : public std::iterator_traits {}; + +template +struct iterator_traits : public std::iterator_traits {}; + +} // namespace utility +} // namespace crypt +} // namespace boost + +#endif // BOOST_CRYPT_HAS_CUDA + +#endif //BOOST_CRYPT_UTILITES_ITERATOR_HPP From 5594e2078861bd867622b2675de17fde90ab7cf5 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 15 Oct 2024 14:02:21 -0400 Subject: [PATCH 078/107] Fix type_traits use for module --- include/boost/crypt/utility/type_traits.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/boost/crypt/utility/type_traits.hpp b/include/boost/crypt/utility/type_traits.hpp index 61033a2..7d68982 100644 --- a/include/boost/crypt/utility/type_traits.hpp +++ b/include/boost/crypt/utility/type_traits.hpp @@ -161,7 +161,9 @@ using cuda::std::underlying_type_t; #else // STD versions +#ifndef BOOST_CRYPT_BUILD_MODULE #include +#endif namespace boost { namespace crypt { From adb3bcd1adf02af0fda91b5e3b735fcf3fb7b728 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 15 Oct 2024 15:48:37 -0400 Subject: [PATCH 079/107] Add RFC link --- include/boost/crypt/hash/md5.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/boost/crypt/hash/md5.hpp b/include/boost/crypt/hash/md5.hpp index d74061d..0769fd1 100644 --- a/include/boost/crypt/hash/md5.hpp +++ b/include/boost/crypt/hash/md5.hpp @@ -1,6 +1,8 @@ // Copyright 2024 Matt Borland // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt +// +// See: https://www.ietf.org/rfc/rfc1321.txt #ifndef BOOST_CRYPT_HASH_MD5_HPP #define BOOST_CRYPT_HASH_MD5_HPP From cdac8d40d8f0ab579b9830809faaaec3ab38842f Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 15 Oct 2024 15:48:57 -0400 Subject: [PATCH 080/107] Add additional interfaces for wider character types --- include/boost/crypt/hash/md5.hpp | 152 ++++++++++++++++++++++++++++++- 1 file changed, 148 insertions(+), 4 deletions(-) diff --git a/include/boost/crypt/hash/md5.hpp b/include/boost/crypt/hash/md5.hpp index 0769fd1..92cf6ee 100644 --- a/include/boost/crypt/hash/md5.hpp +++ b/include/boost/crypt/hash/md5.hpp @@ -15,8 +15,10 @@ #include #include #include +#include #ifndef BOOST_CRYPT_BUILD_MODULE +#include #include #include #include @@ -56,7 +58,13 @@ class md5_hasher BOOST_CRYPT_GPU_ENABLED constexpr auto process_byte(ByteType byte) noexcept BOOST_CRYPT_REQUIRES_CONVERSION(ByteType, boost::crypt::uint8_t); - template + template ::value_type) == 1, bool> = true> + BOOST_CRYPT_GPU_ENABLED constexpr auto process_bytes(ForwardIter buffer, boost::crypt::size_t byte_count) noexcept; + + template ::value_type) == 2, bool> = true> + BOOST_CRYPT_GPU_ENABLED constexpr auto process_bytes(ForwardIter buffer, boost::crypt::size_t byte_count) noexcept; + + template ::value_type) == 4, bool> = true> BOOST_CRYPT_GPU_ENABLED constexpr auto process_bytes(ForwardIter buffer, boost::crypt::size_t byte_count) noexcept; BOOST_CRYPT_GPU_ENABLED constexpr auto get_digest() noexcept -> boost::crypt::array; @@ -198,15 +206,50 @@ template BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::process_byte(ByteType byte) noexcept BOOST_CRYPT_REQUIRES_CONVERSION(ByteType, boost::crypt::uint8_t) { - md5_update(&byte, 1UL); + const auto value {static_cast(byte)}; + md5_update(&value, 1UL); } -template +template ::value_type) == 1, bool>> BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::process_bytes(ForwardIter buffer, boost::crypt::size_t byte_count) noexcept { md5_update(buffer, byte_count); } +template ::value_type) == 2, bool>> +BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::process_bytes(ForwardIter buffer, boost::crypt::size_t byte_count) noexcept +{ + #ifndef BOOST_CRYPT_HAS_CUDA + + const auto* char_ptr {reinterpret_cast(std::addressof(*buffer))}; + const auto* data {reinterpret_cast(char_ptr)}; + md5_update(data, byte_count * 2U); + + #else + + const auto* data {reinterpret_cast(buffer)}; + md5_update(data, byte_count * 2U); + + #endif +} + +template ::value_type) == 4, bool>> +BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::process_bytes(ForwardIter buffer, boost::crypt::size_t byte_count) noexcept +{ + #ifndef BOOST_CRYPT_HAS_CUDA + + const auto* char_ptr {reinterpret_cast(std::addressof(*buffer))}; + const auto* data {reinterpret_cast(char_ptr)}; + md5_update(data, byte_count * 4U); + + #else + + const auto* data {reinterpret_cast(buffer)}; + md5_update(data, byte_count * 4U); + + #endif +} + // See: Applied Cryptography - Bruce Schneier // Section 18.5 namespace md5_body_detail { @@ -415,19 +458,120 @@ BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const boost::crypt::uint8_t* str, boo return detail::md5(str, str + len); } +BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const char16_t* str) noexcept -> boost::crypt::array +{ + if (str == nullptr) + { + return boost::crypt::array{}; // LCOV_EXCL_LINE + } + + const auto message_len {utility::strlen(str)}; + return detail::md5(str, str + message_len); +} + +BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const char16_t* str, boost::crypt::size_t len) noexcept -> boost::crypt::array +{ + if (str == nullptr) + { + return boost::crypt::array{}; // LCOV_EXCL_LINE + } + + return detail::md5(str, str + len); +} + +BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const char32_t* str) noexcept -> boost::crypt::array +{ + if (str == nullptr) + { + return boost::crypt::array{}; // LCOV_EXCL_LINE + } + + const auto message_len {utility::strlen(str)}; + return detail::md5(str, str + message_len); +} + +BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const char32_t* str, boost::crypt::size_t len) noexcept -> boost::crypt::array +{ + if (str == nullptr) + { + return boost::crypt::array{}; // LCOV_EXCL_LINE + } + + return detail::md5(str, str + len); +} + +// On some platforms wchar_t is 16 bits and others it's 32 +// Since we check sizeof() the underlying with SFINAE in the actual implementation this is handled transparently +BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const wchar_t* str) noexcept -> boost::crypt::array +{ + if (str == nullptr) + { + return boost::crypt::array{}; // LCOV_EXCL_LINE + } + + const auto message_len {utility::strlen(str)}; + return detail::md5(str, str + message_len); +} + +BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const wchar_t* str, boost::crypt::size_t len) noexcept -> boost::crypt::array +{ + if (str == nullptr) + { + return boost::crypt::array{}; // LCOV_EXCL_LINE + } + + return detail::md5(str, str + len); +} + // ----- String and String view aren't in the libcu++ STL so they so not have device markers ----- +#ifndef BOOST_CRYPT_HAS_CUDA + inline auto md5(const std::string& str) noexcept -> boost::crypt::array { return detail::md5(str.begin(), str.end()); } +inline auto md5(const std::u16string& str) noexcept -> boost::crypt::array +{ + return detail::md5(str.begin(), str.end()); +} + +inline auto md5(const std::u32string& str) noexcept -> boost::crypt::array +{ + return detail::md5(str.begin(), str.end()); +} + +inline auto md5(const std::wstring& str) noexcept -> boost::crypt::array +{ + return detail::md5(str.begin(), str.end()); +} + #ifdef BOOST_CRYPT_HAS_STRING_VIEW + inline auto md5(const std::string_view& str) -> boost::crypt::array { return detail::md5(str.begin(), str.end()); } -#endif + +inline auto md5(const std::u16string_view& str) -> boost::crypt::array +{ + return detail::md5(str.begin(), str.end()); +} + +inline auto md5(const std::u32string_view& str) -> boost::crypt::array +{ + return detail::md5(str.begin(), str.end()); +} + +inline auto md5(const std::wstring_view& str) -> boost::crypt::array +{ + return detail::md5(str.begin(), str.end()); +} + +#endif // BOOST_CRYPT_HAS_STRING_VIEW + +#endif // BOOST_CRYPT_HAS_CUDA } // namespace crypt } // namespace boost From b6eb2c731bcf2c7e7eb9a99c7ae355b6e25511db Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 15 Oct 2024 15:51:36 -0400 Subject: [PATCH 081/107] Refactor location for random string generation --- test/generate_random_strings.hpp | 40 ++++++++++++++++++++++++++++++++ test/test_md5.cpp | 29 ++++------------------- 2 files changed, 44 insertions(+), 25 deletions(-) create mode 100644 test/generate_random_strings.hpp diff --git a/test/generate_random_strings.hpp b/test/generate_random_strings.hpp new file mode 100644 index 0000000..b13c131 --- /dev/null +++ b/test/generate_random_strings.hpp @@ -0,0 +1,40 @@ +// Copyright 2024 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CRYPT_TEST_GENERATE_RANDOM_STRINGS +#define BOOST_CRYPT_TEST_GENERATE_RANDOM_STRINGS + +#include +#include +#include +#include + +namespace boost { +namespace crypt { + +inline void generate_random_cstring(char* str, std::size_t length) +{ + + const char charset[] = "0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz"; + + const std::size_t charset_size = sizeof(charset) - 1; + + std::mt19937_64 rng(42); + std::uniform_int_distribution dist(0, charset_size); + + for (std::size_t i = 0; i < length - 1; ++i) + { + int index = dist(rng); + str[i] = charset[index]; + } + + str[length - 1] = '\0'; +} + +} // Namespace crypt +} // namespace boost + +#endif // BOOST_CRYPT_TEST_GENERATE_RANDOM_STRINGS diff --git a/test/test_md5.cpp b/test/test_md5.cpp index 67c1e3a..7419ad9 100644 --- a/test/test_md5.cpp +++ b/test/test_md5.cpp @@ -6,6 +6,7 @@ #include #include +#include "generate_random_strings.hpp" #ifdef __clang__ # pragma clang diagnostic push @@ -25,7 +26,6 @@ # pragma GCC diagnostic pop #endif - #include #include #include @@ -35,27 +35,6 @@ #include #include -void generate_random_cstring(char* str, std::size_t length) -{ - - const char charset[] = "0123456789" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz"; - - const std::size_t charset_size = sizeof(charset) - 1; - - std::mt19937_64 rng(42); - std::uniform_int_distribution dist(0, charset_size); - - for (std::size_t i = 0; i < length - 1; ++i) - { - int index = dist(rng); - str[i] = charset[index]; - } - - str[length - 1] = '\0'; -} - auto get_boost_uuid_result(const char* str, size_t length) { unsigned char digest[16]; @@ -228,7 +207,7 @@ void test_random_values() { std::memset(str, '\0', max_str_len); const std::size_t current_str_len {str_len(rng)}; - generate_random_cstring(str, current_str_len); + boost::crypt::generate_random_cstring(str, current_str_len); const auto uuid_res {get_boost_uuid_result(str, current_str_len)}; const auto crypt_res {boost::crypt::md5(str, current_str_len)}; @@ -265,8 +244,8 @@ void test_random_piecewise_values() std::memset(str_2, '\0', max_str_len); const std::size_t current_str_len {str_len(rng)}; - generate_random_cstring(str, current_str_len); - generate_random_cstring(str_2, current_str_len); + boost::crypt::generate_random_cstring(str, current_str_len); + boost::crypt::generate_random_cstring(str_2, current_str_len); boost_hasher.process_bytes(str, current_str_len); boost_hasher.process_bytes(str_2, current_str_len); From 3f31c7e8ff8277a2064216687b20aff08a80b816 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 15 Oct 2024 15:55:28 -0400 Subject: [PATCH 082/107] Add functions for generating wider cstrings --- test/generate_random_strings.hpp | 64 +++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/test/generate_random_strings.hpp b/test/generate_random_strings.hpp index b13c131..25ac5dd 100644 --- a/test/generate_random_strings.hpp +++ b/test/generate_random_strings.hpp @@ -23,17 +23,77 @@ inline void generate_random_cstring(char* str, std::size_t length) const std::size_t charset_size = sizeof(charset) - 1; std::mt19937_64 rng(42); - std::uniform_int_distribution dist(0, charset_size); + std::uniform_int_distribution dist(0, charset_size); for (std::size_t i = 0; i < length - 1; ++i) { - int index = dist(rng); + const auto index = dist(rng); str[i] = charset[index]; } str[length - 1] = '\0'; } +inline void generate_random_u16string(char16_t* str, std::size_t length) +{ + const char16_t charset[] = u"0123456789" + u"ABCDEFGHIJKLMNOPQRSTUVWXYZ" + u"abcdefghijklmnopqrstuvwxyz"; + + const std::size_t charset_size = std::char_traits::length(charset); + + std::mt19937_64 rng(42); + std::uniform_int_distribution dist(0, charset_size - 1); + + for (std::size_t i = 0; i < length - 1; ++i) + { + const auto index = dist(rng); + str[i] = charset[index]; + } + + str[length - 1] = u'\0'; +} + +inline void generate_random_u32string(char16_t* str, std::size_t length) +{ + const char32_t charset[] = U"0123456789" + U"ABCDEFGHIJKLMNOPQRSTUVWXYZ" + U"abcdefghijklmnopqrstuvwxyz"; + + const std::size_t charset_size = std::char_traits::length(charset); + + std::mt19937_64 rng(42); + std::uniform_int_distribution dist(0, charset_size - 1); + + for (std::size_t i = 0; i < length - 1; ++i) + { + const auto index = dist(rng); + str[i] = charset[index]; + } + + str[length - 1] = u'\0'; +} + +inline void generate_random_wstring(wchar_t* str, std::size_t length) +{ + const wchar_t charset[] = L"0123456789" + L"ABCDEFGHIJKLMNOPQRSTUVWXYZ" + L"abcdefghijklmnopqrstuvwxyz"; + + const std::size_t charset_size = std::char_traits::length(charset); + + std::mt19937_64 rng(42); + std::uniform_int_distribution dist(0, charset_size - 1); + + for (std::size_t i = 0; i < length - 1; ++i) + { + const auto index = dist(rng); + str[i] = charset[index]; + } + + str[length - 1] = u'\0'; +} + } // Namespace crypt } // namespace boost From 2613f0a61f0584f2f7c7c63f281e10f02697e300 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 15 Oct 2024 16:01:34 -0400 Subject: [PATCH 083/107] Add testing of wider character types --- test/generate_random_strings.hpp | 8 ++++---- test/test_md5.cpp | 21 ++++++++++++++++----- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/test/generate_random_strings.hpp b/test/generate_random_strings.hpp index 25ac5dd..c85f0ff 100644 --- a/test/generate_random_strings.hpp +++ b/test/generate_random_strings.hpp @@ -13,7 +13,7 @@ namespace boost { namespace crypt { -inline void generate_random_cstring(char* str, std::size_t length) +inline void generate_random_string(char* str, std::size_t length) { const char charset[] = "0123456789" @@ -34,7 +34,7 @@ inline void generate_random_cstring(char* str, std::size_t length) str[length - 1] = '\0'; } -inline void generate_random_u16string(char16_t* str, std::size_t length) +inline void generate_random_string(char16_t* str, std::size_t length) { const char16_t charset[] = u"0123456789" u"ABCDEFGHIJKLMNOPQRSTUVWXYZ" @@ -54,7 +54,7 @@ inline void generate_random_u16string(char16_t* str, std::size_t length) str[length - 1] = u'\0'; } -inline void generate_random_u32string(char16_t* str, std::size_t length) +inline void generate_random_string(char32_t* str, std::size_t length) { const char32_t charset[] = U"0123456789" U"ABCDEFGHIJKLMNOPQRSTUVWXYZ" @@ -74,7 +74,7 @@ inline void generate_random_u32string(char16_t* str, std::size_t length) str[length - 1] = u'\0'; } -inline void generate_random_wstring(wchar_t* str, std::size_t length) +inline void generate_random_string(wchar_t* str, std::size_t length) { const wchar_t charset[] = L"0123456789" L"ABCDEFGHIJKLMNOPQRSTUVWXYZ" diff --git a/test/test_md5.cpp b/test/test_md5.cpp index 7419ad9..4d0e689 100644 --- a/test/test_md5.cpp +++ b/test/test_md5.cpp @@ -195,6 +195,7 @@ void test_class() } } +template void test_random_values() { constexpr std::size_t max_str_len {65535U}; @@ -207,7 +208,7 @@ void test_random_values() { std::memset(str, '\0', max_str_len); const std::size_t current_str_len {str_len(rng)}; - boost::crypt::generate_random_cstring(str, current_str_len); + boost::crypt::generate_random_string(str, current_str_len); const auto uuid_res {get_boost_uuid_result(str, current_str_len)}; const auto crypt_res {boost::crypt::md5(str, current_str_len)}; @@ -226,6 +227,7 @@ void test_random_values() delete[] str; } +template void test_random_piecewise_values() { constexpr std::size_t max_str_len {65535U}; @@ -244,8 +246,8 @@ void test_random_piecewise_values() std::memset(str_2, '\0', max_str_len); const std::size_t current_str_len {str_len(rng)}; - boost::crypt::generate_random_cstring(str, current_str_len); - boost::crypt::generate_random_cstring(str_2, current_str_len); + boost::crypt::generate_random_string(str, current_str_len); + boost::crypt::generate_random_string(str_2, current_str_len); boost_hasher.process_bytes(str, current_str_len); boost_hasher.process_bytes(str_2, current_str_len); @@ -291,8 +293,17 @@ int main() test_class(); - test_random_values(); - test_random_piecewise_values(); + test_random_values(); + test_random_piecewise_values(); + + test_random_values(); + test_random_piecewise_values(); + + test_random_values(); + test_random_piecewise_values(); + + test_random_values(); + test_random_piecewise_values(); return boost::report_errors(); } From 3cf7954bb3e93ef358a79d8dbf81dd1a388260ac Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 15 Oct 2024 16:13:20 -0400 Subject: [PATCH 084/107] Add in tests from original RFC --- test/test_md5.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/test/test_md5.cpp b/test/test_md5.cpp index 4d0e689..20091ab 100644 --- a/test/test_md5.cpp +++ b/test/test_md5.cpp @@ -1,8 +1,6 @@ // Copyright 2024 Matt Borland // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt -// -// Start with the sample hashes from wiki #include #include @@ -51,8 +49,9 @@ auto get_boost_uuid_result(const char* str, size_t length) return return_array; } -constexpr std::array>, 9> test_values = +constexpr std::array>, 15> test_values = { + // // Start with the sample hashes from wiki std::make_tuple("The quick brown fox jumps over the lazy dog", std::array{0x9e, 0x10, 0x7d, 0x9d, 0x37, 0x2b, 0xb6, 0x82, 0x6b, 0xd8, 0x1d, 0x35, 0x42, 0xa4, 0x19, 0xd6}), std::make_tuple("The quick brown fox jumps over the lazy dog.", @@ -71,6 +70,20 @@ constexpr std::array>, 9> test_ std::array{0xd3, 0x7e, 0x43, 0x17, 0x49, 0x05, 0xde, 0x70, 0xfb, 0xb5, 0xb0, 0x38, 0xd7, 0x24, 0x7f, 0x57}), std::make_tuple("The Whirlpool Galaxy is about 88% the size of the Milky Way, with a diameter of 76,900 light-years", std::array{0xd5, 0xdf, 0xd7, 0xb4, 0x12, 0x35, 0xab, 0xc7, 0xa9, 0xa3, 0x20, 0x5b, 0x68, 0x96, 0xf3, 0x4d}), + + // From the RFC + std::make_tuple("a", + std::array{0x0c, 0xc1, 0x75, 0xb9, 0xc0, 0xf1, 0xb6, 0xa8, 0x31, 0xc3, 0x99, 0xe2, 0x69, 0x77, 0x26, 0x61}), + std::make_tuple("abc", + std::array{0x90, 0x01, 0x50, 0x98, 0x3c, 0xd2, 0x4f, 0xb0, 0xd6, 0x96, 0x3f, 0x7d, 0x28, 0xe1, 0x7f, 0x72}), + std::make_tuple("message digest", + std::array{0xf9, 0x6b, 0x69, 0x7d, 0x7c, 0xb7, 0x93, 0x8d, 0x52, 0x5a, 0x2f, 0x31, 0xaa, 0xf1, 0x61, 0xd0}), + std::make_tuple("abcdefghijklmnopqrstuvwxyz", + std::array{0xc3, 0xfc, 0xd3, 0xd7, 0x61, 0x92, 0xe4, 0x00, 0x7d, 0xfb, 0x49, 0x6c, 0xca, 0x67, 0xe1, 0x3b}), + std::make_tuple("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + std::array{0xd1, 0x74, 0xab, 0x98, 0xd2, 0x77, 0xd9, 0xf5, 0xa5, 0x61, 0x1c, 0x2c, 0x9f, 0x41, 0x9d, 0x9f}), + std::make_tuple("12345678901234567890123456789012345678901234567890123456789012345678901234567890", + std::array{0x57, 0xed, 0xf4, 0xa2, 0x2b, 0xe3, 0xc9, 0x55, 0xac, 0x49, 0xda, 0x2e, 0x21, 0x07, 0xb6, 0x7a}), }; void basic_tests() From c02afaa5d02af316a550b124539c1eb4ca283c1b Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 15 Oct 2024 16:14:34 -0400 Subject: [PATCH 085/107] Exclude size_t rollover line --- include/boost/crypt/hash/md5.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/boost/crypt/hash/md5.hpp b/include/boost/crypt/hash/md5.hpp index 92cf6ee..cad1710 100644 --- a/include/boost/crypt/hash/md5.hpp +++ b/include/boost/crypt/hash/md5.hpp @@ -118,7 +118,8 @@ BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::md5_update(ForwardIter data, low_ += input_bits; if (low_ < old_low) { - ++high_; + // This should never happen as it indicates size_t roll over + ++high_; // LCOV_EXCL_LINE } high_ += size >> 29U; From afd76adf16127c5bb626abd98accc8ba159b65a7 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 16 Oct 2024 09:26:17 -0400 Subject: [PATCH 086/107] Pass string views by value not reference --- include/boost/crypt/hash/md5.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/boost/crypt/hash/md5.hpp b/include/boost/crypt/hash/md5.hpp index cad1710..f6f02d6 100644 --- a/include/boost/crypt/hash/md5.hpp +++ b/include/boost/crypt/hash/md5.hpp @@ -550,22 +550,22 @@ inline auto md5(const std::wstring& str) noexcept -> boost::crypt::array boost::crypt::array +inline auto md5(std::string_view str) -> boost::crypt::array { return detail::md5(str.begin(), str.end()); } -inline auto md5(const std::u16string_view& str) -> boost::crypt::array +inline auto md5(std::u16string_view str) -> boost::crypt::array { return detail::md5(str.begin(), str.end()); } -inline auto md5(const std::u32string_view& str) -> boost::crypt::array +inline auto md5(std::u32string_view str) -> boost::crypt::array { return detail::md5(str.begin(), str.end()); } -inline auto md5(const std::wstring_view& str) -> boost::crypt::array +inline auto md5(std::wstring_view str) -> boost::crypt::array { return detail::md5(str.begin(), str.end()); } From 8a7f230a28ba2fcbcbe052aad1b815a1f90031ec Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 16 Oct 2024 09:42:34 -0400 Subject: [PATCH 087/107] Add basic file reader class --- include/boost/crypt/utility/file.hpp | 86 ++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 include/boost/crypt/utility/file.hpp diff --git a/include/boost/crypt/utility/file.hpp b/include/boost/crypt/utility/file.hpp new file mode 100644 index 0000000..c6b5947 --- /dev/null +++ b/include/boost/crypt/utility/file.hpp @@ -0,0 +1,86 @@ +// Copyright 2024 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CRYPT_UTILITY_FILE_HPP +#define BOOST_CRYPT_UTILITY_FILE_HPP + +#include +#include +#include + +#ifndef BOOST_CRYPT_BUILD_MODULE +#include +#include +#include +#include +#endif + +namespace boost { +namespace crypt { +namespace utility { + +template +class file_reader +{ +private: + std::ifstream fd; + std::array buffer_ {}; + +public: + explicit file_reader(const std::string& filename) : fd(filename, std::ios::binary | std::ios::in) + { + if (!fd.is_open()) + { + throw std::runtime_error("Error opening file: " + filename); + } + } + + explicit file_reader(const char* filename) : fd(filename, std::ios::binary | std::ios::in) + { + if (!fd.is_open()) + { + throw std::runtime_error("Error opening file"); + } + } + + #ifdef BOOST_CRYPT_HAS_STRING_VIEW + explicit file_reader(std::string_view filename) : fd(filename.data(), std::ios::binary | std::ios::in) + { + if (!fd.is_open()) + { + throw std::runtime_error("Error opening file"); + } + } + #endif + + auto read_next_block() -> std::array& + { + fd.read(reinterpret_cast(buffer_.data()), block_size); + return buffer_; + } + + auto get_bytes_read() const -> std::size_t + { + return fd.gcount(); + } + + auto eof() const -> bool + { + return fd.eof(); + } + + ~file_reader() + { + if (fd.is_open()) + { + fd.close(); + } + } +}; + +} // namespace utility +} // namespace crypt +} // namespace boost + +#endif //BOOST_CRYPT_UTILITY_FILE_HPP From 3fdd3a347f4eb4da8ee960ea666f7e303656bf91 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 16 Oct 2024 11:19:37 -0400 Subject: [PATCH 088/107] Add interfaces for files --- include/boost/crypt/hash/md5.hpp | 64 ++++++++++++++++++++++++++++ include/boost/crypt/utility/file.hpp | 4 +- 2 files changed, 66 insertions(+), 2 deletions(-) diff --git a/include/boost/crypt/hash/md5.hpp b/include/boost/crypt/hash/md5.hpp index f6f02d6..3458e12 100644 --- a/include/boost/crypt/hash/md5.hpp +++ b/include/boost/crypt/hash/md5.hpp @@ -16,6 +16,7 @@ #include #include #include +#include #ifndef BOOST_CRYPT_BUILD_MODULE #include @@ -572,6 +573,69 @@ inline auto md5(std::wstring_view str) -> boost::crypt::array +auto md5_file_impl(utility::file_reader& reader) noexcept -> boost::crypt::array +{ + md5_hasher hasher; + while (!reader.eof()) + { + const auto buffer_iter {reader.read_next_block()}; + const auto len {reader.get_bytes_read()}; + hasher.process_bytes(buffer_iter, len); + } + + return hasher.get_digest(); +} + +} // namespace detail + +inline auto md5_file(const std::string& filepath) noexcept -> boost::crypt::array +{ + try + { + utility::file_reader<64U> reader(filepath); + return detail::md5_file_impl(reader); + } + catch (const std::runtime_error&) + { + return boost::crypt::array{}; + } +} + +inline auto md5_file(const char* filepath) noexcept -> boost::crypt::array +{ + try + { + utility::file_reader<64U> reader(filepath); + return detail::md5_file_impl(reader); + } + catch (const std::runtime_error&) + { + return boost::crypt::array{}; + } +} + +#ifdef BOOST_CRYPT_HAS_STRING_VIEW + +inline auto md5_file(std::string_view filepath) noexcept -> boost::crypt::array +{ + try + { + utility::file_reader<64U> reader(filepath); + return detail::md5_file_impl(reader); + } + catch (const std::runtime_error&) + { + return boost::crypt::array{}; + } +} + +#endif // BOOST_CRYPT_HAS_STRING_VIEW + #endif // BOOST_CRYPT_HAS_CUDA } // namespace crypt diff --git a/include/boost/crypt/utility/file.hpp b/include/boost/crypt/utility/file.hpp index c6b5947..6f90038 100644 --- a/include/boost/crypt/utility/file.hpp +++ b/include/boost/crypt/utility/file.hpp @@ -54,10 +54,10 @@ class file_reader } #endif - auto read_next_block() -> std::array& + auto read_next_block() { fd.read(reinterpret_cast(buffer_.data()), block_size); - return buffer_; + return buffer_.begin(); } auto get_bytes_read() const -> std::size_t From e1b26fac399e2eeffc50ac92c11e75b9aacba5f5 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 16 Oct 2024 11:40:19 -0400 Subject: [PATCH 089/107] Fix conversion error --- include/boost/crypt/utility/file.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/crypt/utility/file.hpp b/include/boost/crypt/utility/file.hpp index 6f90038..91f4332 100644 --- a/include/boost/crypt/utility/file.hpp +++ b/include/boost/crypt/utility/file.hpp @@ -62,7 +62,7 @@ class file_reader auto get_bytes_read() const -> std::size_t { - return fd.gcount(); + return static_cast(fd.gcount()); } auto eof() const -> bool From 2f4f5d885a5dadc98e65692e3daf11825803879b Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 16 Oct 2024 11:41:14 -0400 Subject: [PATCH 090/107] Add testing of file interfaces --- test/test_file_1.txt | 1 + test/test_file_2.txt | 9 ++++++ test/test_md5.cpp | 77 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+) create mode 100644 test/test_file_1.txt create mode 100644 test/test_file_2.txt diff --git a/test/test_file_1.txt b/test/test_file_1.txt new file mode 100644 index 0000000..2fe6575 --- /dev/null +++ b/test/test_file_1.txt @@ -0,0 +1 @@ +The quick brown fox jumps over the lazy dog. diff --git a/test/test_file_2.txt b/test/test_file_2.txt new file mode 100644 index 0000000..45bb78d --- /dev/null +++ b/test/test_file_2.txt @@ -0,0 +1,9 @@ +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras leo purus, faucibus id risus pulvinar, condimentum molestie justo. Nulla sit amet pulvinar magna. In at quam id leo scelerisque posuere. Nullam porttitor auctor vestibulum. Nullam ac velit orci. Quisque semper hendrerit tortor, eu vulputate mauris vestibulum eget. Quisque nunc neque, posuere ut tortor a, suscipit tristique diam. Maecenas nec elit turpis. Nullam sapien enim, rhoncus et aliquet id, accumsan ac justo. Maecenas eu diam eget lorem vehicula lacinia eget sit amet orci. Ut lobortis magna arcu, pharetra lacinia est lobortis ut. Nam sagittis ex et magna maximus volutpat. Praesent lacinia felis neque. Vestibulum velit nisl, ullamcorper eu hendrerit eget, aliquet vitae ante. Mauris scelerisque blandit felis sed pharetra. + +Etiam a sapien at arcu cursus malesuada. Mauris ut quam velit. Praesent rutrum, neque ut vehicula hendrerit, lorem libero malesuada neque, sed sodales turpis lorem fermentum erat. Vestibulum in eleifend erat, nec blandit libero. Etiam aliquam lacus sit amet nisl cursus, ut consequat orci dignissim. Proin varius lectus augue, a euismod quam euismod at. Nullam augue sapien, finibus viverra ante ac, ultricies eleifend ipsum. Mauris ullamcorper eros nulla, sed porta nulla imperdiet sed. Sed ac massa dui. Pellentesque tellus ligula, posuere quis enim hendrerit, suscipit eleifend felis. Vivamus consectetur feugiat orci a faucibus. Morbi tristique, ex sit amet mollis laoreet, ligula ligula tempor lorem, sed posuere nisl sem at nunc. Morbi a sodales justo. Sed efficitur nibh vitae turpis aliquam semper nec in urna. + +In neque nisl, malesuada eu tristique non, euismod a diam. Sed mattis scelerisque consectetur. Sed in molestie libero, quis porta felis. Curabitur vel augue mauris. Aliquam dignissim facilisis bibendum. Vestibulum ut dignissim metus, ut fermentum elit. Etiam eu arcu id massa tristique semper. Ut lobortis neque eget hendrerit pretium. Nulla congue justo nec nibh cursus mattis. Morbi libero urna, sagittis ac risus vel, rutrum finibus purus. + +Nam mattis fringilla justo eget pretium. Vivamus quis facilisis tortor. Aenean blandit elit eu mollis lacinia. Cras orci odio, aliquet eget lacus ac, feugiat lacinia magna. Pellentesque vel urna congue metus faucibus accumsan. Donec ac tortor feugiat nibh maximus imperdiet non id lectus. Duis commodo, purus eu suscipit porttitor, lorem purus faucibus enim, ac ultricies nulla massa vitae magna. Vestibulum maximus enim ante, quis lacinia magna molestie nec. Donec eleifend sapien at risus iaculis rhoncus. Phasellus sit amet urna pulvinar, commodo mi ut, feugiat sapien. Nullam id felis nec turpis commodo laoreet. + +Vivamus quis felis pretium, bibendum turpis vitae, maximus nulla. Phasellus a elit id erat lacinia lacinia. Nunc in feugiat libero. Morbi sodales quam eget sem egestas varius ut quis orci. In hac habitasse platea dictumst. Sed sollicitudin vestibulum faucibus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Etiam rhoncus nulla elit, id egestas arcu posuere vulputate. Nullam sit amet leo iaculis, viverra nisi nec, efficitur nisi. Fusce nec dui ultricies, ultricies est ac, pretium est. diff --git a/test/test_md5.cpp b/test/test_md5.cpp index 20091ab..e54c8ee 100644 --- a/test/test_md5.cpp +++ b/test/test_md5.cpp @@ -295,6 +295,81 @@ void test_random_piecewise_values() delete[] str_2; } +template +void test_file(T filename, const std::array& res) +{ + const auto crypt_res {boost::crypt::md5_file(filename)}; + + 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 std::array res{}; + + const auto crypt_res {boost::crypt::md5_file(filename)}; + + 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 + } + } +} + +void files_test() +{ + // On macOS 15 + // md5 test_file_1.txt + // MD5 (test_file_1.txt) = 0d7006cd055e94cf614587e1d2ae0c8e + constexpr std::array res{0x0d, 0x70, 0x06, 0xcd, 0x05, 0x5e, 0x94, 0xcf, + 0x61, 0x45, 0x87, 0xe1, 0xd2, 0xae, 0x0c, 0x8e}; + + const auto filename = "test_file_1.txt"; + 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); + + const std::string str_invalid_filename {invalid_filename}; + test_invalid_file(str_invalid_filename); + + #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 + + // On macOS 15 + // md5 test_file_2.txt + // MD5 (test_file_2.txt) = 530e67fa4b01e3ccaee8eca9916a814c + constexpr std::array res_2{0x53, 0x0e, 0x67, 0xfa, 0x4b, 0x01, 0xe3, 0xcc, + 0xae, 0xe8, 0xec, 0xa9, 0x91, 0x6a, 0x81, 0x4c}; + + test_file("test_file_2.txt", res_2); +} + int main() { basic_tests(); @@ -318,5 +393,7 @@ int main() test_random_values(); test_random_piecewise_values(); + files_test(); + return boost::report_errors(); } From 47bec5f57537f1ac526e99a4ad3e04dbb905bfae Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 16 Oct 2024 11:55:05 -0400 Subject: [PATCH 091/107] Fix missing header --- include/boost/crypt/utility/file.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/crypt/utility/file.hpp b/include/boost/crypt/utility/file.hpp index 91f4332..fdf7f27 100644 --- a/include/boost/crypt/utility/file.hpp +++ b/include/boost/crypt/utility/file.hpp @@ -7,13 +7,13 @@ #include #include -#include #ifndef BOOST_CRYPT_BUILD_MODULE #include #include #include #include +#include #endif namespace boost { From 08b30bad5adecd7bb80873e49a0ee26e1e43ed01 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 16 Oct 2024 12:18:39 -0400 Subject: [PATCH 092/107] Fix handling of multiple different test directories --- test/test_md5.cpp | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/test/test_md5.cpp b/test/test_md5.cpp index e54c8ee..8096625 100644 --- a/test/test_md5.cpp +++ b/test/test_md5.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -333,13 +334,41 @@ void test_invalid_file(T filename) void files_test() { + // Based off where we are testing from (test vs boost_root) we need to adjust our filepath + const char* filename; + const char* filename_2; + + std::ifstream fd("libs/crypt/test/test_file_1.txt", std::ios::binary | std::ios::in); + filename = "libs/crypt/test/test_file_1.txt"; + filename_2 = "libs/crypt/test/test_file_2.txt"; + + if (!fd.is_open()) + { + std::ifstream fd2("test_file_1.txt", std::ios::binary | std::ios::in); + filename = "test_file_1.txt"; + filename_2 = "test_file_2.txt"; + + if (!fd2.is_open()) + { + std::cerr << "Test not run due to file system issues" << std::endl; + return; + } + else + { + fd2.close(); + } + } + else + { + fd.close(); + } + // On macOS 15 // md5 test_file_1.txt // MD5 (test_file_1.txt) = 0d7006cd055e94cf614587e1d2ae0c8e constexpr std::array res{0x0d, 0x70, 0x06, 0xcd, 0x05, 0x5e, 0x94, 0xcf, 0x61, 0x45, 0x87, 0xe1, 0xd2, 0xae, 0x0c, 0x8e}; - const auto filename = "test_file_1.txt"; test_file(filename, res); const std::string str_filename {filename}; @@ -367,7 +396,7 @@ void files_test() constexpr std::array res_2{0x53, 0x0e, 0x67, 0xfa, 0x4b, 0x01, 0xe3, 0xcc, 0xae, 0xe8, 0xec, 0xa9, 0x91, 0x6a, 0x81, 0x4c}; - test_file("test_file_2.txt", res_2); + test_file(filename_2, res_2); } int main() From cb16e211eecaa40d4bccf9dfd2cfd95fcf257bda Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 16 Oct 2024 12:26:00 -0400 Subject: [PATCH 093/107] Fix coverage file system issues --- test/test_md5.cpp | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/test/test_md5.cpp b/test/test_md5.cpp index 8096625..19f0121 100644 --- a/test/test_md5.cpp +++ b/test/test_md5.cpp @@ -338,25 +338,39 @@ void files_test() const char* filename; const char* filename_2; + // Boost-root std::ifstream fd("libs/crypt/test/test_file_1.txt", std::ios::binary | std::ios::in); filename = "libs/crypt/test/test_file_1.txt"; filename_2 = "libs/crypt/test/test_file_2.txt"; if (!fd.is_open()) { - std::ifstream fd2("test_file_1.txt", std::ios::binary | std::ios::in); - filename = "test_file_1.txt"; - filename_2 = "test_file_2.txt"; + // Local test directory or IDE + std::ifstream fd2("test_file_1.txt", std::ios::binary | std::ios::in); + filename = "test_file_1.txt"; + filename_2 = "test_file_2.txt"; - if (!fd2.is_open()) + if (!fd2.is_open()) + { + // test/cover + std::ifstream fd3("../test_file_1.txt", std::ios::binary | std::ios::in); + filename = "../test_file_1.txt"; + filename_2 = "../test_file_2.txt"; + + if (!fd3.is_open()) { std::cerr << "Test not run due to file system issues" << std::endl; return; } else { - fd2.close(); + fd3.close(); } + } + else + { + fd2.close(); + } } else { From b88129b3550ecfe8fdbe1abf626fdba33d0d9df5 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 16 Oct 2024 12:28:58 -0400 Subject: [PATCH 094/107] Ignore coverage of path finding correct file name --- test/test_md5.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/test_md5.cpp b/test/test_md5.cpp index 19f0121..c3b5ff7 100644 --- a/test/test_md5.cpp +++ b/test/test_md5.cpp @@ -343,6 +343,7 @@ void files_test() filename = "libs/crypt/test/test_file_1.txt"; filename_2 = "libs/crypt/test/test_file_2.txt"; + // LCOV_EXCL_START if (!fd.is_open()) { // Local test directory or IDE @@ -376,6 +377,7 @@ void files_test() { fd.close(); } + // LCOV_EXCL_STOP // On macOS 15 // md5 test_file_1.txt From 6b8d082e5df3eeb660ba3e316f76c924828b75bb Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 16 Oct 2024 13:38:26 -0400 Subject: [PATCH 095/107] Disable files tests on windows platform --- test/test_md5.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/test_md5.cpp b/test/test_md5.cpp index c3b5ff7..ab4429e 100644 --- a/test/test_md5.cpp +++ b/test/test_md5.cpp @@ -438,7 +438,10 @@ int main() test_random_values(); test_random_piecewise_values(); + // The Windows file system returns a different result than on UNIX platforms + #if defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)) files_test(); + #endif return boost::report_errors(); } From 8563f0bea143a292039e826d76fdaaa12b71963c Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 16 Oct 2024 14:27:28 -0400 Subject: [PATCH 096/107] Add standard gitignore --- doc/.gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 doc/.gitignore diff --git a/doc/.gitignore b/doc/.gitignore new file mode 100644 index 0000000..ff8f381 --- /dev/null +++ b/doc/.gitignore @@ -0,0 +1,2 @@ +/pdf/ +/html/ From 27f91244e1cbf06f0d957bbdf80d04397fe586b1 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 16 Oct 2024 14:27:37 -0400 Subject: [PATCH 097/107] Add jamfile --- doc/Jamfile | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 doc/Jamfile diff --git a/doc/Jamfile b/doc/Jamfile new file mode 100644 index 0000000..65f8705 --- /dev/null +++ b/doc/Jamfile @@ -0,0 +1,25 @@ +# Copyright 2017, 2018 Peter Dimov +# Copyright 2024 Matt Borland +# Distributed under the Boost Software License, Version 1.0. +# https://www.boost.org/LICENSE_1_0.txt + +import asciidoctor ; + +html crypt.html : crypt.adoc + : /boost/boostlook//boostlook + crypt-docinfo-footer.html + ; + +install html_ : crypt.html : html ; + +pdf crypt.pdf : crypt.adoc ; +explicit crypt.pdf ; + +install pdf_ : crypt.pdf : pdf ; +explicit pdf_ ; + +############################################################################### +alias boostdoc ; +explicit boostdoc ; +alias boostrelease : html_ ; +explicit boostrelease ; From 28eccea00c0251c92bfbe5b8bfc57dd7f9035904 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 16 Oct 2024 14:27:45 -0400 Subject: [PATCH 098/107] Add docinfo-footer --- doc/crypt-docinfo-footer.html | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 doc/crypt-docinfo-footer.html diff --git a/doc/crypt-docinfo-footer.html b/doc/crypt-docinfo-footer.html new file mode 100644 index 0000000..622aa5f --- /dev/null +++ b/doc/crypt-docinfo-footer.html @@ -0,0 +1,6 @@ + From de60e93988fa5cc0a78d869a9f0ce58115e1f64a Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 16 Oct 2024 14:27:56 -0400 Subject: [PATCH 099/107] Add copyright page --- doc/crypt/copyright.adoc | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 doc/crypt/copyright.adoc diff --git a/doc/crypt/copyright.adoc b/doc/crypt/copyright.adoc new file mode 100644 index 0000000..f884e9c --- /dev/null +++ b/doc/crypt/copyright.adoc @@ -0,0 +1,12 @@ +//// +Copyright 2024 Matt Borland +Distributed under the Boost Software License, Version 1.0. +https://www.boost.org/LICENSE_1_0.txt +//// + +[#copyright] += Copyright and License +:idprefix: license_ + +This documentation is copyright 2024 Matt Borland and Chris Kormanyos and is distributed under +the http://www.boost.org/LICENSE_1_0.txt[Boost Software License, Version 1.0]. From c7781753395dbc191481d9db07bdd743655814a8 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 16 Oct 2024 14:30:03 -0400 Subject: [PATCH 100/107] Add reference section --- doc/crypt/reference.adoc | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 doc/crypt/reference.adoc diff --git a/doc/crypt/reference.adoc b/doc/crypt/reference.adoc new file mode 100644 index 0000000..87d49fc --- /dev/null +++ b/doc/crypt/reference.adoc @@ -0,0 +1,15 @@ +//// +Copyright 2024 Matt Borland +Distributed under the Boost Software License, Version 1.0. +https://www.boost.org/LICENSE_1_0.txt +//// + +[#reference] += References +:idprefix: ref_ + +The following books, papers and blog posts serve as the basis for the algorithms used in the library: + +:linkattrs: + +- Ronald L. Rivest, https://www.ietf.org/rfc/rfc1321.txt[RFC 1321: The MD5 Message-Digest Algorithm], 1992 From 6e6767685f0c0ec85d8ecdb0a9463b9205e9ccb6 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 16 Oct 2024 14:33:58 -0400 Subject: [PATCH 101/107] Add overview shell --- doc/crypt/overview.adoc | 70 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 doc/crypt/overview.adoc diff --git a/doc/crypt/overview.adoc b/doc/crypt/overview.adoc new file mode 100644 index 0000000..1fab53d --- /dev/null +++ b/doc/crypt/overview.adoc @@ -0,0 +1,70 @@ +//// +Copyright 2023 Matt Borland +Distributed under the Boost Software License, Version 1.0. +https://www.boost.org/LICENSE_1_0.txt +//// + +[#overview] += Overview +:idprefix: overview_ + +== Description + +Boost.Decimal is an implementation of https://standards.ieee.org/ieee/754/6210/[IEEE 754] and https://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2849.pdf[ISO/IEC DTR 24733] Decimal Floating Point numbers. +The library is header-only, has no dependencies, and requires C++14. + +== Motivation + +Current C++ floating point types store the significand (often incorrectly referred to as the mantissa) as binary digits. +Famously this leads to representation errors: https://0.30000000000000004.com. +Decimal floating point numbers avoid this issue by storing the significand in base-10 (decimal). +The other major difference between binary and decimal floating point types is that the latter allows for multiple representations of the same number. +For example 1e5 could also be stored as 0.1e6, 0.01e7, so on and so forth. +These are referred to as cohorts which binary does not have as there is only one way to represent each number in binary floating point. + +== Use Cases + +The use case for Decimal Floating Point numbers is where rounding errors are significantly impactful such as finance. +In applications where integer or fixed-point arithmetic are used to combat this issue Decimal Floating Point numbers can provide a significantly greater range of values. +For example, while a fixed-point representation that allocates 8 decimal digits and 2 decimal places can represent the numbers 123456.78, 8765.43, 123.00, and so on, a floating-point representation with 8 decimal digits could also represent 1.2345678, 1234567.8, 0.000012345678, 12345678000000000, and so on. + +== Supported Compilers + +Boost.Decimal is tested natively on Ubuntu (x86_64, s390x, and aarch64), macOS (x86_64, and Apple Silicon), and Windows (x32 and x64); +as well as emulated PPC64LE and STM32 using QEMU with the following compilers: + +* GCC 7 and later +* Clang 6 and later +* Visual Studio 2017 and later +* Intel OneAPI DPC++ + +Tested on https://github.com/cppalliance/decimal/actions[Github Actions] and https://drone.cpp.al/cppalliance/decimal[Drone]. +Coverage can be found on https://app.codecov.io/gh/cppalliance/decimal[Codecov]. + +== Basic Usage + +[source, c++] +---- +#include +#include +#include + +int main() +{ + using namespace boost::decimal; + + // Outputs 0.30000000000000004 + std::cout << std::setprecision(17) << 0.1 + 0.2; + + // Construct the two decimal values + constexpr decimal64 a {1, -1}; // 1e-1 or 0.1 + constexpr decimal64 b {2, -1}; // 2e-1 or 0.2 + + // Outputs 0.30000000000000000 + std::cout << a + b << std::endl; + + return 0; +} + +---- + From 19019c047f5bad73820e1b836779f1c955c4be1d Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 16 Oct 2024 14:36:33 -0400 Subject: [PATCH 102/107] Add macro configuration section --- doc/crypt/config.adoc | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 doc/crypt/config.adoc diff --git a/doc/crypt/config.adoc b/doc/crypt/config.adoc new file mode 100644 index 0000000..f252c37 --- /dev/null +++ b/doc/crypt/config.adoc @@ -0,0 +1,19 @@ +//// +Copyright 2023 Matt Borland +Distributed under the Boost Software License, Version 1.0. +https://www.boost.org/LICENSE_1_0.txt +//// + +[#configuration] += Configuration Macros +:idprefix: config_ + +== User Configurable Macros + +The following configuration macros are available: + +- None at this time + +== Automatic Configuration Macros + +- `BOOST_CRYPT_HAS_STRING_VIEW`: This is defined when compiling with at least C++17 and your standard library has a complete implementation of ``. From 52d40d79ae54c9de0913a1b08827ef0211c943cb Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 16 Oct 2024 14:56:39 -0400 Subject: [PATCH 103/107] Allow conversion to std::array --- include/boost/crypt/utility/array.hpp | 15 +++++++++++++++ test/test_md5.cpp | 4 +++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/include/boost/crypt/utility/array.hpp b/include/boost/crypt/utility/array.hpp index 302aefa..f13b1dd 100644 --- a/include/boost/crypt/utility/array.hpp +++ b/include/boost/crypt/utility/array.hpp @@ -10,6 +10,10 @@ #include #include +#ifndef BOOST_CRYPT_BUILD_MODULE +#include +#endif + namespace boost { namespace crypt { @@ -97,6 +101,17 @@ class array a = *this; *this = temp; } + + constexpr operator std::array() noexcept + { + std::array new_array{}; + for (boost::crypt::size_t i {}; i < N; ++i) + { + new_array[i] = elements[i]; + } + + return new_array; + } }; template diff --git a/test/test_md5.cpp b/test/test_md5.cpp index ab4429e..fb9ae41 100644 --- a/test/test_md5.cpp +++ b/test/test_md5.cpp @@ -224,7 +224,9 @@ void test_random_values() const std::size_t current_str_len {str_len(rng)}; boost::crypt::generate_random_string(str, current_str_len); const auto uuid_res {get_boost_uuid_result(str, current_str_len)}; - const auto crypt_res {boost::crypt::md5(str, current_str_len)}; + + // boost::crypt::array is implicitly convertible to std::array + const std::array crypt_res = boost::crypt::md5(str, current_str_len); for (std::size_t j {}; j < crypt_res.size(); ++j) { From c626ad72e876733eefefff24721c74d5bcdfa785 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 16 Oct 2024 15:00:36 -0400 Subject: [PATCH 104/107] Add array docs --- doc/crypt/array.adoc | 70 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 doc/crypt/array.adoc diff --git a/doc/crypt/array.adoc b/doc/crypt/array.adoc new file mode 100644 index 0000000..3353bcd --- /dev/null +++ b/doc/crypt/array.adoc @@ -0,0 +1,70 @@ +//// +Copyright 2024 Matt Borland +Distributed under the Boost Software License, Version 1.0. +https://www.boost.org/LICENSE_1_0.txt +//// + +[#array] +:idprefix: array_ + +In order for this lab to use `` in a `constexpr` environment we would need to support C+\+17. +Additionally, CUDA environments do not directly support `std::array`. +For these reasons we reimplement `` in our namespace that both supports both C++14 and CUDA. +It is *IMPLICITLY* convertible to `std::array` for convenience. + +[source, c++] +---- +template +class array +{ +public: + using reference = T&; + using const_reference = const T&; + using iterator = T*; + using const_iterator = const T*; + using size_type = size_t; + using difference_type = ptrdiff_t; + using value_type = T; + using pointer = T*; + using const_pointer = const T*; + + T elements[N]; + + // Iterators + BOOST_CRYPT_GPU_ENABLED constexpr auto begin() noexcept -> iterator; + BOOST_CRYPT_GPU_ENABLED constexpr auto begin() const noexcept -> iterator; + BOOST_CRYPT_GPU_ENABLED constexpr auto cbegin() const noexcept -> const_iterator; + BOOST_CRYPT_GPU_ENABLED constexpr auto end() noexcept -> iterator; + BOOST_CRYPT_GPU_ENABLED constexpr auto end() const noexcept -> iterator; + BOOST_CRYPT_GPU_ENABLED constexpr auto cend() const noexcept -> const_iterator; + + // Sizing + BOOST_CRYPT_GPU_ENABLED constexpr auto size() const noexcept -> size_type; + BOOST_CRYPT_GPU_ENABLED constexpr auto max_size() const noexcept -> size_type; + + // Accessors + BOOST_CRYPT_GPU_ENABLED constexpr auto operator[](size_type n) noexcept; + + BOOST_CRYPT_GPU_ENABLED constexpr auto operator[](size_type n) const noexcept; + + // For at instead of throwing on out of range return the last element since throwing doesn't work on device + BOOST_CRYPT_GPU_ENABLED constexpr auto at(size_type n) noexcept -> reference; + + BOOST_CRYPT_GPU_ENABLED constexpr auto at(size_type n) const noexcept -> const_reference; + + BOOST_CRYPT_GPU_ENABLED constexpr auto front() noexcept -> reference { return elements[0]; } + BOOST_CRYPT_GPU_ENABLED constexpr auto front() const noexcept -> const_reference { return elements[0]; } + BOOST_CRYPT_GPU_ENABLED constexpr auto back() noexcept -> reference { return elements[N - 1]; } + BOOST_CRYPT_GPU_ENABLED constexpr auto back() const noexcept -> const_reference { return elements[N - 1]; } + + BOOST_CRYPT_GPU_ENABLED constexpr auto data() noexcept -> pointer { return elements; } + BOOST_CRYPT_GPU_ENABLED constexpr auto data() const noexcept -> const_pointer { return elements; } + + BOOST_CRYPT_GPU_ENABLED constexpr auto fill(const value_type& v) -> void; + + BOOST_CRYPT_GPU_ENABLED constexpr auto swap(array& a); + + // Conversion + constexpr operator std::array() noexcept; +}; +---- From d999317139106fab368e8f8d7dfcb958f83a53ed Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 16 Oct 2024 15:00:54 -0400 Subject: [PATCH 105/107] Add API reference section --- doc/crypt/api_reference.adoc | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 doc/crypt/api_reference.adoc diff --git a/doc/crypt/api_reference.adoc b/doc/crypt/api_reference.adoc new file mode 100644 index 0000000..f4bb775 --- /dev/null +++ b/doc/crypt/api_reference.adoc @@ -0,0 +1,30 @@ +//// +Copyright 2024 Matt Borland +Distributed under the Boost Software License, Version 1.0. +https://www.boost.org/LICENSE_1_0.txt +//// + +[#api_reference] += API Reference +:idprefix: api_ref_ + +== Types + +- <> + +== Structures and Classes + +- <> +- <> + +== Enums + +- None + +== Constants + +- None + +== Macros + +See: <> From 56ee202237e618f74ea153ff9409a9ac41c94f20 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 16 Oct 2024 16:00:25 -0400 Subject: [PATCH 106/107] Add MD5 documentation --- doc/crypt/md5.adoc | 115 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 doc/crypt/md5.adoc diff --git a/doc/crypt/md5.adoc b/doc/crypt/md5.adoc new file mode 100644 index 0000000..63b20fa --- /dev/null +++ b/doc/crypt/md5.adoc @@ -0,0 +1,115 @@ +//// +Copyright 2024 Matt Borland +Distributed under the Boost Software License, Version 1.0. +https://www.boost.org/LICENSE_1_0.txt +//// + +[#md5] +:idprefix: md5_ + += MD5 + +This library supports MD5 as described in https://www.ietf.org/rfc/rfc1321.txt[RFC 1321]. +There is a wide range of acceptable inputs for the base md5 function: + +== Hashing Functions + +[source, c++] +---- +namespace boost { +namespace crypt { + +uisng return_type = boost::crypt::array; + +BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const char* str) noexcept -> return_type; + +BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const char* str, size_t len) noexcept -> return_type; + +BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const unsigned char* str) noexcept -> return_type; + +BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const unsigned char* str, size_t len) noexcept -> return_type; + +BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const char16_t* str) noexcept -> return_type; + +BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const char16_t* str, size_t len) noexcept -> return_type; + +BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const char32_t* str) noexcept -> return_type; + +BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const char32_t* str, size_t len) noexcept -> return_type; + +BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const wchar_t* str) noexcept -> return_type; + +BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const wchar_t* str, size_t len) noexcept -> return_type; + +inline auto md5(const std::string& str) noexcept -> return_type; + +inline auto md5(const std::u16string& str) noexcept -> return_type; + +inline auto md5(const std::u32string& str) noexcept -> return_type; + +inline auto md5(const std::wstring& str) noexcept -> return_type; + +#ifdef BOOST_CRYPT_HAS_STRING_VIEW + +inline auto md5(std::string_view str) noexcept -> return_type; + +inline auto md5(std::u16string_view str) noexcept -> return_type; + +inline auto md5(std::u32string_view str) noexcept -> return_type; + +inline auto md5(std::wstring_view str) noexcept -> return_type; + +#endif // BOOST_CRYPT_HAS_STRING_VIEW + +} //namespace crypt +} //namespace boost +---- + +== File Hashing Functions + +We also have the ability to scan files and return the MD5 value: + +[source, c++] +---- +namespace boost { +namespace crypt { + +uisng return_type = boost::crypt::array; + +inline auto md5_file(const char* filepath) noexcept -> return_type; + +inline auto md5_file(const std::string& filepath) noexcept -> return_type; + +inline auto md5_file(std::string_view filepath) noexcept -> return_type; + +} // namespace crypt +} // namespace boost +---- + +== Hashing Object + +[#md5_hasher] +Lastly, there is also the ability to create a MD5 hashing object and feed it bytes as the user parses them. +This class does not use any dynamic memory allocation. + +[source, c++] +---- +namespace boost { +namespace crypt { + +class md5_hasher +{ + init(); + + template + BOOST_CRYPT_GPU_ENABLED constexpr auto process_byte(ByteType byte) noexcept -> void; + + template + BOOST_CRYPT_GPU_ENABLED constexpr auto process_bytes(ForwardIter buffer, size_t byte_count) noexcept -> void; + + constexpr auto get_digest() noexcept -> boost::crypt::array; +}; + +} // namespace crypt +} // namespace boost +---- From f6b3fe0aa74ccc8f2163d349623c51e13398a00f Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 16 Oct 2024 16:00:37 -0400 Subject: [PATCH 107/107] Add overall doc file --- doc/crypt.adoc | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 doc/crypt.adoc diff --git a/doc/crypt.adoc b/doc/crypt.adoc new file mode 100644 index 0000000..093e482 --- /dev/null +++ b/doc/crypt.adoc @@ -0,0 +1,30 @@ +//// +Copyright 2024 Matt Borland +Distributed under the Boost Software License, Version 1.0. +https://www.boost.org/LICENSE_1_0.txt +//// + += Crypt: A Modern Cryptographic Module in C++14 +:toc: left +:toclevels: 4 +:idprefix: +:listing-caption: Code Example +:docinfo: private-footer +:source-highlighter: rouge +:source-language: c++ + +:leveloffset: +1 + +include::crypt/overview.adoc[] + +include::crypt/api_reference.adoc[] + +include::crypt/md5.adoc[] + +include::crypt/config.adoc[] + +include::crypt/reference.adoc[] + +include::crypt/copyright.adoc[] + +:leveloffset: -1