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