Trail of Bits Blog
Follow
Constant-time support lands in LLVM: Protecting cryptographic code at the compiler level
Trail of Bits developed constant-time coding support for LLVM 21, providing compiler-level guarantees that protect cryptographic code against branching-related timing attacks, addressing a critical vulnerability where aggressive modern compilers inadvertently introduce data-dependent branches during optimization. The core solution is the __builtin_ct_select intrinsic, which translates into a special LLVM intermediate representation (llvm.ct.select.*) acting as a security barrier, instructing the compiler to preserve the operation's constant-time properties throughout the entire compilation pipeline. Without this intrinsic, carefully crafted constant-time code, such as those used in lookup tables, can be broken by standard compiler optimizations that introduce speculative branching, creating exploitable timing side channels detectable even with minimal cycle variations. This work directly addresses findings from studies like "Breaking Bad," which documented systematic constant-time guarantee failures in numerous production cryptographic libraries caused by compilers. The __builtin_ct_select intrinsic ensures constant-time execution across various architectures—using cmov on x86-64, CSEL on AArch64, and masked arithmetic on platforms lacking constant-time instructions—allowing developers to write portable and secure code. Upstreaming these changes involved extensive community engagement, leading to strong interest from projects like Rust Crypto and PuTTY, who plan to replace complex inline assembly workarounds with these new primitives. Initial benchmarking confirms minimal performance overhead while achieving 100% preservation of constant-time properties across all tested optimization levels, successfully integrating with major cryptographic libraries. Future plans include extending support with additional intrinsics, such as __builtin_ct_expr for forcing entire expressions to evaluate without branches, and enabling adoption in languages like Rust, Swift, and WebAssembly that target LLVM.