Botan 3.5.0
Crypto and TLS for C&
int_utils.h
Go to the documentation of this file.
1/*
2* (C) 2024 Jack Lloyd
3*
4* Botan is released under the Simplified BSD License (see license.txt)
5*/
6
7#ifndef BOTAN_INT_UTILS_H_
8#define BOTAN_INT_UTILS_H_
9
10#include <botan/concepts.h>
11#include <botan/exceptn.h>
12#include <botan/types.h>
13#include <limits>
14#include <optional>
15
16namespace Botan {
17
18template <std::unsigned_integral T>
19constexpr inline std::optional<T> checked_add(T a, T b) {
20 const T r = a + b;
21 if(r < a || r < b) {
22 return {};
23 }
24 return r;
25}
26
27template <std::unsigned_integral T, std::unsigned_integral... Ts>
28 requires all_same_v<T, Ts...>
29constexpr inline std::optional<T> checked_add(T a, T b, Ts... rest) {
30 if(auto r = checked_add(a, b)) {
31 return checked_add(r.value(), rest...);
32 } else {
33 return {};
34 }
35}
36
37template <std::unsigned_integral T>
38constexpr inline std::optional<T> checked_mul(T a, T b) {
39 // Multiplication by 1U is a hack to work around C's insane
40 // integer promotion rules.
41 // https://stackoverflow.com/questions/24795651
42 const T r = (1U * a) * b;
43 // If a == 0 then the multiply certainly did not overflow
44 // Otherwise r / a == b unless overflow occured
45 if(a != 0 && r / a != b) {
46 return {};
47 }
48 return r;
49}
50
51namespace detail {
52
53template <typename T>
55
56template <int_or_strong_type T>
57struct unwrap_type {};
58
59template <int_or_strong_type T>
60 requires std::integral<T>
61struct unwrap_type<T> {
62 using type = T;
63};
64
65template <int_or_strong_type T>
67struct unwrap_type<T> {
68 using type = typename T::wrapped_type;
69};
70
71template <int_or_strong_type T>
73
74template <int_or_strong_type T>
75constexpr auto unwrap(T t) -> unwrap_type_t<T> {
76 if constexpr(std::integral<T>) {
77 return t;
78 } else {
79 return t.get();
80 }
81}
82
83template <int_or_strong_type T>
84constexpr auto wrap(unwrap_type_t<T> t) -> T {
85 if constexpr(std::integral<T>) {
86 return t;
87 } else {
88 return T(t);
89 }
90}
91
92} // namespace detail
93
94template <detail::int_or_strong_type RT, typename ExceptionType, detail::int_or_strong_type AT>
95constexpr RT checked_cast_to_or_throw(AT i, std::string_view error_msg_on_fail) {
96 const auto unwrapped_input = detail::unwrap(i);
97 using unwrapped_input_type = detail::unwrap_type_t<AT>;
98 using unwrapped_result_type = detail::unwrap_type_t<RT>;
99
100 const auto unwrapped_result = static_cast<unwrapped_result_type>(unwrapped_input);
101 if(unwrapped_input != static_cast<unwrapped_input_type>(unwrapped_result)) [[unlikely]] {
102 throw ExceptionType(error_msg_on_fail);
103 }
104
105 return detail::wrap<RT>(unwrapped_result);
106}
107
108template <detail::int_or_strong_type RT, detail::int_or_strong_type AT>
109constexpr RT checked_cast_to(AT i) {
110 return checked_cast_to_or_throw<RT, Internal_Error>(i, "Error during integer conversion");
111}
112
113#define BOTAN_CHECKED_ADD(x, y) checked_add(x, y, __FILE__, __LINE__)
114#define BOTAN_CHECKED_MUL(x, y) checked_mul(x, y)
115
116} // namespace Botan
117
118#endif
FE_25519 T
Definition ge.cpp:34
constexpr auto unwrap(T t) -> unwrap_type_t< T >
Definition int_utils.h:75
constexpr auto wrap(unwrap_type_t< T > t) -> T
Definition int_utils.h:84
typename unwrap_type< T >::type unwrap_type_t
Definition int_utils.h:72
constexpr std::optional< T > checked_add(T a, T b)
Definition int_utils.h:19
constexpr RT checked_cast_to(AT i)
Definition int_utils.h:109
constexpr RT checked_cast_to_or_throw(AT i, std::string_view error_msg_on_fail)
Definition int_utils.h:95
constexpr std::optional< T > checked_mul(T a, T b)
Definition int_utils.h:38