/src/botan/build/include/botan/internal/ct_utils.h
Line | Count | Source |
1 | | /* |
2 | | * Functions for constant time operations on data and testing of |
3 | | * constant time annotations using valgrind. |
4 | | * |
5 | | * For more information about constant time programming see |
6 | | * Wagner, Molnar, et al "The Program Counter Security Model" |
7 | | * |
8 | | * (C) 2010 Falko Strenzke |
9 | | * (C) 2015,2016,2018 Jack Lloyd |
10 | | * |
11 | | * Botan is released under the Simplified BSD License (see license.txt) |
12 | | */ |
13 | | |
14 | | #ifndef BOTAN_CT_UTILS_H_ |
15 | | #define BOTAN_CT_UTILS_H_ |
16 | | |
17 | | #include <botan/secmem.h> |
18 | | #include <botan/internal/bit_ops.h> |
19 | | #include <type_traits> |
20 | | #include <vector> |
21 | | |
22 | | #if defined(BOTAN_HAS_VALGRIND) |
23 | | #include <valgrind/memcheck.h> |
24 | | #endif |
25 | | |
26 | | namespace Botan { |
27 | | |
28 | | namespace CT { |
29 | | |
30 | | /** |
31 | | * Use valgrind to mark the contents of memory as being undefined. |
32 | | * Valgrind will accept operations which manipulate undefined values, |
33 | | * but will warn if an undefined value is used to decided a conditional |
34 | | * jump or a load/store address. So if we poison all of our inputs we |
35 | | * can confirm that the operations in question are truly const time |
36 | | * when compiled by whatever compiler is in use. |
37 | | * |
38 | | * Even better, the VALGRIND_MAKE_MEM_* macros work even when the |
39 | | * program is not run under valgrind (though with a few cycles of |
40 | | * overhead, which is unfortunate in final binaries as these |
41 | | * annotations tend to be used in fairly important loops). |
42 | | * |
43 | | * This approach was first used in ctgrind (https://github.com/agl/ctgrind) |
44 | | * but calling the valgrind mecheck API directly works just as well and |
45 | | * doesn't require a custom patched valgrind. |
46 | | */ |
47 | | template<typename T> |
48 | | inline void poison(const T* p, size_t n) |
49 | 55.9k | { |
50 | | #if defined(BOTAN_HAS_VALGRIND) |
51 | | VALGRIND_MAKE_MEM_UNDEFINED(p, n * sizeof(T)); |
52 | | #else |
53 | 55.9k | BOTAN_UNUSED(p); |
54 | 55.9k | BOTAN_UNUSED(n); |
55 | 55.9k | #endif |
56 | 55.9k | } void Botan::CT::poison<unsigned long>(unsigned long const*, unsigned long) Line | Count | Source | 49 | 51.2k | { | 50 | | #if defined(BOTAN_HAS_VALGRIND) | 51 | | VALGRIND_MAKE_MEM_UNDEFINED(p, n * sizeof(T)); | 52 | | #else | 53 | 51.2k | BOTAN_UNUSED(p); | 54 | 51.2k | BOTAN_UNUSED(n); | 55 | 51.2k | #endif | 56 | 51.2k | } |
void Botan::CT::poison<unsigned char>(unsigned char const*, unsigned long) Line | Count | Source | 49 | 4.67k | { | 50 | | #if defined(BOTAN_HAS_VALGRIND) | 51 | | VALGRIND_MAKE_MEM_UNDEFINED(p, n * sizeof(T)); | 52 | | #else | 53 | 4.67k | BOTAN_UNUSED(p); | 54 | 4.67k | BOTAN_UNUSED(n); | 55 | 4.67k | #endif | 56 | 4.67k | } |
Unexecuted instantiation: void Botan::CT::poison<unsigned short>(unsigned short const*, unsigned long) |
57 | | |
58 | | template<typename T> |
59 | | inline void unpoison(const T* p, size_t n) |
60 | 56.9k | { |
61 | | #if defined(BOTAN_HAS_VALGRIND) |
62 | | VALGRIND_MAKE_MEM_DEFINED(p, n * sizeof(T)); |
63 | | #else |
64 | 56.9k | BOTAN_UNUSED(p); |
65 | 56.9k | BOTAN_UNUSED(n); |
66 | 56.9k | #endif |
67 | 56.9k | } void Botan::CT::unpoison<unsigned long>(unsigned long const*, unsigned long) Line | Count | Source | 60 | 50.1k | { | 61 | | #if defined(BOTAN_HAS_VALGRIND) | 62 | | VALGRIND_MAKE_MEM_DEFINED(p, n * sizeof(T)); | 63 | | #else | 64 | 50.1k | BOTAN_UNUSED(p); | 65 | 50.1k | BOTAN_UNUSED(n); | 66 | 50.1k | #endif | 67 | 50.1k | } |
void Botan::CT::unpoison<unsigned char>(unsigned char const*, unsigned long) Line | Count | Source | 60 | 6.82k | { | 61 | | #if defined(BOTAN_HAS_VALGRIND) | 62 | | VALGRIND_MAKE_MEM_DEFINED(p, n * sizeof(T)); | 63 | | #else | 64 | 6.82k | BOTAN_UNUSED(p); | 65 | 6.82k | BOTAN_UNUSED(n); | 66 | 6.82k | #endif | 67 | 6.82k | } |
Unexecuted instantiation: void Botan::CT::unpoison<unsigned short>(unsigned short const*, unsigned long) Unexecuted instantiation: void Botan::CT::unpoison<unsigned int>(unsigned int const*, unsigned long) |
68 | | |
69 | | template<typename T> |
70 | | inline void unpoison(T& p) |
71 | 291M | { |
72 | | #if defined(BOTAN_HAS_VALGRIND) |
73 | | VALGRIND_MAKE_MEM_DEFINED(&p, sizeof(T)); |
74 | | #else |
75 | 291M | BOTAN_UNUSED(p); |
76 | 291M | #endif |
77 | 291M | } void Botan::CT::unpoison<unsigned long>(unsigned long&) Line | Count | Source | 71 | 182M | { | 72 | | #if defined(BOTAN_HAS_VALGRIND) | 73 | | VALGRIND_MAKE_MEM_DEFINED(&p, sizeof(T)); | 74 | | #else | 75 | 182M | BOTAN_UNUSED(p); | 76 | 182M | #endif | 77 | 182M | } |
void Botan::CT::unpoison<unsigned long const>(unsigned long const&) Line | Count | Source | 71 | 11.1M | { | 72 | | #if defined(BOTAN_HAS_VALGRIND) | 73 | | VALGRIND_MAKE_MEM_DEFINED(&p, sizeof(T)); | 74 | | #else | 75 | 11.1M | BOTAN_UNUSED(p); | 76 | 11.1M | #endif | 77 | 11.1M | } |
void Botan::CT::unpoison<unsigned int>(unsigned int&) Line | Count | Source | 71 | 676k | { | 72 | | #if defined(BOTAN_HAS_VALGRIND) | 73 | | VALGRIND_MAKE_MEM_DEFINED(&p, sizeof(T)); | 74 | | #else | 75 | 676k | BOTAN_UNUSED(p); | 76 | 676k | #endif | 77 | 676k | } |
void Botan::CT::unpoison<long>(long&) Line | Count | Source | 71 | 97.2M | { | 72 | | #if defined(BOTAN_HAS_VALGRIND) | 73 | | VALGRIND_MAKE_MEM_DEFINED(&p, sizeof(T)); | 74 | | #else | 75 | 97.2M | BOTAN_UNUSED(p); | 76 | 97.2M | #endif | 77 | 97.2M | } |
Unexecuted instantiation: void Botan::CT::unpoison<Botan::CT::Mask<unsigned char> >(Botan::CT::Mask<unsigned char>&) void Botan::CT::unpoison<unsigned char>(unsigned char&) Line | Count | Source | 71 | 543 | { | 72 | | #if defined(BOTAN_HAS_VALGRIND) | 73 | | VALGRIND_MAKE_MEM_DEFINED(&p, sizeof(T)); | 74 | | #else | 75 | 543 | BOTAN_UNUSED(p); | 76 | 543 | #endif | 77 | 543 | } |
void Botan::CT::unpoison<unsigned char const>(unsigned char const&) Line | Count | Source | 71 | 1.10k | { | 72 | | #if defined(BOTAN_HAS_VALGRIND) | 73 | | VALGRIND_MAKE_MEM_DEFINED(&p, sizeof(T)); | 74 | | #else | 75 | 1.10k | BOTAN_UNUSED(p); | 76 | 1.10k | #endif | 77 | 1.10k | } |
void Botan::CT::unpoison<unsigned short>(unsigned short&) Line | Count | Source | 71 | 554 | { | 72 | | #if defined(BOTAN_HAS_VALGRIND) | 73 | | VALGRIND_MAKE_MEM_DEFINED(&p, sizeof(T)); | 74 | | #else | 75 | 554 | BOTAN_UNUSED(p); | 76 | 554 | #endif | 77 | 554 | } |
void Botan::CT::unpoison<Botan::CT::Mask<unsigned short> const>(Botan::CT::Mask<unsigned short> const&) Line | Count | Source | 71 | 277 | { | 72 | | #if defined(BOTAN_HAS_VALGRIND) | 73 | | VALGRIND_MAKE_MEM_DEFINED(&p, sizeof(T)); | 74 | | #else | 75 | 277 | BOTAN_UNUSED(p); | 76 | 277 | #endif | 77 | 277 | } |
|
78 | | |
79 | | /** |
80 | | * A Mask type used for constant-time operations. A Mask<T> always has value |
81 | | * either 0 (all bits cleared) or ~0 (all bits set). All operations in a Mask<T> |
82 | | * are intended to compile to code which does not contain conditional jumps. |
83 | | * This must be verified with tooling (eg binary disassembly or using valgrind) |
84 | | * since you never know what a compiler might do. |
85 | | */ |
86 | | template<typename T> |
87 | | class Mask |
88 | | { |
89 | | public: |
90 | | static_assert(std::is_unsigned<T>::value, "CT::Mask only defined for unsigned integer types"); |
91 | | |
92 | | Mask(const Mask<T>& other) = default; |
93 | | Mask<T>& operator=(const Mask<T>& other) = default; |
94 | | |
95 | | /** |
96 | | * Derive a Mask from a Mask of a larger type |
97 | | */ |
98 | | template<typename U> |
99 | | Mask(Mask<U> o) : m_mask(static_cast<T>(o.value())) |
100 | 20.6k | { |
101 | 20.6k | static_assert(sizeof(U) > sizeof(T), "sizes ok"); |
102 | 20.6k | } Botan::CT::Mask<unsigned char>::Mask<unsigned long>(Botan::CT::Mask<unsigned long>) Line | Count | Source | 100 | 20.6k | { | 101 | 20.6k | static_assert(sizeof(U) > sizeof(T), "sizes ok"); | 102 | 20.6k | } |
Unexecuted instantiation: Botan::CT::Mask<unsigned short>::Mask<unsigned int>(Botan::CT::Mask<unsigned int>) |
103 | | |
104 | | /** |
105 | | * Return a Mask<T> with all bits set |
106 | | */ |
107 | | static Mask<T> set() |
108 | 52.6k | { |
109 | 52.6k | return Mask<T>(static_cast<T>(~0)); |
110 | 52.6k | } Botan::CT::Mask<unsigned long>::set() Line | Count | Source | 108 | 50.1k | { | 109 | 50.1k | return Mask<T>(static_cast<T>(~0)); | 110 | 50.1k | } |
Botan::CT::Mask<unsigned char>::set() Line | Count | Source | 108 | 2.50k | { | 109 | 2.50k | return Mask<T>(static_cast<T>(~0)); | 110 | 2.50k | } |
|
111 | | |
112 | | /** |
113 | | * Return a Mask<T> with all bits cleared |
114 | | */ |
115 | | static Mask<T> cleared() |
116 | 3.40M | { |
117 | 3.40M | return Mask<T>(0); |
118 | 3.40M | } Botan::CT::Mask<unsigned long>::cleared() Line | Count | Source | 116 | 3.40M | { | 117 | 3.40M | return Mask<T>(0); | 118 | 3.40M | } |
Botan::CT::Mask<unsigned char>::cleared() Line | Count | Source | 116 | 3.27k | { | 117 | 3.27k | return Mask<T>(0); | 118 | 3.27k | } |
|
119 | | |
120 | | /** |
121 | | * Return a Mask<T> which is set if v is != 0 |
122 | | */ |
123 | | static Mask<T> expand(T v) |
124 | 1.53G | { |
125 | 1.53G | return ~Mask<T>::is_zero(v); |
126 | 1.53G | } Botan::CT::Mask<unsigned long>::expand(unsigned long) Line | Count | Source | 124 | 1.51G | { | 125 | 1.51G | return ~Mask<T>::is_zero(v); | 126 | 1.51G | } |
Botan::CT::Mask<unsigned char>::expand(unsigned char) Line | Count | Source | 124 | 21.8M | { | 125 | 21.8M | return ~Mask<T>::is_zero(v); | 126 | 21.8M | } |
Botan::CT::Mask<unsigned short>::expand(unsigned short) Line | Count | Source | 124 | 554 | { | 125 | 554 | return ~Mask<T>::is_zero(v); | 126 | 554 | } |
|
127 | | |
128 | | /** |
129 | | * Return a Mask<T> which is set if m is set |
130 | | */ |
131 | | template<typename U> |
132 | | static Mask<T> expand(Mask<U> m) |
133 | 209 | { |
134 | 209 | static_assert(sizeof(U) < sizeof(T), "sizes ok"); |
135 | 209 | return ~Mask<T>::is_zero(m.value()); |
136 | 209 | } |
137 | | |
138 | | /** |
139 | | * Return a Mask<T> which is set if v is == 0 or cleared otherwise |
140 | | */ |
141 | | static Mask<T> is_zero(T x) |
142 | 4.90G | { |
143 | 4.90G | return Mask<T>(ct_is_zero<T>(x)); |
144 | 4.90G | } Botan::CT::Mask<unsigned long>::is_zero(unsigned long) Line | Count | Source | 142 | 4.88G | { | 143 | 4.88G | return Mask<T>(ct_is_zero<T>(x)); | 144 | 4.88G | } |
Botan::CT::Mask<unsigned char>::is_zero(unsigned char) Line | Count | Source | 142 | 23.4M | { | 143 | 23.4M | return Mask<T>(ct_is_zero<T>(x)); | 144 | 23.4M | } |
Unexecuted instantiation: Botan::CT::Mask<unsigned int>::is_zero(unsigned int) Botan::CT::Mask<unsigned short>::is_zero(unsigned short) Line | Count | Source | 142 | 77.1k | { | 143 | 77.1k | return Mask<T>(ct_is_zero<T>(x)); | 144 | 77.1k | } |
|
145 | | |
146 | | /** |
147 | | * Return a Mask<T> which is set if x == y |
148 | | */ |
149 | | static Mask<T> is_equal(T x, T y) |
150 | 3.31G | { |
151 | 3.31G | return Mask<T>::is_zero(static_cast<T>(x ^ y)); |
152 | 3.31G | } Botan::CT::Mask<unsigned long>::is_equal(unsigned long, unsigned long) Line | Count | Source | 150 | 3.31G | { | 151 | 3.31G | return Mask<T>::is_zero(static_cast<T>(x ^ y)); | 152 | 3.31G | } |
Botan::CT::Mask<unsigned char>::is_equal(unsigned char, unsigned char) Line | Count | Source | 150 | 395k | { | 151 | 395k | return Mask<T>::is_zero(static_cast<T>(x ^ y)); | 152 | 395k | } |
Botan::CT::Mask<unsigned short>::is_equal(unsigned short, unsigned short) Line | Count | Source | 150 | 76.5k | { | 151 | 76.5k | return Mask<T>::is_zero(static_cast<T>(x ^ y)); | 152 | 76.5k | } |
|
153 | | |
154 | | /** |
155 | | * Return a Mask<T> which is set if x < y |
156 | | */ |
157 | | static Mask<T> is_lt(T x, T y) |
158 | 1.50G | { |
159 | 1.50G | return Mask<T>(expand_top_bit<T>(x^((x^y) | ((x-y)^x)))); |
160 | 1.50G | } Botan::CT::Mask<unsigned long>::is_lt(unsigned long, unsigned long) Line | Count | Source | 158 | 1.50G | { | 159 | 1.50G | return Mask<T>(expand_top_bit<T>(x^((x^y) | ((x-y)^x)))); | 160 | 1.50G | } |
Botan::CT::Mask<unsigned int>::is_lt(unsigned int, unsigned int) Line | Count | Source | 158 | 676k | { | 159 | 676k | return Mask<T>(expand_top_bit<T>(x^((x^y) | ((x-y)^x)))); | 160 | 676k | } |
Botan::CT::Mask<unsigned short>::is_lt(unsigned short, unsigned short) Line | Count | Source | 158 | 77.0k | { | 159 | 77.0k | return Mask<T>(expand_top_bit<T>(x^((x^y) | ((x-y)^x)))); | 160 | 77.0k | } |
Botan::CT::Mask<unsigned char>::is_lt(unsigned char, unsigned char) Line | Count | Source | 158 | 152 | { | 159 | 152 | return Mask<T>(expand_top_bit<T>(x^((x^y) | ((x-y)^x)))); | 160 | 152 | } |
|
161 | | |
162 | | /** |
163 | | * Return a Mask<T> which is set if x > y |
164 | | */ |
165 | | static Mask<T> is_gt(T x, T y) |
166 | 2.67M | { |
167 | 2.67M | return Mask<T>::is_lt(y, x); |
168 | 2.67M | } Botan::CT::Mask<unsigned long>::is_gt(unsigned long, unsigned long) Line | Count | Source | 166 | 2.59M | { | 167 | 2.59M | return Mask<T>::is_lt(y, x); | 168 | 2.59M | } |
Botan::CT::Mask<unsigned short>::is_gt(unsigned short, unsigned short) Line | Count | Source | 166 | 76.5k | { | 167 | 76.5k | return Mask<T>::is_lt(y, x); | 168 | 76.5k | } |
Botan::CT::Mask<unsigned char>::is_gt(unsigned char, unsigned char) Line | Count | Source | 166 | 152 | { | 167 | 152 | return Mask<T>::is_lt(y, x); | 168 | 152 | } |
|
169 | | |
170 | | /** |
171 | | * Return a Mask<T> which is set if x <= y |
172 | | */ |
173 | | static Mask<T> is_lte(T x, T y) |
174 | 2.66M | { |
175 | 2.66M | return ~Mask<T>::is_gt(x, y); |
176 | 2.66M | } Botan::CT::Mask<unsigned long>::is_lte(unsigned long, unsigned long) Line | Count | Source | 174 | 2.58M | { | 175 | 2.58M | return ~Mask<T>::is_gt(x, y); | 176 | 2.58M | } |
Botan::CT::Mask<unsigned short>::is_lte(unsigned short, unsigned short) Line | Count | Source | 174 | 76.5k | { | 175 | 76.5k | return ~Mask<T>::is_gt(x, y); | 176 | 76.5k | } |
|
177 | | |
178 | | /** |
179 | | * Return a Mask<T> which is set if x >= y |
180 | | */ |
181 | | static Mask<T> is_gte(T x, T y) |
182 | 703k | { |
183 | 703k | return ~Mask<T>::is_lt(x, y); |
184 | 703k | } Botan::CT::Mask<unsigned int>::is_gte(unsigned int, unsigned int) Line | Count | Source | 182 | 676k | { | 183 | 676k | return ~Mask<T>::is_lt(x, y); | 184 | 676k | } |
Botan::CT::Mask<unsigned long>::is_gte(unsigned long, unsigned long) Line | Count | Source | 182 | 27.1k | { | 183 | 27.1k | return ~Mask<T>::is_lt(x, y); | 184 | 27.1k | } |
|
185 | | |
186 | | /** |
187 | | * AND-combine two masks |
188 | | */ |
189 | | Mask<T>& operator&=(Mask<T> o) |
190 | 1.72M | { |
191 | 1.72M | m_mask &= o.value(); |
192 | 1.72M | return (*this); |
193 | 1.72M | } Botan::CT::Mask<unsigned long>::operator&=(Botan::CT::Mask<unsigned long>) Line | Count | Source | 190 | 929k | { | 191 | 929k | m_mask &= o.value(); | 192 | 929k | return (*this); | 193 | 929k | } |
Botan::CT::Mask<unsigned char>::operator&=(Botan::CT::Mask<unsigned char>) Line | Count | Source | 190 | 797k | { | 191 | 797k | m_mask &= o.value(); | 192 | 797k | return (*this); | 193 | 797k | } |
|
194 | | |
195 | | /** |
196 | | * XOR-combine two masks |
197 | | */ |
198 | | Mask<T>& operator^=(Mask<T> o) |
199 | | { |
200 | | m_mask ^= o.value(); |
201 | | return (*this); |
202 | | } |
203 | | |
204 | | /** |
205 | | * OR-combine two masks |
206 | | */ |
207 | | Mask<T>& operator|=(Mask<T> o) |
208 | 57.1M | { |
209 | 57.1M | m_mask |= o.value(); |
210 | 57.1M | return (*this); |
211 | 57.1M | } Botan::CT::Mask<unsigned long>::operator|=(Botan::CT::Mask<unsigned long>) Line | Count | Source | 208 | 56.2M | { | 209 | 56.2M | m_mask |= o.value(); | 210 | 56.2M | return (*this); | 211 | 56.2M | } |
Botan::CT::Mask<unsigned char>::operator|=(Botan::CT::Mask<unsigned char>) Line | Count | Source | 208 | 805k | { | 209 | 805k | m_mask |= o.value(); | 210 | 805k | return (*this); | 211 | 805k | } |
Botan::CT::Mask<unsigned short>::operator|=(Botan::CT::Mask<unsigned short>) Line | Count | Source | 208 | 76.3k | { | 209 | 76.3k | m_mask |= o.value(); | 210 | 76.3k | return (*this); | 211 | 76.3k | } |
|
212 | | |
213 | | /** |
214 | | * AND-combine two masks |
215 | | */ |
216 | | friend Mask<T> operator&(Mask<T> x, Mask<T> y) |
217 | 155M | { |
218 | 155M | return Mask<T>(x.value() & y.value()); |
219 | 155M | } Botan::CT::operator&(Botan::CT::Mask<unsigned long>, Botan::CT::Mask<unsigned long>) Line | Count | Source | 217 | 154M | { | 218 | 154M | return Mask<T>(x.value() & y.value()); | 219 | 154M | } |
Botan::CT::operator&(Botan::CT::Mask<unsigned char>, Botan::CT::Mask<unsigned char>) Line | Count | Source | 217 | 597k | { | 218 | 597k | return Mask<T>(x.value() & y.value()); | 219 | 597k | } |
Botan::CT::operator&(Botan::CT::Mask<unsigned short>, Botan::CT::Mask<unsigned short>) Line | Count | Source | 217 | 76.8k | { | 218 | 76.8k | return Mask<T>(x.value() & y.value()); | 219 | 76.8k | } |
|
220 | | |
221 | | /** |
222 | | * XOR-combine two masks |
223 | | */ |
224 | | friend Mask<T> operator^(Mask<T> x, Mask<T> y) |
225 | 4.16M | { |
226 | 4.16M | return Mask<T>(x.value() ^ y.value()); |
227 | 4.16M | } |
228 | | |
229 | | /** |
230 | | * OR-combine two masks |
231 | | */ |
232 | | friend Mask<T> operator|(Mask<T> x, Mask<T> y) |
233 | 154M | { |
234 | 154M | return Mask<T>(x.value() | y.value()); |
235 | 154M | } Botan::CT::operator|(Botan::CT::Mask<unsigned long>, Botan::CT::Mask<unsigned long>) Line | Count | Source | 233 | 154M | { | 234 | 154M | return Mask<T>(x.value() | y.value()); | 235 | 154M | } |
Botan::CT::operator|(Botan::CT::Mask<unsigned char>, Botan::CT::Mask<unsigned char>) Line | Count | Source | 233 | 202k | { | 234 | 202k | return Mask<T>(x.value() | y.value()); | 235 | 202k | } |
|
236 | | |
237 | | /** |
238 | | * Negate this mask |
239 | | */ |
240 | | Mask<T> operator~() const |
241 | 1.54G | { |
242 | 1.54G | return Mask<T>(~value()); |
243 | 1.54G | } Botan::CT::Mask<unsigned long>::operator~() const Line | Count | Source | 241 | 1.52G | { | 242 | 1.52G | return Mask<T>(~value()); | 243 | 1.52G | } |
Botan::CT::Mask<unsigned char>::operator~() const Line | Count | Source | 241 | 22.3M | { | 242 | 22.3M | return Mask<T>(~value()); | 243 | 22.3M | } |
Botan::CT::Mask<unsigned int>::operator~() const Line | Count | Source | 241 | 676k | { | 242 | 676k | return Mask<T>(~value()); | 243 | 676k | } |
Botan::CT::Mask<unsigned short>::operator~() const Line | Count | Source | 241 | 153k | { | 242 | 153k | return Mask<T>(~value()); | 243 | 153k | } |
|
244 | | |
245 | | /** |
246 | | * Return x if the mask is set, or otherwise zero |
247 | | */ |
248 | | T if_set_return(T x) const |
249 | 9.70G | { |
250 | 9.70G | return m_mask & x; |
251 | 9.70G | } Botan::CT::Mask<unsigned long>::if_set_return(unsigned long) const Line | Count | Source | 249 | 9.70G | { | 250 | 9.70G | return m_mask & x; | 251 | 9.70G | } |
Botan::CT::Mask<unsigned char>::if_set_return(unsigned char) const Line | Count | Source | 249 | 797k | { | 250 | 797k | return m_mask & x; | 251 | 797k | } |
Botan::CT::Mask<unsigned short>::if_set_return(unsigned short) const Line | Count | Source | 249 | 554 | { | 250 | 554 | return m_mask & x; | 251 | 554 | } |
|
252 | | |
253 | | /** |
254 | | * Return x if the mask is cleared, or otherwise zero |
255 | | */ |
256 | | T if_not_set_return(T x) const |
257 | 57.8M | { |
258 | 57.8M | return ~m_mask & x; |
259 | 57.8M | } Botan::CT::Mask<unsigned long>::if_not_set_return(unsigned long) const Line | Count | Source | 257 | 56.3M | { | 258 | 56.3M | return ~m_mask & x; | 259 | 56.3M | } |
Botan::CT::Mask<unsigned char>::if_not_set_return(unsigned char) const Line | Count | Source | 257 | 1.43M | { | 258 | 1.43M | return ~m_mask & x; | 259 | 1.43M | } |
Botan::CT::Mask<unsigned short>::if_not_set_return(unsigned short) const Line | Count | Source | 257 | 502 | { | 258 | 502 | return ~m_mask & x; | 259 | 502 | } |
|
260 | | |
261 | | /** |
262 | | * If this mask is set, return x, otherwise return y |
263 | | */ |
264 | | T select(T x, T y) const |
265 | 26.1G | { |
266 | | // (x & value()) | (y & ~value()) |
267 | 26.1G | return static_cast<T>(y ^ (value() & (x ^ y))); |
268 | 26.1G | } Botan::CT::Mask<unsigned long>::select(unsigned long, unsigned long) const Line | Count | Source | 265 | 26.1G | { | 266 | | // (x & value()) | (y & ~value()) | 267 | 26.1G | return static_cast<T>(y ^ (value() & (x ^ y))); | 268 | 26.1G | } |
Botan::CT::Mask<unsigned char>::select(unsigned char, unsigned char) const Line | Count | Source | 265 | 21.8M | { | 266 | | // (x & value()) | (y & ~value()) | 267 | 21.8M | return static_cast<T>(y ^ (value() & (x ^ y))); | 268 | 21.8M | } |
Botan::CT::Mask<unsigned int>::select(unsigned int, unsigned int) const Line | Count | Source | 265 | 676k | { | 266 | | // (x & value()) | (y & ~value()) | 267 | 676k | return static_cast<T>(y ^ (value() & (x ^ y))); | 268 | 676k | } |
Unexecuted instantiation: Botan::CT::Mask<unsigned short>::select(unsigned short, unsigned short) const |
269 | | |
270 | | T select_and_unpoison(T x, T y) const |
271 | 665 | { |
272 | 665 | T r = this->select(x, y); |
273 | 665 | CT::unpoison(r); |
274 | 665 | return r; |
275 | 665 | } Botan::CT::Mask<unsigned long>::select_and_unpoison(unsigned long, unsigned long) const Line | Count | Source | 271 | 513 | { | 272 | 513 | T r = this->select(x, y); | 273 | 513 | CT::unpoison(r); | 274 | 513 | return r; | 275 | 513 | } |
Botan::CT::Mask<unsigned char>::select_and_unpoison(unsigned char, unsigned char) const Line | Count | Source | 271 | 152 | { | 272 | 152 | T r = this->select(x, y); | 273 | 152 | CT::unpoison(r); | 274 | 152 | return r; | 275 | 152 | } |
|
276 | | |
277 | | /** |
278 | | * If this mask is set, return x, otherwise return y |
279 | | */ |
280 | | Mask<T> select_mask(Mask<T> x, Mask<T> y) const |
281 | 1.01G | { |
282 | 1.01G | return Mask<T>(select(x.value(), y.value())); |
283 | 1.01G | } |
284 | | |
285 | | /** |
286 | | * Conditionally set output to x or y, depending on if mask is set or |
287 | | * cleared (resp) |
288 | | */ |
289 | | void select_n(T output[], const T x[], const T y[], size_t len) const |
290 | 580M | { |
291 | 5.99G | for(size_t i = 0; i != len; ++i) |
292 | 5.41G | output[i] = this->select(x[i], y[i]); |
293 | 580M | } Botan::CT::Mask<unsigned long>::select_n(unsigned long*, unsigned long const*, unsigned long const*, unsigned long) const Line | Count | Source | 290 | 580M | { | 291 | 5.99G | for(size_t i = 0; i != len; ++i) | 292 | 5.41G | output[i] = this->select(x[i], y[i]); | 293 | 580M | } |
Unexecuted instantiation: Botan::CT::Mask<unsigned char>::select_n(unsigned char*, unsigned char const*, unsigned char const*, unsigned long) const |
294 | | |
295 | | /** |
296 | | * If this mask is set, zero out buf, otherwise do nothing |
297 | | */ |
298 | | void if_set_zero_out(T buf[], size_t elems) |
299 | 52.8k | { |
300 | 1.41M | for(size_t i = 0; i != elems; ++i) |
301 | 1.36M | { |
302 | 1.36M | buf[i] = this->if_not_set_return(buf[i]); |
303 | 1.36M | } |
304 | 52.8k | } Botan::CT::Mask<unsigned long>::if_set_zero_out(unsigned long*, unsigned long) Line | Count | Source | 299 | 50.1k | { | 300 | 389k | for(size_t i = 0; i != elems; ++i) | 301 | 339k | { | 302 | 339k | buf[i] = this->if_not_set_return(buf[i]); | 303 | 339k | } | 304 | 50.1k | } |
Botan::CT::Mask<unsigned char>::if_set_zero_out(unsigned char*, unsigned long) Line | Count | Source | 299 | 2.68k | { | 300 | 1.02M | for(size_t i = 0; i != elems; ++i) | 301 | 1.02M | { | 302 | 1.02M | buf[i] = this->if_not_set_return(buf[i]); | 303 | 1.02M | } | 304 | 2.68k | } |
|
305 | | |
306 | | /** |
307 | | * Return the value of the mask, unpoisoned |
308 | | */ |
309 | | T unpoisoned_value() const |
310 | 13.3M | { |
311 | 13.3M | T r = value(); |
312 | 13.3M | CT::unpoison(r); |
313 | 13.3M | return r; |
314 | 13.3M | } Botan::CT::Mask<unsigned long>::unpoisoned_value() const Line | Count | Source | 310 | 12.6M | { | 311 | 12.6M | T r = value(); | 312 | 12.6M | CT::unpoison(r); | 313 | 12.6M | return r; | 314 | 12.6M | } |
Botan::CT::Mask<unsigned int>::unpoisoned_value() const Line | Count | Source | 310 | 676k | { | 311 | 676k | T r = value(); | 312 | 676k | CT::unpoison(r); | 313 | 676k | return r; | 314 | 676k | } |
Botan::CT::Mask<unsigned char>::unpoisoned_value() const Line | Count | Source | 310 | 391 | { | 311 | 391 | T r = value(); | 312 | 391 | CT::unpoison(r); | 313 | 391 | return r; | 314 | 391 | } |
Botan::CT::Mask<unsigned short>::unpoisoned_value() const Line | Count | Source | 310 | 277 | { | 311 | 277 | T r = value(); | 312 | 277 | CT::unpoison(r); | 313 | 277 | return r; | 314 | 277 | } |
|
315 | | |
316 | | /** |
317 | | * Return true iff this mask is set |
318 | | */ |
319 | | bool is_set() const |
320 | 13.2M | { |
321 | 13.2M | return unpoisoned_value() != 0; |
322 | 13.2M | } Botan::CT::Mask<unsigned long>::is_set() const Line | Count | Source | 320 | 12.6M | { | 321 | 12.6M | return unpoisoned_value() != 0; | 322 | 12.6M | } |
Botan::CT::Mask<unsigned int>::is_set() const Line | Count | Source | 320 | 676k | { | 321 | 676k | return unpoisoned_value() != 0; | 322 | 676k | } |
Unexecuted instantiation: Botan::CT::Mask<unsigned char>::is_set() const Botan::CT::Mask<unsigned short>::is_set() const Line | Count | Source | 320 | 277 | { | 321 | 277 | return unpoisoned_value() != 0; | 322 | 277 | } |
|
323 | | |
324 | | /** |
325 | | * Return the underlying value of the mask |
326 | | */ |
327 | | T value() const |
328 | 30.5G | { |
329 | 30.5G | return m_mask; |
330 | 30.5G | } Botan::CT::Mask<unsigned long>::value() const Line | Count | Source | 328 | 30.5G | { | 329 | 30.5G | return m_mask; | 330 | 30.5G | } |
Botan::CT::Mask<unsigned char>::value() const Line | Count | Source | 328 | 47.4M | { | 329 | 47.4M | return m_mask; | 330 | 47.4M | } |
Botan::CT::Mask<unsigned int>::value() const Line | Count | Source | 328 | 2.02M | { | 329 | 2.02M | return m_mask; | 330 | 2.02M | } |
Botan::CT::Mask<unsigned short>::value() const Line | Count | Source | 328 | 383k | { | 329 | 383k | return m_mask; | 330 | 383k | } |
|
331 | | |
332 | | private: |
333 | 9.29G | Mask(T m) : m_mask(m) {} Botan::CT::Mask<unsigned long>::Mask(unsigned long) Line | Count | Source | 333 | 9.24G | Mask(T m) : m_mask(m) {} |
Botan::CT::Mask<unsigned char>::Mask(unsigned char) Line | Count | Source | 333 | 46.6M | Mask(T m) : m_mask(m) {} |
Botan::CT::Mask<unsigned int>::Mask(unsigned int) Line | Count | Source | 333 | 1.35M | Mask(T m) : m_mask(m) {} |
Botan::CT::Mask<unsigned short>::Mask(unsigned short) Line | Count | Source | 333 | 384k | Mask(T m) : m_mask(m) {} |
|
334 | | |
335 | | T m_mask; |
336 | | }; |
337 | | |
338 | | template<typename T> |
339 | | inline Mask<T> conditional_copy_mem(T cnd, |
340 | | T* to, |
341 | | const T* from0, |
342 | | const T* from1, |
343 | | size_t elems) |
344 | 124M | { |
345 | 124M | const auto mask = CT::Mask<T>::expand(cnd); |
346 | 124M | mask.select_n(to, from0, from1, elems); |
347 | 124M | return mask; |
348 | 124M | } |
349 | | |
350 | | template<typename T> |
351 | | inline void conditional_swap(bool cnd, T& x, T& y) |
352 | 34.3M | { |
353 | 34.3M | const auto swap = CT::Mask<T>::expand(cnd); |
354 | 34.3M | |
355 | 34.3M | T t0 = swap.select(y, x); |
356 | 34.3M | T t1 = swap.select(x, y); |
357 | 34.3M | x = t0; |
358 | 34.3M | y = t1; |
359 | 34.3M | } |
360 | | |
361 | | template<typename T> |
362 | | inline void conditional_swap_ptr(bool cnd, T& x, T& y) |
363 | 17.1M | { |
364 | 17.1M | uintptr_t xp = reinterpret_cast<uintptr_t>(x); |
365 | 17.1M | uintptr_t yp = reinterpret_cast<uintptr_t>(y); |
366 | 17.1M | |
367 | 17.1M | conditional_swap<uintptr_t>(cnd, xp, yp); |
368 | 17.1M | |
369 | 17.1M | x = reinterpret_cast<T>(xp); |
370 | 17.1M | y = reinterpret_cast<T>(yp); |
371 | 17.1M | } |
372 | | |
373 | | /** |
374 | | * If bad_mask is unset, return in[delim_idx:input_length] copied to |
375 | | * new buffer. If bad_mask is set, return an all zero vector of |
376 | | * unspecified length. |
377 | | */ |
378 | | secure_vector<uint8_t> copy_output(CT::Mask<uint8_t> bad_input, |
379 | | const uint8_t input[], |
380 | | size_t input_length, |
381 | | size_t delim_idx); |
382 | | |
383 | | secure_vector<uint8_t> strip_leading_zeros(const uint8_t in[], size_t length); |
384 | | |
385 | | inline secure_vector<uint8_t> strip_leading_zeros(const secure_vector<uint8_t>& in) |
386 | 2.29k | { |
387 | 2.29k | return strip_leading_zeros(in.data(), in.size()); |
388 | 2.29k | } |
389 | | |
390 | | } |
391 | | |
392 | | } |
393 | | |
394 | | #endif |