Botan 3.6.1
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/strong_type.h>
13#include <botan/types.h>
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>
28constexpr std::optional<T> checked_sub(T a, T b) {
29 if(b > a) {
30 return {};
31 }
32 return a - b;
33}
34
35template <std::unsigned_integral T, std::unsigned_integral... Ts>
36 requires all_same_v<T, Ts...>
37constexpr inline std::optional<T> checked_add(T a, T b, Ts... rest) {
38 if(auto r = checked_add(a, b)) {
39 return checked_add(r.value(), rest...);
40 } else {
41 return {};
42 }
43}
44
45template <std::unsigned_integral T>
46constexpr inline std::optional<T> checked_mul(T a, T b) {
47 // Multiplication by 1U is a hack to work around C's insane
48 // integer promotion rules.
49 // https://stackoverflow.com/questions/24795651
50 const T r = (1U * a) * b;
51 // If a == 0 then the multiply certainly did not overflow
52 // Otherwise r / a == b unless overflow occured
53 if(a != 0 && r / a != b) {
54 return {};
55 }
56 return r;
57}
58
59template <typename RT, typename ExceptionType, typename AT>
60 requires std::integral<strong_type_wrapped_type<RT>> && std::integral<strong_type_wrapped_type<AT>>
61constexpr RT checked_cast_to_or_throw(AT i, std::string_view error_msg_on_fail) {
62 const auto unwrapped_input = unwrap_strong_type(i);
63
64 const auto unwrapped_result = static_cast<strong_type_wrapped_type<RT>>(unwrapped_input);
65 if(unwrapped_input != static_cast<strong_type_wrapped_type<AT>>(unwrapped_result)) [[unlikely]] {
66 throw ExceptionType(error_msg_on_fail);
67 }
68
69 return wrap_strong_type<RT>(unwrapped_result);
70}
71
72template <typename RT, typename AT>
73 requires std::integral<strong_type_wrapped_type<RT>> && std::integral<strong_type_wrapped_type<AT>>
74constexpr RT checked_cast_to(AT i) {
75 return checked_cast_to_or_throw<RT, Internal_Error>(i, "Error during integer conversion");
76}
77
78/**
79* SWAR (SIMD within a word) byte-by-byte comparison
80*
81* This individually compares each byte of the provided words.
82* It returns a mask which contains, for each byte, 0xFF if
83* the byte in @p a was less than the byte in @p b. Otherwise the
84* mask is 00.
85*
86* This implementation assumes that the high bits of each byte
87* in both @p a and @p b are clear! It is possible to support the
88* full range of bytes, but this requires additional comparisons.
89*/
90template <std::unsigned_integral T>
91constexpr T swar_lt(T a, T b) {
92 // The constant 0x808080... as a T
93 constexpr T hi1 = (static_cast<T>(-1) / 255) << 7;
94 // The constant 0x7F7F7F... as a T
95 constexpr T lo7 = static_cast<T>(~hi1);
96 T r = (lo7 - a + b) & hi1;
97 // Currently the mask is 80 if lt, otherwise 00. Convert to FF/00
98 return (r << 1) - (r >> 7);
99}
100
101/**
102* SWAR (SIMD within a word) byte-by-byte comparison
103*
104* This individually compares each byte of the provided words.
105* It returns a mask which contains, for each byte, 0x80 if
106* the byte in @p a was less than the byte in @p b. Otherwise the
107* mask is 00.
108*
109* This implementation assumes that the high bits of each byte
110* in both @p lower and @p upper are clear! It is possible to support the
111* full range of bytes, but this requires additional comparisons.
112*/
113template <std::unsigned_integral T>
114constexpr T swar_in_range(T v, T lower, T upper) {
115 // The constant 0x808080... as a T
116 constexpr T hi1 = (static_cast<T>(-1) / 255) << 7;
117 // The constant 0x7F7F7F... as a T
118 constexpr T lo7 = ~hi1;
119
120 const T sub = ((v | hi1) - (lower & lo7)) ^ ((v ^ (~lower)) & hi1);
121 const T a_lo = sub & lo7;
122 const T a_hi = sub & hi1;
123 return (lo7 - a_lo + upper) & hi1 & ~a_hi;
124}
125
126/**
127* Return the index of the first byte with the high bit set
128*/
129template <std::unsigned_integral T>
130constexpr size_t index_of_first_set_byte(T v) {
131 // The constant 0x010101... as a T
132 constexpr T lo1 = (static_cast<T>(-1) / 255);
133 // The constant 0x808080... as a T
134 constexpr T hi1 = lo1 << 7;
135 // How many bits to shift in order to get the top byte
136 constexpr size_t bits = (sizeof(T) * 8) - 8;
137
138 return static_cast<size_t>((((((v & hi1) - 1) & lo1) * lo1) >> bits) - 1);
139}
140
141} // namespace Botan
142
143#endif
FE_25519 T
Definition ge.cpp:34
constexpr std::optional< T > checked_add(T a, T b)
Definition int_utils.h:19
constexpr T swar_lt(T a, T b)
Definition int_utils.h:91
constexpr std::optional< T > checked_sub(T a, T b)
Definition int_utils.h:28
constexpr RT checked_cast_to_or_throw(AT i, std::string_view error_msg_on_fail)
Definition int_utils.h:61
constexpr RT checked_cast_to(AT i)
Definition int_utils.h:74
constexpr T swar_in_range(T v, T lower, T upper)
Definition int_utils.h:114
constexpr size_t index_of_first_set_byte(T v)
Definition int_utils.h:130
constexpr decltype(auto) unwrap_strong_type(T &&t)
Generically unwraps a strong type to its underlying type.
typename detail::wrapped_type_helper< std::remove_cvref_t< T > >::type strong_type_wrapped_type
Extracts the wrapped type from a strong type.
constexpr std::optional< T > checked_mul(T a, T b)
Definition int_utils.h:46
constexpr decltype(auto) wrap_strong_type(ParamT &&t)
Wraps a value into a caller-defined (strong) type.
const SIMD_8x32 & b