Botan 3.11.0
Crypto and TLS for C&
ct_utils.h
Go to the documentation of this file.
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,2024 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/assert.h>
18#include <botan/range_concepts.h>
19#include <botan/secmem.h>
20#include <botan/internal/bit_ops.h>
21#include <botan/internal/scoped_cleanup.h>
22#include <botan/internal/target_info.h>
23#include <botan/internal/value_barrier.h>
24
25#include <optional>
26#include <span>
27#include <type_traits>
28
29#if defined(BOTAN_HAS_VALGRIND)
30 #include <valgrind/memcheck.h>
31#endif
32
33namespace Botan::CT {
34
35/// @name Constant Time Check Annotation Helpers
36/// @{
37
38/**
39* Use valgrind to mark the contents of memory as being undefined.
40* Valgrind will accept operations which manipulate undefined values,
41* but will warn if an undefined value is used to decided a conditional
42* jump or a load/store address. So if we poison all of our inputs we
43* can confirm that the operations in question are truly const time
44* when compiled by whatever compiler is in use.
45*
46* Even better, the VALGRIND_MAKE_MEM_* macros work even when the
47* program is not run under valgrind (though with a few cycles of
48* overhead, which is unfortunate in final binaries as these
49* annotations tend to be used in fairly important loops).
50*
51* This approach was first used in ctgrind (https://github.com/agl/ctgrind)
52* but calling the valgrind mecheck API directly works just as well and
53* doesn't require a custom patched valgrind.
54*/
55template <typename T>
56constexpr inline void poison(const T* p, size_t n) {
57#if defined(BOTAN_HAS_VALGRIND)
58 if(!std::is_constant_evaluated()) {
59 VALGRIND_MAKE_MEM_UNDEFINED(p, n * sizeof(T));
60 }
61#endif
62
63 BOTAN_UNUSED(p, n);
64}
65
66template <typename T>
67constexpr inline void unpoison(const T* p, size_t n) {
68#if defined(BOTAN_HAS_VALGRIND)
69 if(!std::is_constant_evaluated()) {
70 VALGRIND_MAKE_MEM_DEFINED(p, n * sizeof(T));
71 }
72#endif
73
74 BOTAN_UNUSED(p, n);
75}
76
77/**
78 * Checks whether CT::poison() and CT::unpoison() actually have an effect.
79 *
80 * If the build is not instrumented and/or not run using an analysis tool like
81 * valgrind, the functions are no-ops and the return value is false.
82 *
83 * @returns true if CT::poison() and CT::unpoison() are effective
84 */
85inline bool poison_has_effect() {
86#if defined(BOTAN_HAS_VALGRIND)
87 return RUNNING_ON_VALGRIND;
88#else
89 return false;
90#endif
91}
92
93/// @}
94
95/// @name Constant Time Check Annotation Convenience overloads
96/// @{
97
98template <typename T>
99concept custom_poisonable = requires(const T& v) { v._const_time_poison(); };
100template <typename T>
101concept custom_unpoisonable = requires(const T& v) { v._const_time_unpoison(); };
102
103/**
104 * Poison a single integral object
105 */
106template <std::integral T>
107constexpr void poison(const T& p) {
108 poison(&p, 1);
109}
110
111template <std::integral T>
112constexpr void unpoison(const T& p) {
113 unpoison(&p, 1);
114}
115
116/**
117 * Poison a contiguous buffer of trivial objects (e.g. integers and such)
118 */
119template <ranges::spanable_range R>
120 requires std::is_trivially_copyable_v<std::ranges::range_value_t<R>> && (!custom_poisonable<R>)
121constexpr void poison(const R& r) {
122 const std::span s{r};
123 poison(s.data(), s.size());
124}
125
126template <ranges::spanable_range R>
127 requires std::is_trivially_copyable_v<std::ranges::range_value_t<R>> && (!custom_unpoisonable<R>)
128constexpr void unpoison(const R& r) {
129 const std::span s{r};
130 unpoison(s.data(), s.size());
131}
132
133/**
134 * Poison a class type that provides a public `_const_time_poison()` method
135 * For instance: BigInt, CT::Mask<>, FrodoMatrix, ...
136 */
137template <custom_poisonable T>
138constexpr void poison(const T& x) {
139 x._const_time_poison();
140}
141
142template <custom_unpoisonable T>
143constexpr void unpoison(const T& x) {
144 x._const_time_unpoison();
145}
146
147/**
148 * Poison an optional object if it has a value.
149 */
150template <typename T>
151 requires requires(const T& v) { ::Botan::CT::poison(v); }
152constexpr void poison(const std::optional<T>& x) {
153 if(x.has_value()) {
154 poison(*x);
155 }
156}
157
158template <typename T>
159 requires requires(const T& v) { ::Botan::CT::unpoison(v); }
160constexpr void unpoison(const std::optional<T>& x) {
161 if(x.has_value()) {
162 unpoison(*x);
163 }
164}
165
166/// @}
167
168/// @name Higher-level Constant Time Check Annotation Helpers
169/// @{
170
171template <typename T>
172concept poisonable = requires(const T& v) { ::Botan::CT::poison(v); };
173template <typename T>
174concept unpoisonable = requires(const T& v) { ::Botan::CT::unpoison(v); };
175
176/**
177 * Poison a range of objects by calling `poison` on each element.
178 */
179template <std::ranges::range R>
181constexpr void poison_range(const R& r) {
182 for(const auto& v : r) {
183 poison(v);
184 }
185}
186
187template <std::ranges::range R>
188 requires unpoisonable<std::ranges::range_value_t<R>>
189constexpr void unpoison_range(const R& r) {
190 for(const auto& v : r) {
191 unpoison(v);
192 }
193}
194
195/**
196 * Poisons an arbitrary number of values in a single call.
197 * Mostly syntactic sugar to save clutter (i.e. lines-of-code).
198 */
199template <poisonable... Ts>
200 requires(sizeof...(Ts) > 0)
201constexpr void poison_all(const Ts&... ts) {
202 (poison(ts), ...);
203}
204
205template <unpoisonable... Ts>
206 requires(sizeof...(Ts) > 0)
207constexpr void unpoison_all(const Ts&... ts) {
208 (unpoison(ts), ...);
209}
210
211/**
212 * Poisons an arbitrary number of poisonable values, and unpoisons them when the
213 * returned object runs out-of-scope
214 *
215 * Use this when you want to poison a value that remains valid longer than the
216 * scope you are currently in. For instance, a private key structure that is a
217 * member of a Signature_Operation object, that may be used for multiple
218 * signatures.
219 */
220template <typename... Ts>
221 requires(sizeof...(Ts) > 0) && (poisonable<Ts> && ...) && (unpoisonable<Ts> && ...)
222[[nodiscard]] constexpr auto scoped_poison(const Ts&... xs) {
223 auto scope = scoped_cleanup([&] { unpoison_all(xs...); });
224 poison_all(xs...);
225 return scope;
226}
227
228/**
229 * Poisons an r-value @p v and forwards it as the return value.
230 */
231template <poisonable T>
232[[nodiscard]] decltype(auto) driveby_poison(T&& v)
233 requires(std::is_rvalue_reference_v<decltype(v)>)
234{
235 poison(v);
236 return std::forward<T>(v);
237}
238
239/**
240 * Unpoisons an r-value @p v and forwards it as the return value.
241 */
242template <unpoisonable T>
243[[nodiscard]] decltype(auto) driveby_unpoison(T&& v)
244 requires(std::is_rvalue_reference_v<decltype(v)>)
245{
246 unpoison(v);
247 return std::forward<T>(v);
248}
249
250/// @}
251
252/**
253* A Choice is used for constant-time conditionals.
254*
255* Internally it always is either |0| (all 0 bits) or |1| (all 1 bits)
256* and measures are taken to block compilers from reasoning about the
257* expected value of a Choice.
258*/
259class Choice final {
260 public:
262
263 /**
264 * If v == 0 return an unset (false) Choice, otherwise a set Choice
265 */
266 template <typename T>
267 requires std::unsigned_integral<T> && (!std::same_as<bool, T>)
268 constexpr static Choice from_int(T v) {
269 if constexpr(sizeof(T) <= sizeof(underlying_type)) {
271 } else {
272 // Mask of T that is either |0| or |1|
273 const T v_is_0 = ct_is_zero<T>(value_barrier<T>(v));
274
275 // We want the mask to be set if v != 0 so we must check that
276 // v_is_0 is itself zero.
277 //
278 // Also sizeof(T) may not equal sizeof(underlying_type) so we must
279 // use ct_is_zero<underlying_type>. It's ok to either truncate or
280 // zero extend v_is_0 to 32 bits since we know it is |0| or |1|
281 // so even just the low bit is sufficient.
282 return Choice(ct_is_zero<underlying_type>(static_cast<underlying_type>(v_is_0)));
283 }
284 }
285
286 /**
287 * Return a bitmask |1| if the choice is set, or |0| otherwise
288 */
289 template <typename T>
290 requires std::unsigned_integral<T> && (!std::same_as<bool, T>)
291 constexpr T into_bitmask() const {
292 if constexpr(sizeof(T) <= sizeof(underlying_type)) {
293 // The inner mask is already |0| or |1| so just truncate
294 return static_cast<T>(value());
295 } else {
296 return ~ct_is_zero<T>(value());
297 }
298 }
299
300 /**
301 * Create a Choice directly from a mask value - this assumes v is either |0| or |1|
302 */
303 constexpr static Choice from_mask(underlying_type v) { return Choice(v); }
304
305 constexpr static Choice yes() { return !no(); }
306
307 constexpr static Choice no() { return Choice(0); }
308
309 constexpr Choice operator!() const { return Choice(~value()); }
310
311 constexpr Choice operator&&(const Choice& other) const { return Choice(value() & other.value()); }
312
313 constexpr Choice operator||(const Choice& other) const { return Choice(value() | other.value()); }
314
315 constexpr Choice operator!=(const Choice& other) const { return Choice(value() ^ other.value()); }
316
317 constexpr Choice operator==(const Choice& other) const { return !(*this != other); }
318
319 /**
320 * Unsafe conversion to bool
321 *
322 * This conversion itself is (probably) constant time, but once the
323 * choice is reduced to a simple bool, it's entirely possible for the
324 * compiler to perform range analysis on the values, since there are just
325 * the two. As a consequence even if the caller is not using this in an
326 * obviously branchy way (`if(choice.as_bool()) ...`) a smart compiler
327 * may introduce branches depending on the value.
328 */
329 constexpr bool as_bool() const { return m_value != 0; }
330
331 /// Return the masked value
332 constexpr underlying_type value() const { return value_barrier(m_value); }
333
334 constexpr Choice(const Choice& other) = default;
335 constexpr Choice(Choice&& other) = default;
336 constexpr Choice& operator=(const Choice& other) noexcept = default;
337 constexpr Choice& operator=(Choice&& other) noexcept = default;
338 constexpr ~Choice() = default;
339
340 private:
341 constexpr explicit Choice(underlying_type v) : m_value(CT::value_barrier<underlying_type>(v)) {}
342
343 underlying_type m_value;
344};
345
346/**
347* A concept for a type which is conditionally assignable
348*/
349template <typename T>
350concept ct_conditional_assignable = requires(T lhs, const T& rhs, Choice c) { lhs.conditional_assign(c, rhs); };
351
352/**
353* A Mask type used for constant-time operations. A Mask<T> always has value
354* either |0| (all bits cleared) or |1| (all bits set). All operations in a Mask<T>
355* are intended to compile to code which does not contain conditional jumps.
356* This must be verified with tooling (eg binary disassembly or using valgrind)
357* since you never know what a compiler might do.
358*/
359template <typename T>
360class Mask final {
361 public:
362 static_assert(std::is_unsigned_v<T> && !std::is_same_v<bool, T>,
363 "Only unsigned integer types are supported by CT::Mask");
364
365 Mask(const Mask<T>& other) = default;
366 Mask(Mask<T>&& other) = default;
367 Mask<T>& operator=(const Mask<T>& other) = default;
368 Mask<T>& operator=(Mask<T>&& other) = default;
369 ~Mask() = default;
370
371 /**
372 * Derive a Mask from a Mask of a larger type
373 */
374 template <typename U>
375 constexpr explicit Mask(Mask<U> o) : m_mask(static_cast<T>(o.value())) {
376 static_assert(sizeof(U) > sizeof(T), "sizes ok");
377 }
378
379 /**
380 * Return a Mask<T> of |1| (all bits set)
381 */
382 static constexpr Mask<T> set() { return Mask<T>(static_cast<T>(~0)); }
383
384 /**
385 * Return a Mask<T> of |0| (all bits cleared)
386 */
387 static constexpr Mask<T> cleared() { return Mask<T>(0); }
388
389 /**
390 * Return a Mask<T> which is set if v is != 0
391 */
392 static constexpr Mask<T> expand(T v) { return ~Mask<T>::is_zero(value_barrier<T>(v)); }
393
394 /**
395 * Return a Mask<T> which is set if v is true
396 */
397 static constexpr Mask<T> expand_bool(bool v) { return Mask<T>::expand(static_cast<T>(v)); }
398
399 /**
400 * Return a Mask<T> which is set if choice is set
401 */
402 static constexpr Mask<T> from_choice(Choice c) {
403 if constexpr(sizeof(T) <= sizeof(Choice::underlying_type)) {
404 // Take advantage of the fact that Choice's mask is always
405 // either |0| or |1|
406 return Mask<T>(static_cast<T>(c.value()));
407 } else {
408 return ~Mask<T>::is_zero(c.value());
409 }
410 }
411
412 /**
413 * Return a Mask<T> which is set if the top bit of v is set
414 */
415 static constexpr Mask<T> expand_top_bit(T v) { return Mask<T>(ct_expand_top_bit<T>(v)); }
416
417 /**
418 * Return a Mask<T> which is set if the given @p bit of @p v is set.
419 * @p bit must be from 0 (LSB) to (sizeof(T) * 8 - 1) (MSB).
420 */
421 static constexpr Mask<T> expand_bit(T v, size_t bit) {
422 return CT::Mask<T>::expand_top_bit(v << (sizeof(v) * 8 - 1 - bit));
423 }
424
425 /**
426 * Return a Mask<T> which is set if m is set
427 */
428 template <typename U>
429 static constexpr Mask<T> expand(Mask<U> m) {
430 static_assert(sizeof(U) < sizeof(T), "sizes ok");
431 return ~Mask<T>::is_zero(m.value());
432 }
433
434 /**
435 * Return a Mask<T> which is set if v is == 0 or cleared otherwise
436 */
437 static constexpr Mask<T> is_zero(T x) { return Mask<T>(ct_is_zero<T>(value_barrier<T>(x))); }
438
439 /**
440 * Return a Mask<T> which is set if x == y
441 */
442 static constexpr Mask<T> is_equal(T x, T y) {
443 const T diff = value_barrier(x) ^ value_barrier(y);
444 return Mask<T>::is_zero(diff);
445 }
446
447 /**
448 * Return a Mask<T> which is set if x < y
449 */
450 static constexpr Mask<T> is_lt(T x, T y) {
451 T u = x ^ ((x ^ y) | ((x - y) ^ x));
452 return Mask<T>::expand_top_bit(u);
453 }
454
455 /**
456 * Return a Mask<T> which is set if x > y
457 */
458 static constexpr Mask<T> is_gt(T x, T y) { return Mask<T>::is_lt(y, x); }
459
460 /**
461 * Return a Mask<T> which is set if x <= y
462 */
463 static constexpr Mask<T> is_lte(T x, T y) { return ~Mask<T>::is_gt(x, y); }
464
465 /**
466 * Return a Mask<T> which is set if x >= y
467 */
468 static constexpr Mask<T> is_gte(T x, T y) { return ~Mask<T>::is_lt(x, y); }
469
470 static constexpr Mask<T> is_within_range(T v, T l, T u) {
471 //return Mask<T>::is_gte(v, l) & Mask<T>::is_lte(v, u);
472
473 const T v_lt_l = v ^ ((v ^ l) | ((v - l) ^ v));
474 const T v_gt_u = u ^ ((u ^ v) | ((u - v) ^ u));
475 const T either = value_barrier(v_lt_l) | value_barrier(v_gt_u);
476 return ~Mask<T>::expand_top_bit(either);
477 }
478
479 static constexpr Mask<T> is_any_of(T v, std::initializer_list<T> accepted) {
480 T accept = 0;
481
482 for(auto a : accepted) {
483 const T diff = a ^ v;
484 const T eq_zero = value_barrier<T>(~diff & (diff - 1));
485 accept |= eq_zero;
486 }
487
488 return Mask<T>::expand_top_bit(accept);
489 }
490
491 /**
492 * AND-combine two masks
493 */
495 m_mask &= o.value();
496 return (*this);
497 }
498
499 /**
500 * XOR-combine two masks
501 */
503 m_mask ^= o.value();
504 return (*this);
505 }
506
507 /**
508 * OR-combine two masks
509 */
511 m_mask |= o.value();
512 return (*this);
513 }
514
515 /**
516 * AND-combine two masks
517 */
518 friend Mask<T> operator&(Mask<T> x, Mask<T> y) { return Mask<T>(x.value() & y.value()); }
519
520 /**
521 * XOR-combine two masks
522 */
523 friend Mask<T> operator^(Mask<T> x, Mask<T> y) { return Mask<T>(x.value() ^ y.value()); }
524
525 /**
526 * OR-combine two masks
527 */
528 friend Mask<T> operator|(Mask<T> x, Mask<T> y) { return Mask<T>(x.value() | y.value()); }
529
530 /**
531 * Negate this mask
532 */
533 constexpr Mask<T> operator~() const { return Mask<T>(~value()); }
534
535 /**
536 * Return x if the mask is set, or otherwise zero
537 */
538 constexpr T if_set_return(T x) const { return value() & x; }
539
540 /**
541 * Return x if the mask is cleared, or otherwise zero
542 */
543 constexpr T if_not_set_return(T x) const { return ~value() & x; }
544
545 /**
546 * If this mask is set, return x, otherwise return y
547 */
548 constexpr T select(T x, T y) const { return choose(value(), x, y); }
549
550 constexpr T select_and_unpoison(T x, T y) const {
551 T r = this->select(x, y);
552 CT::unpoison(r);
553 return r;
554 }
555
556 /**
557 * If this mask is set, return x, otherwise return y
558 */
559 Mask<T> select_mask(Mask<T> x, Mask<T> y) const { return Mask<T>(select(x.value(), y.value())); }
560
561 /**
562 * Conditionally set output to x or y, depending on if mask is set or
563 * cleared (resp)
564 */
565 constexpr void select_n(T output[], const T x[], const T y[], size_t len) const {
566 const T mask = value();
567 for(size_t i = 0; i != len; ++i) {
568 output[i] = choose(mask, x[i], y[i]);
569 }
570 }
571
572 /**
573 * If this mask is set, zero out buf, otherwise do nothing
574 */
575 constexpr void if_set_zero_out(T buf[], size_t elems) {
576 for(size_t i = 0; i != elems; ++i) {
577 buf[i] = this->if_not_set_return(buf[i]);
578 }
579 }
580
581 /**
582 * If this mask is set, swap x and y
583 */
584 template <typename U>
585 void conditional_swap(U& x, U& y) const
586 requires(sizeof(U) <= sizeof(T))
587 {
588 auto cnd = Mask<U>(*this);
589 U t0 = cnd.select(y, x);
590 U t1 = cnd.select(x, y);
591 x = t0;
592 y = t1;
593 }
594
595 /**
596 * Return the value of the mask, unpoisoned
597 */
598 constexpr T unpoisoned_value() const {
599 T r = value();
600 CT::unpoison(r);
601 return r;
602 }
603
604 /**
605 * Unsafe conversion to bool
606 *
607 * This conversion itself is (probably) constant time, but once the
608 * mask is reduced to a simple bool, it's entirely possible for the
609 * compiler to perform range analysis on the values, since there are just
610 * the two. As a consequence even if the caller is not using this in an
611 * obviously branchy way (`if(mask.as_bool()) ...`) a smart compiler
612 * may introduce branches depending on the value.
613 */
614 constexpr bool as_bool() const { return unpoisoned_value() != 0; }
615
616 /**
617 * Return a Choice based on this mask
618 */
619 constexpr CT::Choice as_choice() const {
620 if constexpr(sizeof(T) >= sizeof(Choice::underlying_type)) {
622 } else {
624 }
625 }
626
627 /**
628 * Return the underlying value of the mask
629 */
630 constexpr T value() const { return value_barrier<T>(m_mask); }
631
632 constexpr void _const_time_poison() const { CT::poison(m_mask); }
633
634 constexpr void _const_time_unpoison() const { CT::unpoison(m_mask); }
635
636 private:
637 constexpr explicit Mask(T m) : m_mask(m) {}
638
639 T m_mask;
640};
641
642/**
643* A CT::Option<T> is either a valid T, or not
644*
645* To maintain constant time behavior a value must always be stored.
646* A CT::Choice tracks if the value is valid or not. It is not possible
647* to access the inner value if the Choice is unset.
648*/
649template <typename T>
650class Option final {
651 public:
652 /// Construct an Option which contains the specified value, and is set or not
653 constexpr Option(T v, Choice valid) : m_has_value(valid), m_value(std::move(v)) {}
654
655 /// Construct a set option with the provided value
656 constexpr explicit Option(T v) : Option(std::move(v), Choice::yes()) {}
657
658 /// Construct an unset option with a default inner value
659 constexpr Option()
660 requires std::default_initializable<T>
661 : Option(T(), Choice::no()) {}
662
663 /// Return true if this Option contains a value
664 constexpr Choice has_value() const { return m_has_value; }
665
666 /**
667 * Apply a function to the inner value and return a new Option
668 * which contains that value. This is constant time only if @p f is.
669 *
670 * @note The function will always be called, even if the Option is None. It
671 * must be prepared to handle any possible state of T.
672 */
673 template <std::invocable<const T&> F>
675 return {f(m_value), m_has_value};
676 }
677
678 /// Either returns the value or throws an exception
679 constexpr const T& value() const {
680 BOTAN_STATE_CHECK(m_has_value.as_bool());
681 return m_value;
682 }
683
684 /// Returns either the inner value or the alternative, in constant time
685 ///
686 /// This variant is used for types which explicitly define a function
687 /// conditional_assign which takes a CT::Choice as the conditional.
688 constexpr T value_or(T other) const
690 {
691 other.conditional_assign(m_has_value, m_value);
692 return other;
693 }
694
695 /// Returns either the inner value or the alternative, in constant time
696 ///
697 /// This variant is used for integer types where CT::Mask can perform
698 /// a constant time selection
699 constexpr T value_or(T other) const
700 requires std::unsigned_integral<T>
701 {
702 auto mask = CT::Mask<T>::from_choice(m_has_value);
703 return mask.select(m_value, other);
704 }
705
706 /// Convert this Option into a std::optional
707 ///
708 /// This is not constant time, leaking if the Option had a
709 /// value or not
710 constexpr std::optional<T> as_optional_vartime() const {
711 if(m_has_value.as_bool()) {
712 return {m_value};
713 } else {
714 return {};
715 }
716 }
717
718 /// Return a new CT::Option that is set if @p also is set as well
719 constexpr CT::Option<T> operator&&(CT::Choice also) { return CT::Option<T>(m_value, m_has_value && also); }
720
721 private:
722 Choice m_has_value;
723 T m_value;
724};
725
726/**
727* Conditional memory copy (constant time)
728*
729* If mask is set, then sets dest to if_set, otherwise sets dest to if_unset
730*/
731template <typename T>
732constexpr inline Mask<T> conditional_copy_mem(Mask<T> mask, T* dest, const T* if_set, const T* if_unset, size_t elems) {
733 mask.select_n(dest, if_set, if_unset, elems);
734 return mask;
735}
736
737template <typename T>
738constexpr inline Mask<T> conditional_copy_mem(T cnd, T* dest, const T* if_set, const T* if_unset, size_t elems) {
739 const auto mask = CT::Mask<T>::expand(cnd);
740 return CT::conditional_copy_mem(mask, dest, if_set, if_unset, elems);
741}
742
743/**
744* Conditional memory assignment (constant time)
745*
746* If mask is set overwrites dest with src
747*/
748template <typename T>
749constexpr inline Mask<T> conditional_assign_mem(T cnd, T* dest, const T* src, size_t elems) {
750 const auto mask = CT::Mask<T>::expand(cnd);
751 mask.select_n(dest, src, dest, elems);
752 return mask;
753}
754
755/**
756* Conditional memory assignment (constant time)
757*
758* If mask is set overwrites dest with src
759*/
760template <typename T>
761constexpr inline Mask<T> conditional_assign_mem(Choice cnd, T* dest, const T* src, size_t elems) {
762 const auto mask = CT::Mask<T>::from_choice(cnd);
763 mask.select_n(dest, src, dest, elems);
764 return mask;
765}
766
767template <typename T>
768constexpr inline void conditional_swap(bool cnd, T& x, T& y) {
769 const auto swap = CT::Mask<T>::expand(cnd);
770 swap.conditional_swap(x, y);
771}
772
773template <typename T>
774constexpr inline void conditional_swap_ptr(bool cnd, T& x, T& y) {
775 uintptr_t xp = reinterpret_cast<uintptr_t>(x);
776 uintptr_t yp = reinterpret_cast<uintptr_t>(y);
777
778 conditional_swap<uintptr_t>(cnd, xp, yp);
779
780 x = reinterpret_cast<T>(xp); // NOLINT(*-no-int-to-ptr)
781 y = reinterpret_cast<T>(yp); // NOLINT(*-no-int-to-ptr)
782}
783
784template <typename T>
785constexpr inline CT::Mask<T> all_zeros(const T elem[], size_t len) {
786 T sum = 0;
787 for(size_t i = 0; i != len; ++i) {
788 sum |= elem[i];
789 }
790 return CT::Mask<T>::is_zero(sum);
791}
792
793/**
794* Compare two arrays of equal size and return a Mask indicating if
795* they are equal or not. The mask is set if they are identical.
796*/
797template <typename T>
798constexpr inline CT::Mask<T> is_equal(const T x[], const T y[], size_t len) {
799 if(std::is_constant_evaluated()) {
800 T difference = 0;
801
802 for(size_t i = 0; i != len; ++i) {
803 difference = difference | (x[i] ^ y[i]);
804 }
805
806 return CT::Mask<T>::is_zero(difference);
807 } else {
808 volatile T difference = 0;
809
810 for(size_t i = 0; i != len; ++i) {
811 difference = difference | (x[i] ^ y[i]);
812 }
813
814 return CT::Mask<T>::is_zero(difference);
815 }
816}
817
818/**
819* Compare two spans and return a Mask which is set iff they were identical.
820*
821* If the spans are of different length then the function returns early without
822* looking at either span
823*/
824template <typename T>
825constexpr inline CT::Mask<T> is_equal(std::span<const T> x, std::span<const T> y) {
826 if(x.size() != y.size()) {
827 return CT::Mask<T>::cleared();
828 }
829
830 return is_equal(x.data(), y.data(), x.size());
831}
832
833/**
834* Compare two arrays of equal size and return a Mask indicating if
835* they are equal or not. The mask is set if they differ.
836*/
837template <typename T>
838constexpr inline CT::Mask<T> is_not_equal(const T x[], const T y[], size_t len) {
839 return ~CT::is_equal(x, y, len);
840}
841
842/**
843* Constant time conditional copy out with offset
844*
845* If accept is set and offset <= input_length, sets output[0..] to
846* input[offset:input_length] and returns input_length - offset. The
847* remaining bytes of output are zeroized.
848*
849* Otherwise, output is zeroized, and returns an empty Ct::Option
850*
851* The input and output spans may not overlap, and output must be at
852* least as large as input.
853*
854* This function attempts to avoid leaking the following to side channels
855* - if accept was set or not
856* - the value of offset
857* - the value of input
858*
859* This function leaks the length of the input
860*/
863 std::span<uint8_t> output,
864 std::span<const uint8_t> input,
865 size_t offset);
866
867size_t count_leading_zero_bytes(std::span<const uint8_t> input);
868
869secure_vector<uint8_t> strip_leading_zeros(std::span<const uint8_t> input);
870
871} // namespace Botan::CT
872
873#endif
#define BOTAN_TEST_API
Definition api.h:41
#define BOTAN_UNUSED
Definition assert.h:144
#define BOTAN_STATE_CHECK(expr)
Definition assert.h:49
constexpr Choice operator==(const Choice &other) const
Definition ct_utils.h:317
static constexpr Choice yes()
Definition ct_utils.h:305
static constexpr Choice from_int(T v)
Definition ct_utils.h:268
constexpr Choice & operator=(const Choice &other) noexcept=default
constexpr Choice(const Choice &other)=default
static constexpr Choice from_mask(underlying_type v)
Definition ct_utils.h:303
constexpr Choice operator!=(const Choice &other) const
Definition ct_utils.h:315
constexpr Choice operator||(const Choice &other) const
Definition ct_utils.h:313
constexpr Choice operator!() const
Definition ct_utils.h:309
static constexpr Choice no()
Definition ct_utils.h:307
constexpr T into_bitmask() const
Definition ct_utils.h:291
constexpr bool as_bool() const
Definition ct_utils.h:329
constexpr Choice(Choice &&other)=default
constexpr ~Choice()=default
constexpr Choice operator&&(const Choice &other) const
Definition ct_utils.h:311
constexpr Choice & operator=(Choice &&other) noexcept=default
constexpr underlying_type value() const
Return the masked value.
Definition ct_utils.h:332
static constexpr Mask< T > expand_bit(T v, size_t bit)
Definition ct_utils.h:421
Mask< T > select_mask(Mask< T > x, Mask< T > y) const
Definition ct_utils.h:559
void conditional_swap(U &x, U &y) const
Definition ct_utils.h:585
constexpr T value() const
Definition ct_utils.h:630
constexpr void if_set_zero_out(T buf[], size_t elems)
Definition ct_utils.h:575
static constexpr Mask< T > is_lte(T x, T y)
Definition ct_utils.h:463
static constexpr Mask< T > is_gte(T x, T y)
Definition ct_utils.h:468
constexpr T if_not_set_return(T x) const
Definition ct_utils.h:543
constexpr Mask(Mask< U > o)
Definition ct_utils.h:375
~Mask()=default
static constexpr Mask< T > set()
Definition ct_utils.h:382
friend Mask< T > operator|(Mask< T > x, Mask< T > y)
Definition ct_utils.h:528
Mask< T > & operator^=(Mask< T > o)
Definition ct_utils.h:502
Mask(Mask< T > &&other)=default
constexpr T unpoisoned_value() const
Definition ct_utils.h:598
constexpr void select_n(T output[], const T x[], const T y[], size_t len) const
Definition ct_utils.h:565
friend Mask< T > operator^(Mask< T > x, Mask< T > y)
Definition ct_utils.h:523
constexpr T if_set_return(T x) const
Definition ct_utils.h:538
Mask< T > & operator=(const Mask< T > &other)=default
Mask< T > & operator=(Mask< T > &&other)=default
constexpr void _const_time_poison() const
Definition ct_utils.h:632
Mask(const Mask< T > &other)=default
static constexpr Mask< T > expand(Mask< U > m)
Definition ct_utils.h:429
Mask< T > & operator&=(Mask< T > o)
Definition ct_utils.h:494
constexpr T select_and_unpoison(T x, T y) const
Definition ct_utils.h:550
static constexpr Mask< T > expand(T v)
Definition ct_utils.h:392
constexpr T select(T x, T y) const
Definition ct_utils.h:548
static constexpr Mask< T > expand_top_bit(T v)
Definition ct_utils.h:415
static constexpr Mask< T > is_within_range(T v, T l, T u)
Definition ct_utils.h:470
constexpr CT::Choice as_choice() const
Definition ct_utils.h:619
static constexpr Mask< T > from_choice(Choice c)
Definition ct_utils.h:402
static constexpr Mask< T > is_equal(T x, T y)
Definition ct_utils.h:442
Mask< T > & operator|=(Mask< T > o)
Definition ct_utils.h:510
constexpr Mask< T > operator~() const
Definition ct_utils.h:533
static constexpr Mask< T > expand_bool(bool v)
Definition ct_utils.h:397
static constexpr Mask< T > is_gt(T x, T y)
Definition ct_utils.h:458
constexpr bool as_bool() const
Definition ct_utils.h:614
static constexpr Mask< T > is_lt(T x, T y)
Definition ct_utils.h:450
friend Mask< T > operator&(Mask< T > x, Mask< T > y)
Definition ct_utils.h:518
constexpr void _const_time_unpoison() const
Definition ct_utils.h:634
static constexpr Mask< T > is_any_of(T v, std::initializer_list< T > accepted)
Definition ct_utils.h:479
static constexpr Mask< T > is_zero(T x)
Definition ct_utils.h:437
static constexpr Mask< T > cleared()
Definition ct_utils.h:387
constexpr Option(T v)
Construct a set option with the provided value.
Definition ct_utils.h:656
constexpr Option(T v, Choice valid)
Construct an Option which contains the specified value, and is set or not.
Definition ct_utils.h:653
constexpr auto transform(F f) const -> Option< std::remove_cvref_t< std::invoke_result_t< F, const T & > > >
Definition ct_utils.h:674
constexpr Choice has_value() const
Return true if this Option contains a value.
Definition ct_utils.h:664
constexpr CT::Option< T > operator&&(CT::Choice also)
Return a new CT::Option that is set if also is set as well.
Definition ct_utils.h:719
constexpr const T & value() const
Either returns the value or throws an exception.
Definition ct_utils.h:679
constexpr Option()
Construct an unset option with a default inner value.
Definition ct_utils.h:659
constexpr std::optional< T > as_optional_vartime() const
Definition ct_utils.h:710
constexpr T value_or(T other) const
Definition ct_utils.h:688
constexpr T value_or(T other) const
Definition ct_utils.h:699
Helper class to create a RAII-style cleanup callback.
secure_vector< uint8_t > strip_leading_zeros(std::span< const uint8_t > input)
Definition ct_utils.cpp:94
constexpr void conditional_swap_ptr(bool cnd, T &x, T &y)
Definition ct_utils.h:774
decltype(auto) driveby_unpoison(T &&v)
Definition ct_utils.h:243
constexpr void conditional_swap(bool cnd, T &x, T &y)
Definition ct_utils.h:768
constexpr void poison_range(const R &r)
Definition ct_utils.h:181
constexpr void poison_all(const Ts &... ts)
Definition ct_utils.h:201
bool poison_has_effect()
Definition ct_utils.h:85
constexpr T value_barrier(T x)
decltype(auto) driveby_poison(T &&v)
Definition ct_utils.h:232
constexpr Mask< T > conditional_copy_mem(Mask< T > mask, T *dest, const T *if_set, const T *if_unset, size_t elems)
Definition ct_utils.h:732
constexpr auto scoped_poison(const Ts &... xs)
Definition ct_utils.h:222
constexpr CT::Mask< T > is_not_equal(const T x[], const T y[], size_t len)
Definition ct_utils.h:838
constexpr void unpoison_all(const Ts &... ts)
Definition ct_utils.h:207
BOTAN_TEST_API CT::Option< size_t > copy_output(CT::Choice accept, std::span< uint8_t > output, std::span< const uint8_t > input, size_t offset)
Definition ct_utils.cpp:13
size_t count_leading_zero_bytes(std::span< const uint8_t > input)
Definition ct_utils.cpp:84
constexpr CT::Mask< T > is_equal(const T x[], const T y[], size_t len)
Definition ct_utils.h:798
constexpr void unpoison_range(const R &r)
Definition ct_utils.h:189
constexpr void unpoison(const T *p, size_t n)
Definition ct_utils.h:67
constexpr CT::Mask< T > all_zeros(const T elem[], size_t len)
Definition ct_utils.h:785
constexpr Mask< T > conditional_assign_mem(T cnd, T *dest, const T *src, size_t elems)
Definition ct_utils.h:749
constexpr void poison(const T *p, size_t n)
Definition ct_utils.h:56
BOTAN_FORCE_INLINE constexpr T choose(T mask, T a, T b)
Definition bit_ops.h:216
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:68
BOTAN_FORCE_INLINE constexpr T ct_expand_top_bit(T a)
Definition bit_ops.h:28
std::conditional_t< HasNative64BitRegisters, std::uint64_t, uint32_t > word
Definition types.h:119
BOTAN_FORCE_INLINE constexpr T ct_is_zero(T x)
Definition bit_ops.h:37