From 8df03f119e1dcc7d6ff4dba51666163e922e4af2 Mon Sep 17 00:00:00 2001 From: Rene Meusel Date: Thu, 11 Jan 2024 15:53:01 +0100 Subject: [PATCH] add range based overloads of copy_out_be/le Co-Authored-By: Fabian Albert --- src/lib/utils/loadstor.h | 51 +++++++++++++++++++++++++++++ src/tests/test_utils.cpp | 70 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 120 insertions(+), 1 deletion(-) diff --git a/src/lib/utils/loadstor.h b/src/lib/utils/loadstor.h index 09c372fd29f..bec52fba04c 100644 --- a/src/lib/utils/loadstor.h +++ b/src/lib/utils/loadstor.h @@ -712,6 +712,57 @@ inline constexpr auto store_be(ParamTs&&... params) { return detail::store_any(std::forward(params)...); } +namespace detail { + +template +size_t copy_out_any_word_aligned_portion(std::span& out, std::span& in) { + const size_t full_words = out.size() / sizeof(T); + const size_t full_word_bytes = full_words * sizeof(T); + const size_t remaining_bytes = out.size() - full_word_bytes; + BOTAN_ASSERT_NOMSG(in.size_bytes() >= full_word_bytes + remaining_bytes); + + // copy full words + store_any(out.first(full_word_bytes), in.first(full_words)); + out = out.subspan(full_word_bytes); + in = in.subspan(full_words); + + return remaining_bytes; +} + +} // namespace detail + +/** + * Partially copy a subset of @p in into @p out using big-endian + * byte order. + */ +template +void copy_out_be(std::span out, InR&& in) { + using T = std::ranges::range_value_t; + std::span in_s{in}; + const auto remaining_bytes = detail::copy_out_any_word_aligned_portion(out, in_s); + + // copy remaining bytes as a partial word + for(size_t i = 0; i < remaining_bytes; ++i) { + out[i] = get_byte_var(i, in_s.front()); + } +} + +/** + * Partially copy a subset of @p in into @p out using little-endian + * byte order. + */ +template +void copy_out_le(std::span out, InR&& in) { + using T = std::ranges::range_value_t; + std::span in_s{in}; + const auto remaining_bytes = detail::copy_out_any_word_aligned_portion(out, in_s); + + // copy remaining bytes as a partial word + for(size_t i = 0; i < remaining_bytes; ++i) { + out[i] = get_byte_var(sizeof(T) - 1 - i, in_s.front()); + } +} + template void copy_out_be(uint8_t out[], size_t out_bytes, const T in[]) { while(out_bytes >= sizeof(T)) { diff --git a/src/tests/test_utils.cpp b/src/tests/test_utils.cpp index 8a9e30a6e90..ae6781fd183 100644 --- a/src/tests/test_utils.cpp +++ b/src/tests/test_utils.cpp @@ -67,7 +67,7 @@ class Utility_Function_Tests final : public Text_Based_Test { results.push_back(test_loadstore()); results.push_back(test_loadstore_fallback()); results.push_back(test_loadstore_constexpr()); - return results; + return Botan::concat(results, test_copy_out_be_le()); } private: @@ -577,6 +577,74 @@ class Utility_Function_Tests final : public Text_Based_Test { return result; } + + static std::vector test_copy_out_be_le() { + return { + Botan_Tests::CHECK("copy_out_be with 16bit input (word aligned)", + [&](auto& result) { + std::vector out_vector(4); + const std::array in_array = {0x0A0B, 0x0C0D}; + Botan::copy_out_be(out_vector, in_array); + result.test_is_eq(out_vector, Botan::hex_decode("0A0B0C0D")); + }), + + Botan_Tests::CHECK("copy_out_be with 16bit input (partial words)", + [&](auto& result) { + std::vector out_vector(3); + const std::array in_array = {0x0A0B, 0x0C0D}; + Botan::copy_out_be(out_vector, in_array); + result.test_is_eq(out_vector, Botan::hex_decode("0A0B0C")); + }), + + Botan_Tests::CHECK("copy_out_le with 16bit input (word aligned)", + [&](auto& result) { + std::vector out_vector(4); + const std::array in_array = {0x0A0B, 0x0C0D}; + Botan::copy_out_le(out_vector, in_array); + result.test_is_eq(out_vector, Botan::hex_decode("0B0A0D0C")); + }), + + Botan_Tests::CHECK("copy_out_le with 16bit input (partial words)", + [&](auto& result) { + std::vector out_vector(3); + const std::array in_array = {0x0A0B, 0x0C0D}; + Botan::copy_out_le(out_vector, in_array); + result.test_is_eq(out_vector, Botan::hex_decode("0B0A0D")); + }), + + Botan_Tests::CHECK("copy_out_be with 64bit input (word aligned)", + [&](auto& result) { + std::vector out_vector(16); + const std::array in_array = {0x0A0B0C0D0E0F1011, 0x1213141516171819}; + Botan::copy_out_be(out_vector, in_array); + result.test_is_eq(out_vector, Botan::hex_decode("0A0B0C0D0E0F10111213141516171819")); + }), + + Botan_Tests::CHECK("copy_out_le with 64bit input (word aligned)", + [&](auto& result) { + std::vector out_vector(16); + const std::array in_array = {0x0A0B0C0D0E0F1011, 0x1213141516171819}; + Botan::copy_out_le(out_vector, in_array); + result.test_is_eq(out_vector, Botan::hex_decode("11100F0E0D0C0B0A1918171615141312")); + }), + + Botan_Tests::CHECK("copy_out_be with 64bit input (partial words)", + [&](auto& result) { + std::vector out_vector(15); + const std::array in_array = {0x0A0B0C0D0E0F1011, 0x1213141516171819}; + Botan::copy_out_be(out_vector, in_array); + result.test_is_eq(out_vector, Botan::hex_decode("0A0B0C0D0E0F101112131415161718")); + }), + + Botan_Tests::CHECK("copy_out_le with 64bit input (partial words)", + [&](auto& result) { + std::vector out_vector(15); + const std::array in_array = {0x0A0B0C0D0E0F1011, 0x1213141516171819}; + Botan::copy_out_le(out_vector, in_array); + result.test_is_eq(out_vector, Botan::hex_decode("11100F0E0D0C0B0A19181716151413")); + }), + }; + } }; BOTAN_REGISTER_SMOKE_TEST("utils", "util", Utility_Function_Tests);