Skip to content

Commit

Permalink
Merge pull request #3715 from Rohde-Schwarz/span/memops
Browse files Browse the repository at this point in the history
Range-based mem_ops
  • Loading branch information
reneme authored Nov 21, 2023
2 parents 20279c6 + dd160f3 commit 3005ae6
Show file tree
Hide file tree
Showing 3 changed files with 285 additions and 44 deletions.
82 changes: 82 additions & 0 deletions src/lib/utils/concepts.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,14 @@
#ifndef BOTAN_CONCEPTS_H_
#define BOTAN_CONCEPTS_H_

#include <botan/assert.h>

#include <compare>
#include <concepts>
#include <cstdint>
#include <ostream>
#include <ranges>
#include <span>
#include <type_traits>

namespace Botan {
Expand All @@ -29,6 +33,84 @@ struct is_strong_type<Strong<Ts...>> : std::true_type {};
template <typename... Ts>
constexpr bool is_strong_type_v = is_strong_type<std::remove_const_t<Ts>...>::value;

namespace ranges {

/**
* Models a std::ranges::contiguous_range that (optionally) restricts its
* value_type to ValueT. In other words: a stretch of contiguous memory of
* a certain type (optional ValueT).
*/
template <typename T, typename ValueT = std::ranges::range_value_t<T>>
concept contiguous_range = std::ranges::contiguous_range<T> && std::same_as<ValueT, std::ranges::range_value_t<T>>;

/**
* Models a std::ranges::contiguous_range that satisfies
* std::ranges::output_range with an arbitrary value_type. In other words: a
* stretch of contiguous memory of a certain type (optional ValueT) that can be
* written to.
*/
template <typename T, typename ValueT = std::ranges::range_value_t<T>>
concept contiguous_output_range = contiguous_range<T, ValueT> && std::ranges::output_range<T, ValueT>;

/**
* Models a range that can be turned into a std::span<>. Typically, this is some
* form of ranges::contiguous_range.
*/
template <typename T>
concept spanable_range = std::constructible_from<std::span<const std::ranges::range_value_t<T>>, T>;

/**
* Find the length in bytes of a given contiguous range @p r.
*/
inline constexpr size_t size_bytes(spanable_range auto&& r) {
return std::span{r}.size_bytes();
}

/**
* Check that a given range @p r has a certain statically-known byte length. If
* the range's extent is known at compile time, this is a static check,
* otherwise a runtime argument check will be added.
*
* @throws Invalid_Argument if range @p r has a dynamic extent and does not
* feature the expected byte length.
*/
template <size_t expected, spanable_range R>
inline constexpr void assert_exact_byte_length(R&& r) {
const std::span s{r};
if constexpr(decltype(s)::extent != std::dynamic_extent) {
static_assert(s.size_bytes() == expected, "memory region does not have expected byte lengths");
} else {
BOTAN_ASSERT(s.size_bytes() == expected, "memory region does not have expected byte lengths");
}
}

/**
* Check that a list of ranges (in @p r0 and @p rs) all have the same byte
* lengths. If the first range's extent is known at compile time, this will be a
* static check for all other ranges whose extents are known at compile time,
* otherwise a runtime argument check will be added.
*
* @throws Invalid_Argument if any range has a dynamic extent and not all
* ranges feature the same byte length.
*/
template <spanable_range R0, spanable_range... Rs>
inline constexpr void assert_equal_byte_lengths(R0&& r0, Rs&&... rs)
requires(sizeof...(Rs) > 0)
{
const std::span s0{r0};

if constexpr(decltype(s0)::extent != std::dynamic_extent) {
constexpr size_t expected_size = s0.size_bytes();
(assert_exact_byte_length<expected_size>(rs), ...);
} else {
const size_t expected_size = s0.size_bytes();
BOTAN_ARG_CHECK(((std::span<const std::ranges::range_value_t<Rs>>{rs}.size_bytes() == expected_size) && ...),
"memory regions don't have equal lengths");
}
}

} // namespace ranges

namespace concepts {

// TODO: C++20 use std::convertible_to<> that was not available in Android NDK
Expand Down
7 changes: 7 additions & 0 deletions src/lib/utils/mem_ops.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,11 @@ uint8_t ct_compare_u8(const uint8_t x[], const uint8_t y[], size_t len) {
return CT::is_equal(x, y, len).value();
}

bool constant_time_compare(std::span<const uint8_t> x, std::span<const uint8_t> y) {
const auto min_size = CT::Mask<size_t>::is_lte(x.size(), y.size()).select(x.size(), y.size());
const auto equal_size = CT::Mask<size_t>::is_equal(x.size(), y.size());
const auto equal_content = CT::Mask<size_t>::expand(CT::is_equal(x.data(), y.data(), min_size));
return (equal_content & equal_size).as_bool();
}

} // namespace Botan
Loading

0 comments on commit 3005ae6

Please sign in to comment.