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