/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 | 209k | { |
50 | | #if defined(BOTAN_HAS_VALGRIND) |
51 | | VALGRIND_MAKE_MEM_UNDEFINED(p, n * sizeof(T)); |
52 | | #else |
53 | 209k | BOTAN_UNUSED(p); |
54 | 209k | BOTAN_UNUSED(n); |
55 | 209k | #endif |
56 | 209k | } void Botan::CT::poison<unsigned long>(unsigned long const*, unsigned long) Line | Count | Source | 49 | 207k | { | 50 | | #if defined(BOTAN_HAS_VALGRIND) | 51 | | VALGRIND_MAKE_MEM_UNDEFINED(p, n * sizeof(T)); | 52 | | #else | 53 | 207k | BOTAN_UNUSED(p); | 54 | 207k | BOTAN_UNUSED(n); | 55 | 207k | #endif | 56 | 207k | } |
void Botan::CT::poison<unsigned char>(unsigned char const*, unsigned long) Line | Count | Source | 49 | 2.15k | { | 50 | | #if defined(BOTAN_HAS_VALGRIND) | 51 | | VALGRIND_MAKE_MEM_UNDEFINED(p, n * sizeof(T)); | 52 | | #else | 53 | 2.15k | BOTAN_UNUSED(p); | 54 | 2.15k | BOTAN_UNUSED(n); | 55 | 2.15k | #endif | 56 | 2.15k | } |
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 | 211k | { |
61 | | #if defined(BOTAN_HAS_VALGRIND) |
62 | | VALGRIND_MAKE_MEM_DEFINED(p, n * sizeof(T)); |
63 | | #else |
64 | 211k | BOTAN_UNUSED(p); |
65 | 211k | BOTAN_UNUSED(n); |
66 | 211k | #endif |
67 | 211k | } void Botan::CT::unpoison<unsigned long>(unsigned long const*, unsigned long) Line | Count | Source | 60 | 207k | { | 61 | | #if defined(BOTAN_HAS_VALGRIND) | 62 | | VALGRIND_MAKE_MEM_DEFINED(p, n * sizeof(T)); | 63 | | #else | 64 | 207k | BOTAN_UNUSED(p); | 65 | 207k | BOTAN_UNUSED(n); | 66 | 207k | #endif | 67 | 207k | } |
void Botan::CT::unpoison<unsigned char>(unsigned char const*, unsigned long) Line | Count | Source | 60 | 4.61k | { | 61 | | #if defined(BOTAN_HAS_VALGRIND) | 62 | | VALGRIND_MAKE_MEM_DEFINED(p, n * sizeof(T)); | 63 | | #else | 64 | 4.61k | BOTAN_UNUSED(p); | 65 | 4.61k | BOTAN_UNUSED(n); | 66 | 4.61k | #endif | 67 | 4.61k | } |
Unexecuted instantiation: void Botan::CT::unpoison<unsigned short>(unsigned short const*, unsigned long) |
68 | | |
69 | | template<typename T> |
70 | | inline void unpoison(T& p) |
71 | 261M | { |
72 | | #if defined(BOTAN_HAS_VALGRIND) |
73 | | VALGRIND_MAKE_MEM_DEFINED(&p, sizeof(T)); |
74 | | #else |
75 | 261M | BOTAN_UNUSED(p); |
76 | 261M | #endif |
77 | 261M | } void Botan::CT::unpoison<unsigned long>(unsigned long&) Line | Count | Source | 71 | 148M | { | 72 | | #if defined(BOTAN_HAS_VALGRIND) | 73 | | VALGRIND_MAKE_MEM_DEFINED(&p, sizeof(T)); | 74 | | #else | 75 | 148M | BOTAN_UNUSED(p); | 76 | 148M | #endif | 77 | 148M | } |
void Botan::CT::unpoison<unsigned long const>(unsigned long const&) Line | Count | Source | 71 | 10.7M | { | 72 | | #if defined(BOTAN_HAS_VALGRIND) | 73 | | VALGRIND_MAKE_MEM_DEFINED(&p, sizeof(T)); | 74 | | #else | 75 | 10.7M | BOTAN_UNUSED(p); | 76 | 10.7M | #endif | 77 | 10.7M | } |
void Botan::CT::unpoison<unsigned int>(unsigned int&) Line | Count | Source | 71 | 674k | { | 72 | | #if defined(BOTAN_HAS_VALGRIND) | 73 | | VALGRIND_MAKE_MEM_DEFINED(&p, sizeof(T)); | 74 | | #else | 75 | 674k | BOTAN_UNUSED(p); | 76 | 674k | #endif | 77 | 674k | } |
void Botan::CT::unpoison<long>(long&) Line | Count | Source | 71 | 100M | { | 72 | | #if defined(BOTAN_HAS_VALGRIND) | 73 | | VALGRIND_MAKE_MEM_DEFINED(&p, sizeof(T)); | 74 | | #else | 75 | 100M | BOTAN_UNUSED(p); | 76 | 100M | #endif | 77 | 100M | } |
void Botan::CT::unpoison<unsigned char>(unsigned char&) Line | Count | Source | 71 | 510 | { | 72 | | #if defined(BOTAN_HAS_VALGRIND) | 73 | | VALGRIND_MAKE_MEM_DEFINED(&p, sizeof(T)); | 74 | | #else | 75 | 510 | BOTAN_UNUSED(p); | 76 | 510 | #endif | 77 | 510 | } |
Unexecuted instantiation: void Botan::CT::unpoison<Botan::CT::Mask<unsigned char> >(Botan::CT::Mask<unsigned char>&) void Botan::CT::unpoison<unsigned short>(unsigned short&) Line | Count | Source | 71 | 590 | { | 72 | | #if defined(BOTAN_HAS_VALGRIND) | 73 | | VALGRIND_MAKE_MEM_DEFINED(&p, sizeof(T)); | 74 | | #else | 75 | 590 | BOTAN_UNUSED(p); | 76 | 590 | #endif | 77 | 590 | } |
void Botan::CT::unpoison<Botan::CT::Mask<unsigned short> const>(Botan::CT::Mask<unsigned short> const&) Line | Count | Source | 71 | 295 | { | 72 | | #if defined(BOTAN_HAS_VALGRIND) | 73 | | VALGRIND_MAKE_MEM_DEFINED(&p, sizeof(T)); | 74 | | #else | 75 | 295 | BOTAN_UNUSED(p); | 76 | 295 | #endif | 77 | 295 | } |
|
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 | 6.45k | { |
101 | 6.45k | static_assert(sizeof(U) > sizeof(T), "sizes ok"); |
102 | 6.45k | } Unexecuted instantiation: Botan::CT::Mask<unsigned short>::Mask<unsigned int>(Botan::CT::Mask<unsigned int>) Botan::CT::Mask<unsigned char>::Mask<unsigned long>(Botan::CT::Mask<unsigned long>) Line | Count | Source | 100 | 6.45k | { | 101 | 6.45k | static_assert(sizeof(U) > sizeof(T), "sizes ok"); | 102 | 6.45k | } |
|
103 | | |
104 | | /** |
105 | | * Return a Mask<T> with all bits set |
106 | | */ |
107 | | static Mask<T> set() |
108 | 1.85k | { |
109 | 1.85k | return Mask<T>(static_cast<T>(~0)); |
110 | 1.85k | } |
111 | | |
112 | | /** |
113 | | * Return a Mask<T> with all bits cleared |
114 | | */ |
115 | | static Mask<T> cleared() |
116 | 2.59k | { |
117 | 2.59k | return Mask<T>(0); |
118 | 2.59k | } |
119 | | |
120 | | /** |
121 | | * Return a Mask<T> which is set if v is != 0 |
122 | | */ |
123 | | static Mask<T> expand(T v) |
124 | 1.16G | { |
125 | 1.16G | return ~Mask<T>::is_zero(v); |
126 | 1.16G | } Botan::CT::Mask<unsigned long>::expand(unsigned long) Line | Count | Source | 124 | 1.15G | { | 125 | 1.15G | return ~Mask<T>::is_zero(v); | 126 | 1.15G | } |
Botan::CT::Mask<unsigned char>::expand(unsigned char) Line | Count | Source | 124 | 17.3M | { | 125 | 17.3M | return ~Mask<T>::is_zero(v); | 126 | 17.3M | } |
Botan::CT::Mask<unsigned short>::expand(unsigned short) Line | Count | Source | 124 | 590 | { | 125 | 590 | return ~Mask<T>::is_zero(v); | 126 | 590 | } |
|
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 | 198 | { |
134 | 198 | static_assert(sizeof(U) < sizeof(T), "sizes ok"); |
135 | 198 | return ~Mask<T>::is_zero(m.value()); |
136 | 198 | } |
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 | 3.79G | { |
143 | 3.79G | return Mask<T>(ct_is_zero<T>(x)); |
144 | 3.79G | } Botan::CT::Mask<unsigned long>::is_zero(unsigned long) Line | Count | Source | 142 | 3.77G | { | 143 | 3.77G | return Mask<T>(ct_is_zero<T>(x)); | 144 | 3.77G | } |
Botan::CT::Mask<unsigned char>::is_zero(unsigned char) Line | Count | Source | 142 | 18.7M | { | 143 | 18.7M | return Mask<T>(ct_is_zero<T>(x)); | 144 | 18.7M | } |
Unexecuted instantiation: Botan::CT::Mask<unsigned int>::is_zero(unsigned int) Botan::CT::Mask<unsigned short>::is_zero(unsigned short) Line | Count | Source | 142 | 80.9k | { | 143 | 80.9k | return Mask<T>(ct_is_zero<T>(x)); | 144 | 80.9k | } |
|
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 | 2.58G | { |
151 | 2.58G | return Mask<T>::is_zero(static_cast<T>(x ^ y)); |
152 | 2.58G | } Botan::CT::Mask<unsigned long>::is_equal(unsigned long, unsigned long) Line | Count | Source | 150 | 2.58G | { | 151 | 2.58G | return Mask<T>::is_zero(static_cast<T>(x ^ y)); | 152 | 2.58G | } |
Botan::CT::Mask<unsigned char>::is_equal(unsigned char, unsigned char) Line | Count | Source | 150 | 396k | { | 151 | 396k | return Mask<T>::is_zero(static_cast<T>(x ^ y)); | 152 | 396k | } |
Botan::CT::Mask<unsigned short>::is_equal(unsigned short, unsigned short) Line | Count | Source | 150 | 80.3k | { | 151 | 80.3k | return Mask<T>::is_zero(static_cast<T>(x ^ y)); | 152 | 80.3k | } |
|
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.05G | { |
159 | 1.05G | return Mask<T>(expand_top_bit<T>(x^((x^y) | ((x-y)^x)))); |
160 | 1.05G | } Botan::CT::Mask<unsigned long>::is_lt(unsigned long, unsigned long) Line | Count | Source | 158 | 1.05G | { | 159 | 1.05G | return Mask<T>(expand_top_bit<T>(x^((x^y) | ((x-y)^x)))); | 160 | 1.05G | } |
Botan::CT::Mask<unsigned int>::is_lt(unsigned int, unsigned int) Line | Count | Source | 158 | 674k | { | 159 | 674k | return Mask<T>(expand_top_bit<T>(x^((x^y) | ((x-y)^x)))); | 160 | 674k | } |
Botan::CT::Mask<unsigned short>::is_lt(unsigned short, unsigned short) Line | Count | Source | 158 | 80.8k | { | 159 | 80.8k | return Mask<T>(expand_top_bit<T>(x^((x^y) | ((x-y)^x)))); | 160 | 80.8k | } |
Botan::CT::Mask<unsigned char>::is_lt(unsigned char, unsigned char) Line | Count | Source | 158 | 141 | { | 159 | 141 | return Mask<T>(expand_top_bit<T>(x^((x^y) | ((x-y)^x)))); | 160 | 141 | } |
|
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 | 89.0k | { |
167 | 89.0k | return Mask<T>::is_lt(y, x); |
168 | 89.0k | } Botan::CT::Mask<unsigned long>::is_gt(unsigned long, unsigned long) Line | Count | Source | 166 | 8.59k | { | 167 | 8.59k | return Mask<T>::is_lt(y, x); | 168 | 8.59k | } |
Botan::CT::Mask<unsigned short>::is_gt(unsigned short, unsigned short) Line | Count | Source | 166 | 80.3k | { | 167 | 80.3k | return Mask<T>::is_lt(y, x); | 168 | 80.3k | } |
Botan::CT::Mask<unsigned char>::is_gt(unsigned char, unsigned char) Line | Count | Source | 166 | 141 | { | 167 | 141 | return Mask<T>::is_lt(y, x); | 168 | 141 | } |
|
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 | 82.3k | { |
175 | 82.3k | return ~Mask<T>::is_gt(x, y); |
176 | 82.3k | } Botan::CT::Mask<unsigned long>::is_lte(unsigned long, unsigned long) Line | Count | Source | 174 | 2.02k | { | 175 | 2.02k | return ~Mask<T>::is_gt(x, y); | 176 | 2.02k | } |
Botan::CT::Mask<unsigned short>::is_lte(unsigned short, unsigned short) Line | Count | Source | 174 | 80.3k | { | 175 | 80.3k | return ~Mask<T>::is_gt(x, y); | 176 | 80.3k | } |
|
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 | 686k | { |
183 | 686k | return ~Mask<T>::is_lt(x, y); |
184 | 686k | } Botan::CT::Mask<unsigned int>::is_gte(unsigned int, unsigned int) Line | Count | Source | 182 | 674k | { | 183 | 674k | return ~Mask<T>::is_lt(x, y); | 184 | 674k | } |
Botan::CT::Mask<unsigned long>::is_gte(unsigned long, unsigned long) Line | Count | Source | 182 | 12.5k | { | 183 | 12.5k | return ~Mask<T>::is_lt(x, y); | 184 | 12.5k | } |
|
185 | | |
186 | | /** |
187 | | * AND-combine two masks |
188 | | */ |
189 | | Mask<T>& operator&=(Mask<T> o) |
190 | 904k | { |
191 | 904k | m_mask &= o.value(); |
192 | 904k | return (*this); |
193 | 904k | } Botan::CT::Mask<unsigned long>::operator&=(Botan::CT::Mask<unsigned long>) Line | Count | Source | 190 | 272k | { | 191 | 272k | m_mask &= o.value(); | 192 | 272k | return (*this); | 193 | 272k | } |
Botan::CT::Mask<unsigned char>::operator&=(Botan::CT::Mask<unsigned char>) Line | Count | Source | 190 | 632k | { | 191 | 632k | m_mask &= o.value(); | 192 | 632k | return (*this); | 193 | 632k | } |
|
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 | 1.03M | { |
209 | 1.03M | m_mask |= o.value(); |
210 | 1.03M | return (*this); |
211 | 1.03M | } Botan::CT::Mask<unsigned long>::operator|=(Botan::CT::Mask<unsigned long>) Line | Count | Source | 208 | 157k | { | 209 | 157k | m_mask |= o.value(); | 210 | 157k | return (*this); | 211 | 157k | } |
Botan::CT::Mask<unsigned char>::operator|=(Botan::CT::Mask<unsigned char>) Line | Count | Source | 208 | 797k | { | 209 | 797k | m_mask |= o.value(); | 210 | 797k | return (*this); | 211 | 797k | } |
Botan::CT::Mask<unsigned short>::operator|=(Botan::CT::Mask<unsigned short>) Line | Count | Source | 208 | 80.0k | { | 209 | 80.0k | m_mask |= o.value(); | 210 | 80.0k | return (*this); | 211 | 80.0k | } |
|
212 | | |
213 | | /** |
214 | | * AND-combine two masks |
215 | | */ |
216 | | friend Mask<T> operator&(Mask<T> x, Mask<T> y) |
217 | 90.5M | { |
218 | 90.5M | return Mask<T>(x.value() & y.value()); |
219 | 90.5M | } Botan::CT::operator&(Botan::CT::Mask<unsigned long>, Botan::CT::Mask<unsigned long>) Line | Count | Source | 217 | 89.8M | { | 218 | 89.8M | return Mask<T>(x.value() & y.value()); | 219 | 89.8M | } |
Botan::CT::operator&(Botan::CT::Mask<unsigned char>, Botan::CT::Mask<unsigned char>) Line | Count | Source | 217 | 592k | { | 218 | 592k | return Mask<T>(x.value() & y.value()); | 219 | 592k | } |
Botan::CT::operator&(Botan::CT::Mask<unsigned short>, Botan::CT::Mask<unsigned short>) Line | Count | Source | 217 | 80.6k | { | 218 | 80.6k | return Mask<T>(x.value() & y.value()); | 219 | 80.6k | } |
|
220 | | |
221 | | /** |
222 | | * XOR-combine two masks |
223 | | */ |
224 | | friend Mask<T> operator^(Mask<T> x, Mask<T> y) |
225 | 1.43M | { |
226 | 1.43M | return Mask<T>(x.value() ^ y.value()); |
227 | 1.43M | } |
228 | | |
229 | | /** |
230 | | * OR-combine two masks |
231 | | */ |
232 | | friend Mask<T> operator|(Mask<T> x, Mask<T> y) |
233 | 90.0M | { |
234 | 90.0M | return Mask<T>(x.value() | y.value()); |
235 | 90.0M | } Botan::CT::operator|(Botan::CT::Mask<unsigned long>, Botan::CT::Mask<unsigned long>) Line | Count | Source | 233 | 89.8M | { | 234 | 89.8M | return Mask<T>(x.value() | y.value()); | 235 | 89.8M | } |
Botan::CT::operator|(Botan::CT::Mask<unsigned char>, Botan::CT::Mask<unsigned char>) Line | Count | Source | 233 | 196k | { | 234 | 196k | return Mask<T>(x.value() | y.value()); | 235 | 196k | } |
|
236 | | |
237 | | /** |
238 | | * Negate this mask |
239 | | */ |
240 | | Mask<T> operator~() const |
241 | 1.17G | { |
242 | 1.17G | return Mask<T>(~value()); |
243 | 1.17G | } Botan::CT::Mask<unsigned long>::operator~() const Line | Count | Source | 241 | 1.15G | { | 242 | 1.15G | return Mask<T>(~value()); | 243 | 1.15G | } |
Botan::CT::Mask<unsigned char>::operator~() const Line | Count | Source | 241 | 17.9M | { | 242 | 17.9M | return Mask<T>(~value()); | 243 | 17.9M | } |
Botan::CT::Mask<unsigned int>::operator~() const Line | Count | Source | 241 | 674k | { | 242 | 674k | return Mask<T>(~value()); | 243 | 674k | } |
Botan::CT::Mask<unsigned short>::operator~() const Line | Count | Source | 241 | 160k | { | 242 | 160k | return Mask<T>(~value()); | 243 | 160k | } |
|
244 | | |
245 | | /** |
246 | | * Return x if the mask is set, or otherwise zero |
247 | | */ |
248 | | T if_set_return(T x) const |
249 | 6.22G | { |
250 | 6.22G | return m_mask & x; |
251 | 6.22G | } Botan::CT::Mask<unsigned long>::if_set_return(unsigned long) const Line | Count | Source | 249 | 6.22G | { | 250 | 6.22G | return m_mask & x; | 251 | 6.22G | } |
Botan::CT::Mask<unsigned char>::if_set_return(unsigned char) const Line | Count | Source | 249 | 632k | { | 250 | 632k | return m_mask & x; | 251 | 632k | } |
Botan::CT::Mask<unsigned short>::if_set_return(unsigned short) const Line | Count | Source | 249 | 590 | { | 250 | 590 | return m_mask & x; | 251 | 590 | } |
|
252 | | |
253 | | /** |
254 | | * Return x if the mask is cleared, or otherwise zero |
255 | | */ |
256 | | T if_not_set_return(T x) const |
257 | 1.24M | { |
258 | 1.24M | return ~m_mask & x; |
259 | 1.24M | } Botan::CT::Mask<unsigned char>::if_not_set_return(unsigned char) const Line | Count | Source | 257 | 1.24M | { | 258 | 1.24M | return ~m_mask & x; | 259 | 1.24M | } |
Unexecuted instantiation: Botan::CT::Mask<unsigned long>::if_not_set_return(unsigned long) const Botan::CT::Mask<unsigned short>::if_not_set_return(unsigned short) const Line | Count | Source | 257 | 519 | { | 258 | 519 | return ~m_mask & x; | 259 | 519 | } |
|
260 | | |
261 | | /** |
262 | | * If this mask is set, return x, otherwise return y |
263 | | */ |
264 | | T select(T x, T y) const |
265 | 20.0G | { |
266 | 20.0G | // (x & value()) | (y & ~value()) |
267 | 20.0G | return static_cast<T>(y ^ (value() & (x ^ y))); |
268 | 20.0G | } Botan::CT::Mask<unsigned long>::select(unsigned long, unsigned long) const Line | Count | Source | 265 | 20.0G | { | 266 | 20.0G | // (x & value()) | (y & ~value()) | 267 | 20.0G | return static_cast<T>(y ^ (value() & (x ^ y))); | 268 | 20.0G | } |
Botan::CT::Mask<unsigned char>::select(unsigned char, unsigned char) const Line | Count | Source | 265 | 17.3M | { | 266 | 17.3M | // (x & value()) | (y & ~value()) | 267 | 17.3M | return static_cast<T>(y ^ (value() & (x ^ y))); | 268 | 17.3M | } |
Botan::CT::Mask<unsigned int>::select(unsigned int, unsigned int) const Line | Count | Source | 265 | 674k | { | 266 | 674k | // (x & value()) | (y & ~value()) | 267 | 674k | return static_cast<T>(y ^ (value() & (x ^ y))); | 268 | 674k | } |
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 | 621 | { |
272 | 621 | T r = this->select(x, y); |
273 | 621 | CT::unpoison(r); |
274 | 621 | return r; |
275 | 621 | } Botan::CT::Mask<unsigned long>::select_and_unpoison(unsigned long, unsigned long) const Line | Count | Source | 271 | 480 | { | 272 | 480 | T r = this->select(x, y); | 273 | 480 | CT::unpoison(r); | 274 | 480 | return r; | 275 | 480 | } |
Botan::CT::Mask<unsigned char>::select_and_unpoison(unsigned char, unsigned char) const Line | Count | Source | 271 | 141 | { | 272 | 141 | T r = this->select(x, y); | 273 | 141 | CT::unpoison(r); | 274 | 141 | return r; | 275 | 141 | } |
|
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 | 705M | { |
282 | 705M | return Mask<T>(select(x.value(), y.value())); |
283 | 705M | } |
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 | 420M | { |
291 | 3.93G | for(size_t i = 0; i != len; ++i) |
292 | 3.51G | output[i] = this->select(x[i], y[i]); |
293 | 420M | } Botan::CT::Mask<unsigned long>::select_n(unsigned long*, unsigned long const*, unsigned long const*, unsigned long) const Line | Count | Source | 290 | 420M | { | 291 | 3.93G | for(size_t i = 0; i != len; ++i) | 292 | 3.51G | output[i] = this->select(x[i], y[i]); | 293 | 420M | } |
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 | 2.02k | { |
300 | 843k | for(size_t i = 0; i != elems; ++i) |
301 | 841k | { |
302 | 841k | buf[i] = this->if_not_set_return(buf[i]); |
303 | 841k | } |
304 | 2.02k | } |
305 | | |
306 | | /** |
307 | | * Return the value of the mask, unpoisoned |
308 | | */ |
309 | | T unpoisoned_value() const |
310 | 12.1M | { |
311 | 12.1M | T r = value(); |
312 | 12.1M | CT::unpoison(r); |
313 | 12.1M | return r; |
314 | 12.1M | } Botan::CT::Mask<unsigned long>::unpoisoned_value() const Line | Count | Source | 310 | 11.4M | { | 311 | 11.4M | T r = value(); | 312 | 11.4M | CT::unpoison(r); | 313 | 11.4M | return r; | 314 | 11.4M | } |
Botan::CT::Mask<unsigned int>::unpoisoned_value() const Line | Count | Source | 310 | 674k | { | 311 | 674k | T r = value(); | 312 | 674k | CT::unpoison(r); | 313 | 674k | return r; | 314 | 674k | } |
Botan::CT::Mask<unsigned char>::unpoisoned_value() const Line | Count | Source | 310 | 369 | { | 311 | 369 | T r = value(); | 312 | 369 | CT::unpoison(r); | 313 | 369 | return r; | 314 | 369 | } |
Botan::CT::Mask<unsigned short>::unpoisoned_value() const Line | Count | Source | 310 | 295 | { | 311 | 295 | T r = value(); | 312 | 295 | CT::unpoison(r); | 313 | 295 | return r; | 314 | 295 | } |
|
315 | | |
316 | | /** |
317 | | * Return true iff this mask is set |
318 | | */ |
319 | | bool is_set() const |
320 | 12.1M | { |
321 | 12.1M | return unpoisoned_value() != 0; |
322 | 12.1M | } Botan::CT::Mask<unsigned long>::is_set() const Line | Count | Source | 320 | 11.4M | { | 321 | 11.4M | return unpoisoned_value() != 0; | 322 | 11.4M | } |
Botan::CT::Mask<unsigned int>::is_set() const Line | Count | Source | 320 | 674k | { | 321 | 674k | return unpoisoned_value() != 0; | 322 | 674k | } |
Unexecuted instantiation: Botan::CT::Mask<unsigned char>::is_set() const Botan::CT::Mask<unsigned short>::is_set() const Line | Count | Source | 320 | 295 | { | 321 | 295 | return unpoisoned_value() != 0; | 322 | 295 | } |
|
323 | | |
324 | | /** |
325 | | * Return the underlying value of the mask |
326 | | */ |
327 | | T value() const |
328 | 23.1G | { |
329 | 23.1G | return m_mask; |
330 | 23.1G | } Botan::CT::Mask<unsigned long>::value() const Line | Count | Source | 328 | 23.0G | { | 329 | 23.0G | return m_mask; | 330 | 23.0G | } |
Botan::CT::Mask<unsigned char>::value() const Line | Count | Source | 328 | 38.3M | { | 329 | 38.3M | return m_mask; | 330 | 38.3M | } |
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 | 402k | { | 329 | 402k | return m_mask; | 330 | 402k | } |
|
331 | | |
332 | | private: |
333 | 6.90G | Mask(T m) : m_mask(m) {} Botan::CT::Mask<unsigned long>::Mask(unsigned long) Line | Count | Source | 333 | 6.86G | Mask(T m) : m_mask(m) {} |
Botan::CT::Mask<unsigned char>::Mask(unsigned char) Line | Count | Source | 333 | 37.5M | Mask(T m) : m_mask(m) {} |
Botan::CT::Mask<unsigned int>::Mask(unsigned int) Line | Count | Source | 333 | 1.34M | Mask(T m) : m_mask(m) {} |
Botan::CT::Mask<unsigned short>::Mask(unsigned short) Line | Count | Source | 333 | 403k | 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 | 79.7M | { |
345 | 79.7M | const auto mask = CT::Mask<T>::expand(cnd); |
346 | 79.7M | mask.select_n(to, from0, from1, elems); |
347 | 79.7M | return mask; |
348 | 79.7M | } |
349 | | |
350 | | template<typename T> |
351 | | inline void conditional_swap(bool cnd, T& x, T& y) |
352 | 27.8M | { |
353 | 27.8M | const auto swap = CT::Mask<T>::expand(cnd); |
354 | 27.8M | |
355 | 27.8M | T t0 = swap.select(y, x); |
356 | 27.8M | T t1 = swap.select(x, y); |
357 | 27.8M | x = t0; |
358 | 27.8M | y = t1; |
359 | 27.8M | } |
360 | | |
361 | | template<typename T> |
362 | | inline void conditional_swap_ptr(bool cnd, T& x, T& y) |
363 | 13.9M | { |
364 | 13.9M | uintptr_t xp = reinterpret_cast<uintptr_t>(x); |
365 | 13.9M | uintptr_t yp = reinterpret_cast<uintptr_t>(y); |
366 | 13.9M | |
367 | 13.9M | conditional_swap<uintptr_t>(cnd, xp, yp); |
368 | 13.9M | |
369 | 13.9M | x = reinterpret_cast<T>(xp); |
370 | 13.9M | y = reinterpret_cast<T>(yp); |
371 | 13.9M | } |
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 | 1.66k | { |
387 | 1.66k | return strip_leading_zeros(in.data(), in.size()); |
388 | 1.66k | } |
389 | | |
390 | | } |
391 | | |
392 | | } |
393 | | |
394 | | #endif |