Skip to content

Commit

Permalink
add range based overloads of copy_out_be/le
Browse files Browse the repository at this point in the history
Co-Authored-By: Fabian Albert <[email protected]>
  • Loading branch information
reneme and FAlbertDev committed Jan 11, 2024
1 parent bc377d6 commit 9250ba8
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 1 deletion.
51 changes: 51 additions & 0 deletions src/lib/utils/loadstor.h
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,57 @@ inline constexpr auto store_be(ParamTs&&... params) {
return detail::store_any<detail::Endianness::Big, ModifierT>(std::forward<ParamTs>(params)...);
}

namespace detail {

template <Endianness endianness, unsigned_integralish T>
size_t copy_out_any_word_aligned_portion(std::span<uint8_t>& out, std::span<const T>& 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<endianness, T>(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 <ranges::spanable_range InR>
void copy_out_be(std::span<uint8_t> out, InR&& in) {
using T = std::ranges::range_value_t<InR>;
std::span<const T> in_s{in};
const auto remaining_bytes = detail::copy_out_any_word_aligned_portion<detail::Endianness::Big>(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 <ranges::spanable_range InR>
void copy_out_le(std::span<uint8_t> out, InR&& in) {
using T = std::ranges::range_value_t<InR>;
std::span<const T> in_s{in};
const auto remaining_bytes = detail::copy_out_any_word_aligned_portion<detail::Endianness::Little>(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 <typename T>
void copy_out_be(uint8_t out[], size_t out_bytes, const T in[]) {
while(out_bytes >= sizeof(T)) {
Expand Down
70 changes: 69 additions & 1 deletion src/tests/test_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class Utility_Function_Tests final : public Text_Based_Test {
std::vector<Test::Result> results;

results.push_back(test_loadstore());
return results;
return Botan::concat(results, test_copy_out_be_le());
}

private:
Expand Down Expand Up @@ -345,6 +345,74 @@ class Utility_Function_Tests final : public Text_Based_Test {

return result;
}

static std::vector<Test::Result> test_copy_out_be_le() {
return {
Botan_Tests::CHECK("copy_out_be with 16bit input (word aligned)",
[&](auto& result) {
std::vector<uint8_t> out_vector(4);
const std::array<uint16_t, 2> 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<uint8_t> out_vector(3);
const std::array<uint16_t, 2> 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<uint8_t> out_vector(4);
const std::array<uint16_t, 2> 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<uint8_t> out_vector(3);
const std::array<uint16_t, 2> 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<uint8_t> out_vector(16);
const std::array<uint64_t, 2> 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<uint8_t> out_vector(16);
const std::array<uint64_t, 2> 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<uint8_t> out_vector(15);
const std::array<uint64_t, 2> 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<uint8_t> out_vector(15);
const std::array<uint64_t, 2> 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);
Expand Down

0 comments on commit 9250ba8

Please sign in to comment.