Botan 3.11.0
Crypto and TLS for C&
value_barrier.h
Go to the documentation of this file.
1/*
2* (C) 2025 Jack Lloyd
3*
4* Botan is released under the Simplified BSD License (see license.txt)
5*/
6
7#ifndef BOTAN_VALUE_BARRIER_H_
8#define BOTAN_VALUE_BARRIER_H_
9
10#include <botan/internal/target_info.h>
11#include <concepts>
12#include <type_traits>
13
14namespace Botan::CT {
15
16/**
17* This function returns its argument, but (if called in a non-constexpr context)
18* attempts to prevent the compiler from reasoning about the value or the possible
19* range of values. Such optimizations have a way of breaking constant time code.
20*
21* The method that is use is decided at configuration time based on the target
22* compiler and architecture (see `ct_value_barrier` blocks in `src/build-data/cc`).
23* The decision can be overridden by the user with the configure.py option
24* `--ct-value-barrier-type=`
25*
26* There are three options currently possible in the data files and with the
27* option:
28*
29* * `asm`: Use an inline assembly expression which (currently) prevents Clang
30* and GCC from optimizing based on the possible value of the input expression.
31*
32* * `volatile`: Launder the input through a volatile variable. This is likely
33* to cause significant performance regressions since the value must be
34* actually stored and loaded back from memory each time.
35*
36* * `none`: disable constant time barriers entirely. This is used
37* with MSVC, which is not known to perform optimizations that break
38* constant time code and which does not support GCC-style inline asm.
39*
40*/
41template <std::unsigned_integral T>
42 requires(!std::same_as<bool, T>)
43constexpr inline T value_barrier(T x) {
44 if(std::is_constant_evaluated()) {
45 return x;
46 } else {
47#if defined(BOTAN_CT_VALUE_BARRIER_USE_ASM)
48 /*
49 * We may want a "stronger" statement such as
50 * asm volatile("" : "+r,m"(x) : : "memory);
51 * (see https://theunixzoo.co.uk/blog/2021-10-14-preventing-optimisations.html)
52 * however the current approach seems sufficient with current compilers,
53 * and is minimally damaging with regards to degrading code generation.
54 */
55 asm("" : "+r"(x) : /* no input */); // NOLINT(*-no-assembler)
56 return x;
57#elif defined(BOTAN_CT_VALUE_BARRIER_USE_VOLATILE)
58 volatile T vx = x;
59 return vx;
60#else
61 return x;
62#endif
63 }
64}
65
66} // namespace Botan::CT
67
68#endif
constexpr T value_barrier(T x)