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