CsCrypto  1.0.1
hash_digest.h
1 /***********************************************************************
2 *
3 * Copyright (c) 2021-2024 Tim van Deurzen
4 * Copyright (c) 2021-2024 Barbara Geller
5 * Copyright (c) 2021-2024 Ansel Sermersheim
6 *
7 * This file is part of CsCrypto.
8 *
9 * CsCrypto is free software, released under the BSD 2-Clause license.
10 * For license details refer to LICENSE provided with this project.
11 *
12 * CsCrypto is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15 *
16 * https://opensource.org/licenses/BSD-2-Clause
17 *
18 ***********************************************************************/
19 
20 #ifndef CS_CRYPTO_HASH_DIGEST_H
21 #define CS_CRYPTO_HASH_DIGEST_H
22 
23 #include <core/hash/hash_append.h>
24 #include <util/tools/crypto_traits.h>
25 
26 #include <optional>
27 #include <type_traits>
28 
29 namespace cs_crypto::hash {
30 
31 template <typename T>
32 using finalize_member_fn = decltype(std::declval<T&&>().finalize());
33 
34 template <typename T>
35 using finalize_free_fn = decltype(finalize(std::declval<T&&>()));
36 
37 template <typename T>
38 using make_context_fn = decltype(T::make_context());
39 
40 struct finalize_dispatch_fn {
41  template <typename HashContext>
42  auto operator()(HashContext &&ctx) const
43  {
44  if constexpr (traits::is_detected<finalize_member_fn, HashContext>{}) {
45  return std::move(ctx).finalize();
46 
47  } else if constexpr (traits::is_detected<finalize_free_fn, HashContext>{}) {
48  return finalize(std::move(ctx));
49 
50  } else {
51  static_assert(traits::always_false<HashContext>{},
52  "Driver incomplete, unable to locate finalize() method or free function");
53  }
54  }
55 };
56 
57 inline constexpr finalize_dispatch_fn finalize{};
58 
59 template <typename Ctx>
60 [[maybe_unused]] constexpr static bool is_hash_digest_context_v =
61  is_appendable_hash_context_v<Ctx> &&
62  traits::is_detected_v<make_context_fn, Ctx> &&
63  (traits::is_detected_v<finalize_free_fn, Ctx> || traits::is_detected_v<finalize_member_fn, Ctx>);
64 
65 template <typename HashContext>
66 struct hash_digest_internal {
67  using result_type = std::optional<cs_crypto::traits::remove_optional_t<decltype(finalize(std::declval<HashContext &&>()))>>;
68 
69  template <typename... Ts>
70  constexpr auto operator()(Ts &&... args) const -> result_type
71  {
72  static_assert(! std::is_same_v<HashContext, cs_crypto::traits::nonesuch>,
73  "Selected driver does not support this operation");
74 
75  static_assert(is_hash_digest_context_v<HashContext>,
76  "Hash context does not satisfy is_hash_digest_context_v type trait");
77 
78  auto maybe_context = HashContext::make_context();
79  if (! maybe_context.has_value()) {
80  return std::nullopt;
81  }
82 
83  auto ctx = std::move(maybe_context).value();
84  hash_append(ctx, std::forward<Ts>(args)...);
85 
86  return finalize(std::move(ctx));
87  }
88 };
89 
90 template <typename HashDriver, template <typename> typename HashSelector>
91 inline constexpr hash_digest_internal<HashSelector<HashDriver>> hash_digest = {};
92 
93 } // namespace cs_crypto::hash
94 
95 #endif