20 #ifndef CS_CRYPTO_HASH_APPEND_H
21 #define CS_CRYPTO_HASH_APPEND_H
23 #include <util/conversions/byte.h>
24 #include <util/tools/crypto_traits.h>
25 #include <util/tools/is_detected_traits.h>
26 #include <util/tools/span.h>
31 #include <type_traits>
34 namespace cs_crypto::hash {
37 using update_member_fn =
decltype(std::declval<T &>().update(std::declval<cs_crypto::util::span<std::byte>>()));
40 using update_free_fn =
decltype(update(std::declval<T &>(), std::declval<cs_crypto::util::span<std::byte>>()));
42 struct update_dispatch_fn {
43 template <
typename HashContext>
44 constexpr auto operator()(HashContext &ctx, cs_crypto::util::span<std::byte> bytes)
const
46 if constexpr (traits::is_detected_v<update_member_fn, HashContext>) {
47 return ctx.update(bytes);
49 }
else if constexpr (traits::is_detected_v<update_free_fn, HashContext>) {
50 return update(ctx, bytes);
53 static_assert(traits::always_false<HashContext>{},
54 "Driver incomplete, unable to locate update() as a method or free function");
59 inline constexpr const update_dispatch_fn dispatch_update{};
61 template <
typename HashContext,
typename T,
62 typename = std::enable_if_t<cs_crypto::traits::is_uniquely_represented_byte_v<T>>>
63 constexpr auto internal_hash_append(HashContext &ctx,
const T v)
65 return dispatch_update(ctx, {util::to_byte_ptr(std::addressof(v)), 1});
68 template <
typename HashContext,
typename T, std::size_t N,
69 typename = std::enable_if_t<cs_crypto::traits::is_uniquely_represented_byte_v<T>>>
70 constexpr auto internal_hash_append(HashContext &ctx,
const T (&arr)[N])
72 return dispatch_update(ctx, {util::to_byte_ptr(std::addressof(arr[0])), N});
75 template <
typename HashContext,
typename T, std::size_t N,
76 typename = std::enable_if_t<cs_crypto::traits::is_uniquely_represented_byte_v<T>>>
77 constexpr auto internal_hash_append(HashContext &ctx,
const std::array<T, N> &data)
79 return dispatch_update(ctx, {util::to_byte_ptr(data.data()), data.size()});
82 template <
typename HashContext,
typename T,
83 typename = std::enable_if_t<cs_crypto::traits::is_uniquely_represented_byte_v<T>>>
84 constexpr auto internal_hash_append(HashContext &ctx,
const std::vector<T> &data)
86 return dispatch_update(ctx, {util::to_byte_ptr(data.data()), data.size()});
89 template <
typename HashContext>
90 constexpr auto internal_hash_append(HashContext &ctx,
const std::string &s)
92 return dispatch_update(ctx, {util::to_byte_ptr(s.data()), s.size()});
95 template <
typename HashContext,
typename T,
typename = std::enable_if_t<traits::is_iterable_v<T>>>
96 constexpr auto internal_hash_append(HashContext &ctx,
const T &data)
100 for (
const auto elem : data) {
101 internal_hash_append(ctx, elem);
105 template <
typename HashContext,
typename It,
typename End>
106 constexpr auto internal_hash_append(HashContext &ctx, It iter, End end)
110 while (iter != end) {
111 internal_hash_append(ctx, *iter);
112 iter = std::next(iter);
116 template <
typename Ctx>
117 [[maybe_unused]]
inline constexpr bool is_appendable_hash_context_v =
118 std::is_copy_assignable_v<Ctx> && std::is_copy_constructible_v<Ctx> &&
119 std::is_move_assignable_v<Ctx> && std::is_move_constructible_v<Ctx> &&
120 (traits::is_detected_v<update_free_fn, Ctx> || traits::is_detected_v<update_member_fn, Ctx>);
122 struct hash_append_internal {
123 template <
typename HashContext,
typename... Ts>
124 constexpr auto operator()(HashContext && context, Ts &&... args)
const
126 static_assert(! std::is_same_v<HashContext, cs_crypto::traits::nonesuch>,
127 "Selected driver does not support this operation");
129 static_assert(is_appendable_hash_context_v<std::remove_reference_t<HashContext>>,
130 "Hash context does not satisfy is_appendable_hash_context type trait");
132 return internal_hash_append(std::forward<HashContext>(context), std::forward<Ts>(args)...);
136 inline constexpr const hash_append_internal hash_append = {};