Botan 3.6.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*/
251template <typename T>
252constexpr inline T value_barrier(T x) {
253 if(!std::is_constant_evaluated()) {
254 /*
255 * For compilers without inline asm, is there something else we can do?
256 *
257 * For instance we could potentially launder the value through a
258 * `volatile T` or `volatile T*`. This would require some experimentation.
259 *
260 * GCC has an attribute noipa which disables interprocedural analysis, which
261 * might be useful here. However Clang does not currently support this attribute.
262 *
263 * We may want a "stronger" statement such as
264 * asm volatile("" : "+r,m"(x) : : "memory);
265 * (see https://theunixzoo.co.uk/blog/2021-10-14-preventing-optimisations.html)
266 * however the current approach seems sufficient with current compilers,
267 * and is minimally damaging with regards to degrading code generation.
268 */
269#if defined(BOTAN_USE_GCC_INLINE_ASM) && !defined(BOTAN_HAS_SANITIZER_MEMORY)
270 asm("" : "+r"(x) : /* no input */);
271#endif
272 return x;
273 } else {
274 return x;
275 }
276}
277
278/**
279* A Choice is used for constant-time conditionals.
280*
281* Internally it always is either |0| (all 0 bits) or |1| (all 1 bits)
282* and measures are taken to block compilers from reasoning about the
283* expected value of a Choice.
284*/
286 public:
287 /**
288 * If v == 0 return an unset (false) Choice, otherwise a set Choice
289 */
290 template <typename T>
291 requires std::unsigned_integral<T> && (!std::same_as<bool, T>)
292 constexpr static Choice from_int(T v) {
293 // Mask of T that is either |0| or |1|
294 const T v_is_0 = ct_is_zero<T>(value_barrier<T>(v));
295
296 // We want the mask to be set if v != 0 so we must check that
297 // v_is_0 is itself zero.
298 //
299 // Also sizeof(T) may not equal sizeof(uint32_t) so we must
300 // use ct_is_zero<uint32_t>. It's ok to either truncate or
301 // zero extend v_is_0 to 32 bits since we know it is |0| or |1|
302 // so even just the low bit is sufficient.
303 return Choice(ct_is_zero<uint32_t>(static_cast<uint32_t>(v_is_0)));
304 }
305
306 constexpr static Choice yes() { return Choice(static_cast<uint32_t>(-1)); }
307
308 constexpr static Choice no() { return Choice(0); }
309
310 constexpr Choice operator!() const { return Choice(~value()); }
311
312 constexpr Choice operator&&(const Choice& other) const { return Choice(value() & other.value()); }
313
314 constexpr Choice operator||(const Choice& other) const { return Choice(value() | other.value()); }
315
316 constexpr Choice operator!=(const Choice& other) const { return Choice(value() ^ other.value()); }
317
318 constexpr Choice operator==(const Choice& other) const { return !(*this != other); }
319
320 /**
321 * Unsafe conversion to bool
322 *
323 * This conversion itself is (probably) constant time, but once the
324 * choice is reduced to a simple bool, it's entirely possible for the
325 * compiler to perform range analysis on the values, since there are just
326 * the two. As a consequence even if the caller is not using this in an
327 * obviously branchy way (`if(choice.as_bool()) ...`) a smart compiler
328 * may introduce branches depending on the value.
329 */
330 constexpr bool as_bool() const { return m_value != 0; }
331
332 /// Return the masked value
333 constexpr uint32_t value() const { return value_barrier(m_value); }
334
335 constexpr Choice(const Choice& other) = default;
336 constexpr Choice(Choice&& other) = default;
337 constexpr Choice& operator=(const Choice& other) noexcept = default;
338 constexpr Choice& operator=(Choice&& other) noexcept = default;
339
340 private:
341 constexpr explicit Choice(uint32_t v) : m_value(v) {}
342
343 uint32_t m_value;
344};
345
346/**
347* A concept for a type which is conditionally assignable
348*/
349template <typename T>
350concept ct_conditional_assignable = requires(T lhs, const T& rhs, Choice c) { lhs.conditional_assign(c, rhs); };
351
352/**
353* A Mask type used for constant-time operations. A Mask<T> always has value
354* either |0| (all bits cleared) or |1| (all bits set). All operations in a Mask<T>
355* are intended to compile to code which does not contain conditional jumps.
356* This must be verified with tooling (eg binary disassembly or using valgrind)
357* since you never know what a compiler might do.
358*/
359template <typename T>
360class Mask final {
361 public:
362 static_assert(std::is_unsigned<T>::value && !std::is_same<bool, T>::value,
363 "Only unsigned integer types are supported by CT::Mask");
364
365 Mask(const Mask<T>& other) = default;
366 Mask<T>& operator=(const Mask<T>& other) = default;
367
368 /**
369 * Derive a Mask from a Mask of a larger type
370 */
371 template <typename U>
372 constexpr Mask(Mask<U> o) : m_mask(static_cast<T>(o.value())) {
373 static_assert(sizeof(U) > sizeof(T), "sizes ok");
374 }
375
376 /**
377 * Return a Mask<T> of |1| (all bits set)
378 */
379 static constexpr Mask<T> set() { return Mask<T>(static_cast<T>(~0)); }
380
381 /**
382 * Return a Mask<T> of |0| (all bits cleared)
383 */
384 static constexpr Mask<T> cleared() { return Mask<T>(0); }
385
386 /**
387 * Return a Mask<T> which is set if v is != 0
388 */
389 static constexpr Mask<T> expand(T v) { return ~Mask<T>::is_zero(value_barrier<T>(v)); }
390
391 /**
392 * Return a Mask<T> which is set if choice is set
393 */
394 static constexpr Mask<T> from_choice(Choice c) {
395 if constexpr(sizeof(T) <= sizeof(uint32_t)) {
396 // Take advantage of the fact that Choice's mask is always
397 // either |0| or |1|
398 return Mask<T>(static_cast<T>(c.value()));
399 } else {
400 return ~Mask<T>::is_zero(c.value());
401 }
402 }
403
404 /**
405 * Return a Mask<T> which is set if the top bit of v is set
406 */
408
409 /**
410 * Return a Mask<T> which is set if the given @p bit of @p v is set.
411 * @p bit must be from 0 (LSB) to (sizeof(T) * 8 - 1) (MSB).
412 */
413 static constexpr Mask<T> expand_bit(T v, size_t bit) {
414 return CT::Mask<T>::expand_top_bit(v << (sizeof(v) * 8 - 1 - bit));
415 }
416
417 /**
418 * Return a Mask<T> which is set if m is set
419 */
420 template <typename U>
421 static constexpr Mask<T> expand(Mask<U> m) {
422 static_assert(sizeof(U) < sizeof(T), "sizes ok");
423 return ~Mask<T>::is_zero(m.value());
424 }
425
426 /**
427 * Return a Mask<T> which is set if v is == 0 or cleared otherwise
428 */
429 static constexpr Mask<T> is_zero(T x) { return Mask<T>(ct_is_zero<T>(value_barrier<T>(x))); }
430
431 /**
432 * Return a Mask<T> which is set if x == y
433 */
434 static constexpr Mask<T> is_equal(T x, T y) {
435 const T diff = value_barrier(x) ^ value_barrier(y);
436 return Mask<T>::is_zero(diff);
437 }
438
439 /**
440 * Return a Mask<T> which is set if x < y
441 */
442 static constexpr Mask<T> is_lt(T x, T y) {
443 T u = x ^ ((x ^ y) | ((x - y) ^ x));
444 return Mask<T>::expand_top_bit(u);
445 }
446
447 /**
448 * Return a Mask<T> which is set if x > y
449 */
450 static constexpr Mask<T> is_gt(T x, T y) { return Mask<T>::is_lt(y, x); }
451
452 /**
453 * Return a Mask<T> which is set if x <= y
454 */
455 static constexpr Mask<T> is_lte(T x, T y) { return ~Mask<T>::is_gt(x, y); }
456
457 /**
458 * Return a Mask<T> which is set if x >= y
459 */
460 static constexpr Mask<T> is_gte(T x, T y) { return ~Mask<T>::is_lt(x, y); }
461
462 static constexpr Mask<T> is_within_range(T v, T l, T u) {
463 //return Mask<T>::is_gte(v, l) & Mask<T>::is_lte(v, u);
464
465 const T v_lt_l = v ^ ((v ^ l) | ((v - l) ^ v));
466 const T v_gt_u = u ^ ((u ^ v) | ((u - v) ^ u));
467 const T either = value_barrier(v_lt_l) | value_barrier(v_gt_u);
468 return ~Mask<T>::expand_top_bit(either);
469 }
470
471 static constexpr Mask<T> is_any_of(T v, std::initializer_list<T> accepted) {
472 T accept = 0;
473
474 for(auto a : accepted) {
475 const T diff = a ^ v;
476 const T eq_zero = value_barrier<T>(~diff & (diff - 1));
477 accept |= eq_zero;
478 }
479
480 return Mask<T>::expand_top_bit(accept);
481 }
482
483 /**
484 * AND-combine two masks
485 */
487 m_mask &= o.value();
488 return (*this);
489 }
490
491 /**
492 * XOR-combine two masks
493 */
495 m_mask ^= o.value();
496 return (*this);
497 }
498
499 /**
500 * OR-combine two masks
501 */
503 m_mask |= o.value();
504 return (*this);
505 }
506
507 /**
508 * AND-combine two masks
509 */
510 friend Mask<T> operator&(Mask<T> x, Mask<T> y) { return Mask<T>(x.value() & y.value()); }
511
512 /**
513 * XOR-combine two masks
514 */
515 friend Mask<T> operator^(Mask<T> x, Mask<T> y) { return Mask<T>(x.value() ^ y.value()); }
516
517 /**
518 * OR-combine two masks
519 */
520 friend Mask<T> operator|(Mask<T> x, Mask<T> y) { return Mask<T>(x.value() | y.value()); }
521
522 /**
523 * Negate this mask
524 */
525 constexpr Mask<T> operator~() const { return Mask<T>(~value()); }
526
527 /**
528 * Return x if the mask is set, or otherwise zero
529 */
530 constexpr T if_set_return(T x) const { return value() & x; }
531
532 /**
533 * Return x if the mask is cleared, or otherwise zero
534 */
535 constexpr T if_not_set_return(T x) const { return ~value() & x; }
536
537 /**
538 * If this mask is set, return x, otherwise return y
539 */
540 constexpr T select(T x, T y) const { return choose(value(), x, y); }
541
542 constexpr T select_and_unpoison(T x, T y) const {
543 T r = this->select(x, y);
544 CT::unpoison(r);
545 return r;
546 }
547
548 /**
549 * If this mask is set, return x, otherwise return y
550 */
551 Mask<T> select_mask(Mask<T> x, Mask<T> y) const { return Mask<T>(select(x.value(), y.value())); }
552
553 /**
554 * Conditionally set output to x or y, depending on if mask is set or
555 * cleared (resp)
556 */
557 constexpr void select_n(T output[], const T x[], const T y[], size_t len) const {
558 const T mask = value();
559 for(size_t i = 0; i != len; ++i) {
560 output[i] = choose(mask, x[i], y[i]);
561 }
562 }
563
564 /**
565 * If this mask is set, zero out buf, otherwise do nothing
566 */
567 constexpr void if_set_zero_out(T buf[], size_t elems) {
568 for(size_t i = 0; i != elems; ++i) {
569 buf[i] = this->if_not_set_return(buf[i]);
570 }
571 }
572
573 /**
574 * Return the value of the mask, unpoisoned
575 */
576 constexpr T unpoisoned_value() const {
577 T r = value();
578 CT::unpoison(r);
579 return r;
580 }
581
582 /**
583 * Unsafe conversion to bool
584 *
585 * This conversion itself is (probably) constant time, but once the
586 * mask is reduced to a simple bool, it's entirely possible for the
587 * compiler to perform range analysis on the values, since there are just
588 * the two. As a consequence even if the caller is not using this in an
589 * obviously branchy way (`if(mask.as_bool()) ...`) a smart compiler
590 * may introduce branches depending on the value.
591 */
592 constexpr bool as_bool() const { return unpoisoned_value() != 0; }
593
594 /**
595 * Return a Choice based on this mask
596 */
598
599 /**
600 * Return the underlying value of the mask
601 */
602 constexpr T value() const { return value_barrier<T>(m_mask); }
603
604 constexpr void _const_time_poison() const { CT::poison(m_mask); }
605
606 constexpr void _const_time_unpoison() const { CT::unpoison(m_mask); }
607
608 private:
609 constexpr Mask(T m) : m_mask(m) {}
610
611 T m_mask;
612};
613
614/**
615* A CT::Option<T> is either a valid T, or not
616*
617* To maintain constant time behavior a value must always be stored.
618* A CT::Choice tracks if the value is valid or not. It is not possible
619* to access the inner value if the Choice is unset.
620*/
621template <typename T>
622class Option {
623 public:
624 /// Construct an Option which contains the specified value, and is set or not
625 constexpr Option(T v, Choice valid) : m_has_value(valid), m_value(std::move(v)) {}
626
627 /// Construct a set option with the provided value
628 constexpr Option(T v) : Option(std::move(v), Choice::yes()) {}
629
630 /// Construct an unset option with a default inner value
631 constexpr Option()
632 requires std::default_initializable<T>
633 : Option(T(), Choice::no()) {}
634
635 /// Return true if this Option contains a value
636 constexpr Choice has_value() const { return m_has_value; }
637
638 /**
639 * Apply a function to the inner value and return a new Option
640 * which contains that value. This is constant time only if @p f is.
641 *
642 * @note The function will always be called, even if the Option is None. It
643 * must be prepared to handle any possible state of T.
644 */
645 template <std::invocable<const T&> F>
647 return {f(m_value), m_has_value};
648 }
649
650 /// Either returns the value or throws an exception
651 constexpr const T& value() const {
652 BOTAN_STATE_CHECK(m_has_value.as_bool());
653 return m_value;
654 }
655
656 /// Returns either the inner value or the alternative, in constant time
657 ///
658 /// This variant is used for types which explicitly define a function
659 /// conditional_assign which takes a CT::Choice as the conditional.
660 constexpr T value_or(T other) const
662 {
663 other.conditional_assign(m_has_value, m_value);
664 return other;
665 }
666
667 /// Returns either the inner value or the alternative, in constant time
668 ///
669 /// This variant is used for integer types where CT::Mask can perform
670 /// a constant time selection
671 constexpr T value_or(T other) const
672 requires std::unsigned_integral<T>
673 {
674 auto mask = CT::Mask<T>::from_choice(m_has_value);
675 return mask.select(m_value, other);
676 }
677
678 /// Convert this Option into a std::optional
679 ///
680 /// This is not constant time, leaking if the Option had a
681 /// value or not
682 constexpr std::optional<T> as_optional_vartime() const {
683 if(m_has_value.as_bool()) {
684 return {m_value};
685 } else {
686 return {};
687 }
688 }
689
690 /// Return a new CT::Option that is set if @p also is set as well
691 constexpr CT::Option<T> operator&&(CT::Choice also) { return CT::Option<T>(m_value, m_has_value && also); }
692
693 private:
694 Choice m_has_value;
695 T m_value;
696};
697
698template <typename T>
699constexpr inline Mask<T> conditional_copy_mem(Mask<T> mask, T* to, const T* from0, const T* from1, size_t elems) {
700 mask.select_n(to, from0, from1, elems);
701 return mask;
702}
703
704template <typename T>
705constexpr inline Mask<T> conditional_copy_mem(T cnd, T* to, const T* from0, const T* from1, size_t elems) {
706 const auto mask = CT::Mask<T>::expand(cnd);
707 return CT::conditional_copy_mem(mask, to, from0, from1, elems);
708}
709
710template <typename T>
711constexpr inline Mask<T> conditional_assign_mem(T cnd, T* sink, const T* src, size_t elems) {
712 const auto mask = CT::Mask<T>::expand(cnd);
713 mask.select_n(sink, src, sink, elems);
714 return mask;
715}
716
717template <typename T>
718constexpr inline Mask<T> conditional_assign_mem(Choice cnd, T* sink, const T* src, size_t elems) {
719 const auto mask = CT::Mask<T>::from_choice(cnd);
720 mask.select_n(sink, src, sink, elems);
721 return mask;
722}
723
724template <typename T>
725constexpr inline void conditional_swap(bool cnd, T& x, T& y) {
726 const auto swap = CT::Mask<T>::expand(cnd);
727
728 T t0 = swap.select(y, x);
729 T t1 = swap.select(x, y);
730 x = t0;
731 y = t1;
732}
733
734template <typename T>
735constexpr inline void conditional_swap_ptr(bool cnd, T& x, T& y) {
736 uintptr_t xp = reinterpret_cast<uintptr_t>(x);
737 uintptr_t yp = reinterpret_cast<uintptr_t>(y);
738
739 conditional_swap<uintptr_t>(cnd, xp, yp);
740
741 x = reinterpret_cast<T>(xp);
742 y = reinterpret_cast<T>(yp);
743}
744
745template <typename T>
746constexpr inline CT::Mask<T> all_zeros(const T elem[], size_t len) {
747 T sum = 0;
748 for(size_t i = 0; i != len; ++i) {
749 sum |= elem[i];
750 }
751 return CT::Mask<T>::is_zero(sum);
752}
753
754/**
755* Compare two arrays of equal size and return a Mask indicating if
756* they are equal or not. The mask is set if they are identical.
757*/
758template <typename T>
759constexpr inline CT::Mask<T> is_equal(const T x[], const T y[], size_t len) {
760 if(std::is_constant_evaluated()) {
761 T difference = 0;
762
763 for(size_t i = 0; i != len; ++i) {
764 difference = difference | (x[i] ^ y[i]);
765 }
766
767 return CT::Mask<T>::is_zero(difference);
768 } else {
769 volatile T difference = 0;
770
771 for(size_t i = 0; i != len; ++i) {
772 difference = difference | (x[i] ^ y[i]);
773 }
774
775 return CT::Mask<T>::is_zero(difference);
776 }
777}
778
779/**
780* Compare two arrays of equal size and return a Mask indicating if
781* they are equal or not. The mask is set if they differ.
782*/
783template <typename T>
784constexpr inline CT::Mask<T> is_not_equal(const T x[], const T y[], size_t len) {
785 return ~CT::is_equal(x, y, len);
786}
787
788/**
789* Constant time conditional copy out with offset
790*
791* If accept is set and offset <= input_length, sets output[0..] to
792* input[offset:input_length] and returns input_length - offset. The
793* remaining bytes of output are zeroized.
794*
795* Otherwise, output is zeroized, and returns an empty Ct::Option
796*
797* The input and output spans may not overlap, and output must be at
798* least as large as input.
799*
800* This function attempts to avoid leaking the following to side channels
801* - if accept was set or not
802* - the value of offset
803* - the value of input
804*
805* This function leaks the length of the input
806*/
809 std::span<uint8_t> output,
810 std::span<const uint8_t> input,
811 size_t offset);
812
813size_t count_leading_zero_bytes(std::span<const uint8_t> input);
814
815secure_vector<uint8_t> strip_leading_zeros(std::span<const uint8_t> input);
816
817} // namespace Botan::CT
818
819#endif
#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:318
static constexpr Choice yes()
Definition ct_utils.h:306
static constexpr Choice from_int(T v)
Definition ct_utils.h:292
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:316
constexpr Choice operator||(const Choice &other) const
Definition ct_utils.h:314
constexpr Choice operator!() const
Definition ct_utils.h:310
static constexpr Choice no()
Definition ct_utils.h:308
constexpr bool as_bool() const
Definition ct_utils.h:330
constexpr Choice(Choice &&other)=default
constexpr Choice operator&&(const Choice &other) const
Definition ct_utils.h:312
constexpr uint32_t value() const
Return the masked value.
Definition ct_utils.h:333
constexpr Choice & operator=(Choice &&other) noexcept=default
static constexpr Mask< T > expand_bit(T v, size_t bit)
Definition ct_utils.h:413
Mask< T > select_mask(Mask< T > x, Mask< T > y) const
Definition ct_utils.h:551
constexpr T value() const
Definition ct_utils.h:602
constexpr void if_set_zero_out(T buf[], size_t elems)
Definition ct_utils.h:567
static constexpr Mask< T > is_lte(T x, T y)
Definition ct_utils.h:455
static constexpr Mask< T > is_gte(T x, T y)
Definition ct_utils.h:460
constexpr T if_not_set_return(T x) const
Definition ct_utils.h:535
constexpr Mask(Mask< U > o)
Definition ct_utils.h:372
static constexpr Mask< T > set()
Definition ct_utils.h:379
friend Mask< T > operator|(Mask< T > x, Mask< T > y)
Definition ct_utils.h:520
Mask< T > & operator^=(Mask< T > o)
Definition ct_utils.h:494
constexpr T unpoisoned_value() const
Definition ct_utils.h:576
constexpr void select_n(T output[], const T x[], const T y[], size_t len) const
Definition ct_utils.h:557
friend Mask< T > operator^(Mask< T > x, Mask< T > y)
Definition ct_utils.h:515
constexpr T if_set_return(T x) const
Definition ct_utils.h:530
Mask< T > & operator=(const Mask< T > &other)=default
constexpr void _const_time_poison() const
Definition ct_utils.h:604
Mask(const Mask< T > &other)=default
static constexpr Mask< T > expand(Mask< U > m)
Definition ct_utils.h:421
Mask< T > & operator&=(Mask< T > o)
Definition ct_utils.h:486
constexpr T select_and_unpoison(T x, T y) const
Definition ct_utils.h:542
static constexpr Mask< T > expand(T v)
Definition ct_utils.h:389
constexpr T select(T x, T y) const
Definition ct_utils.h:540
static constexpr Mask< T > expand_top_bit(T v)
Definition ct_utils.h:407
static constexpr Mask< T > is_within_range(T v, T l, T u)
Definition ct_utils.h:462
constexpr CT::Choice as_choice() const
Definition ct_utils.h:597
static constexpr Mask< T > from_choice(Choice c)
Definition ct_utils.h:394
static constexpr Mask< T > is_equal(T x, T y)
Definition ct_utils.h:434
Mask< T > & operator|=(Mask< T > o)
Definition ct_utils.h:502
constexpr Mask< T > operator~() const
Definition ct_utils.h:525
static constexpr Mask< T > is_gt(T x, T y)
Definition ct_utils.h:450
constexpr bool as_bool() const
Definition ct_utils.h:592
static constexpr Mask< T > is_lt(T x, T y)
Definition ct_utils.h:442
friend Mask< T > operator&(Mask< T > x, Mask< T > y)
Definition ct_utils.h:510
constexpr void _const_time_unpoison() const
Definition ct_utils.h:606
static constexpr Mask< T > is_any_of(T v, std::initializer_list< T > accepted)
Definition ct_utils.h:471
static constexpr Mask< T > is_zero(T x)
Definition ct_utils.h:429
static constexpr Mask< T > cleared()
Definition ct_utils.h:384
constexpr Option(T v)
Construct a set option with the provided value.
Definition ct_utils.h:628
constexpr Option(T v, Choice valid)
Construct an Option which contains the specified value, and is set or not.
Definition ct_utils.h:625
constexpr auto transform(F f) const -> Option< std::remove_cvref_t< std::invoke_result_t< F, const T & > > >
Definition ct_utils.h:646
constexpr Choice has_value() const
Return true if this Option contains a value.
Definition ct_utils.h:636
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:691
constexpr const T & value() const
Either returns the value or throws an exception.
Definition ct_utils.h:651
constexpr Option()
Construct an unset option with a default inner value.
Definition ct_utils.h:631
constexpr std::optional< T > as_optional_vartime() const
Definition ct_utils.h:682
constexpr T value_or(T other) const
Definition ct_utils.h:660
constexpr T value_or(T other) const
Definition ct_utils.h:671
Helper class to create a RAII-style cleanup callback.
Definition stl_util.h:354
int(* final)(unsigned char *, CTX *)
#define BOTAN_TEST_API
Definition compiler.h:51
FE_25519 T
Definition ge.cpp:34
constexpr T value_barrier(T x)
Definition ct_utils.h:252
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:735
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:725
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:711
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:699
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:784
constexpr void poison_all(Ts &&... ts)
Definition ct_utils.h:195
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:759
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:746
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:193
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:61
constexpr T ct_is_zero(T x)
Definition bit_ops.h:33
constexpr T expand_top_bit(T a)
Definition bit_ops.h:23