1a8e1175bSopenharmony_ci/** 2a8e1175bSopenharmony_ci * Constant-time functions 3a8e1175bSopenharmony_ci * 4a8e1175bSopenharmony_ci * Copyright The Mbed TLS Contributors 5a8e1175bSopenharmony_ci * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later 6a8e1175bSopenharmony_ci */ 7a8e1175bSopenharmony_ci 8a8e1175bSopenharmony_ci#ifndef MBEDTLS_CONSTANT_TIME_IMPL_H 9a8e1175bSopenharmony_ci#define MBEDTLS_CONSTANT_TIME_IMPL_H 10a8e1175bSopenharmony_ci 11a8e1175bSopenharmony_ci#include <stddef.h> 12a8e1175bSopenharmony_ci 13a8e1175bSopenharmony_ci#include "common.h" 14a8e1175bSopenharmony_ci 15a8e1175bSopenharmony_ci#if defined(MBEDTLS_BIGNUM_C) 16a8e1175bSopenharmony_ci#include "mbedtls/bignum.h" 17a8e1175bSopenharmony_ci#endif 18a8e1175bSopenharmony_ci 19a8e1175bSopenharmony_ci/* 20a8e1175bSopenharmony_ci * To improve readability of constant_time_internal.h, the static inline 21a8e1175bSopenharmony_ci * definitions are here, and constant_time_internal.h has only the declarations. 22a8e1175bSopenharmony_ci * 23a8e1175bSopenharmony_ci * This results in duplicate declarations of the form: 24a8e1175bSopenharmony_ci * static inline void f(); // from constant_time_internal.h 25a8e1175bSopenharmony_ci * static inline void f() { ... } // from constant_time_impl.h 26a8e1175bSopenharmony_ci * when constant_time_internal.h is included. 27a8e1175bSopenharmony_ci * 28a8e1175bSopenharmony_ci * This appears to behave as if the declaration-without-definition was not present 29a8e1175bSopenharmony_ci * (except for warnings if gcc -Wredundant-decls or similar is used). 30a8e1175bSopenharmony_ci * 31a8e1175bSopenharmony_ci * Disable -Wredundant-decls so that gcc does not warn about this. This is re-enabled 32a8e1175bSopenharmony_ci * at the bottom of this file. 33a8e1175bSopenharmony_ci */ 34a8e1175bSopenharmony_ci#if defined(MBEDTLS_COMPILER_IS_GCC) && (__GNUC__ > 4) 35a8e1175bSopenharmony_ci #pragma GCC diagnostic push 36a8e1175bSopenharmony_ci #pragma GCC diagnostic ignored "-Wredundant-decls" 37a8e1175bSopenharmony_ci#endif 38a8e1175bSopenharmony_ci 39a8e1175bSopenharmony_ci/* Disable asm under Memsan because it confuses Memsan and generates false errors. 40a8e1175bSopenharmony_ci * 41a8e1175bSopenharmony_ci * We also disable under Valgrind by default, because it's more useful 42a8e1175bSopenharmony_ci * for Valgrind to test the plain C implementation. MBEDTLS_TEST_CONSTANT_FLOW_ASM //no-check-names 43a8e1175bSopenharmony_ci * may be set to permit building asm under Valgrind. 44a8e1175bSopenharmony_ci */ 45a8e1175bSopenharmony_ci#if defined(MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN) || \ 46a8e1175bSopenharmony_ci (defined(MBEDTLS_TEST_CONSTANT_FLOW_VALGRIND) && !defined(MBEDTLS_TEST_CONSTANT_FLOW_ASM)) //no-check-names 47a8e1175bSopenharmony_ci#define MBEDTLS_CT_NO_ASM 48a8e1175bSopenharmony_ci#elif defined(__has_feature) 49a8e1175bSopenharmony_ci#if __has_feature(memory_sanitizer) 50a8e1175bSopenharmony_ci#define MBEDTLS_CT_NO_ASM 51a8e1175bSopenharmony_ci#endif 52a8e1175bSopenharmony_ci#endif 53a8e1175bSopenharmony_ci 54a8e1175bSopenharmony_ci/* armcc5 --gnu defines __GNUC__ but doesn't support GNU's extended asm */ 55a8e1175bSopenharmony_ci#if defined(MBEDTLS_HAVE_ASM) && defined(__GNUC__) && (!defined(__ARMCC_VERSION) || \ 56a8e1175bSopenharmony_ci __ARMCC_VERSION >= 6000000) && !defined(MBEDTLS_CT_NO_ASM) 57a8e1175bSopenharmony_ci#define MBEDTLS_CT_ASM 58a8e1175bSopenharmony_ci#if (defined(__arm__) || defined(__thumb__) || defined(__thumb2__)) 59a8e1175bSopenharmony_ci#define MBEDTLS_CT_ARM_ASM 60a8e1175bSopenharmony_ci#elif defined(__aarch64__) 61a8e1175bSopenharmony_ci#define MBEDTLS_CT_AARCH64_ASM 62a8e1175bSopenharmony_ci#elif defined(__amd64__) || defined(__x86_64__) 63a8e1175bSopenharmony_ci#define MBEDTLS_CT_X86_64_ASM 64a8e1175bSopenharmony_ci#elif defined(__i386__) 65a8e1175bSopenharmony_ci#define MBEDTLS_CT_X86_ASM 66a8e1175bSopenharmony_ci#endif 67a8e1175bSopenharmony_ci#endif 68a8e1175bSopenharmony_ci 69a8e1175bSopenharmony_ci#define MBEDTLS_CT_SIZE (sizeof(mbedtls_ct_uint_t) * 8) 70a8e1175bSopenharmony_ci 71a8e1175bSopenharmony_ci 72a8e1175bSopenharmony_ci/* ============================================================================ 73a8e1175bSopenharmony_ci * Core const-time primitives 74a8e1175bSopenharmony_ci */ 75a8e1175bSopenharmony_ci 76a8e1175bSopenharmony_ci/* Ensure that the compiler cannot know the value of x (i.e., cannot optimise 77a8e1175bSopenharmony_ci * based on its value) after this function is called. 78a8e1175bSopenharmony_ci * 79a8e1175bSopenharmony_ci * If we are not using assembly, this will be fairly inefficient, so its use 80a8e1175bSopenharmony_ci * should be minimised. 81a8e1175bSopenharmony_ci */ 82a8e1175bSopenharmony_ci 83a8e1175bSopenharmony_ci#if !defined(MBEDTLS_CT_ASM) 84a8e1175bSopenharmony_ciextern volatile mbedtls_ct_uint_t mbedtls_ct_zero; 85a8e1175bSopenharmony_ci#endif 86a8e1175bSopenharmony_ci 87a8e1175bSopenharmony_ci/** 88a8e1175bSopenharmony_ci * \brief Ensure that a value cannot be known at compile time. 89a8e1175bSopenharmony_ci * 90a8e1175bSopenharmony_ci * \param x The value to hide from the compiler. 91a8e1175bSopenharmony_ci * \return The same value that was passed in, such that the compiler 92a8e1175bSopenharmony_ci * cannot prove its value (even for calls of the form 93a8e1175bSopenharmony_ci * x = mbedtls_ct_compiler_opaque(1), x will be unknown). 94a8e1175bSopenharmony_ci * 95a8e1175bSopenharmony_ci * \note This is mainly used in constructing mbedtls_ct_condition_t 96a8e1175bSopenharmony_ci * values and performing operations over them, to ensure that 97a8e1175bSopenharmony_ci * there is no way for the compiler to ever know anything about 98a8e1175bSopenharmony_ci * the value of an mbedtls_ct_condition_t. 99a8e1175bSopenharmony_ci */ 100a8e1175bSopenharmony_cistatic inline mbedtls_ct_uint_t mbedtls_ct_compiler_opaque(mbedtls_ct_uint_t x) 101a8e1175bSopenharmony_ci{ 102a8e1175bSopenharmony_ci#if defined(MBEDTLS_CT_ASM) 103a8e1175bSopenharmony_ci asm volatile ("" : [x] "+r" (x) :); 104a8e1175bSopenharmony_ci return x; 105a8e1175bSopenharmony_ci#else 106a8e1175bSopenharmony_ci return x ^ mbedtls_ct_zero; 107a8e1175bSopenharmony_ci#endif 108a8e1175bSopenharmony_ci} 109a8e1175bSopenharmony_ci 110a8e1175bSopenharmony_ci/* 111a8e1175bSopenharmony_ci * Selecting unified syntax is needed for gcc, and harmless on clang. 112a8e1175bSopenharmony_ci * 113a8e1175bSopenharmony_ci * This is needed because on Thumb 1, condition flags are always set, so 114a8e1175bSopenharmony_ci * e.g. "negs" is supported but "neg" is not (on Thumb 2, both exist). 115a8e1175bSopenharmony_ci * 116a8e1175bSopenharmony_ci * Under Thumb 1 unified syntax, only the "negs" form is accepted, and 117a8e1175bSopenharmony_ci * under divided syntax, only the "neg" form is accepted. clang only 118a8e1175bSopenharmony_ci * supports unified syntax. 119a8e1175bSopenharmony_ci * 120a8e1175bSopenharmony_ci * On Thumb 2 and Arm, both compilers are happy with the "s" suffix, 121a8e1175bSopenharmony_ci * although we don't actually care about setting the flags. 122a8e1175bSopenharmony_ci * 123a8e1175bSopenharmony_ci * For old versions of gcc (see #8516 for details), restore divided 124a8e1175bSopenharmony_ci * syntax afterwards - otherwise old versions of gcc seem to apply 125a8e1175bSopenharmony_ci * unified syntax globally, which breaks other asm code. 126a8e1175bSopenharmony_ci */ 127a8e1175bSopenharmony_ci#if defined(MBEDTLS_COMPILER_IS_GCC) && defined(__thumb__) && !defined(__thumb2__) && \ 128a8e1175bSopenharmony_ci (__GNUC__ < 11) && !defined(__ARM_ARCH_2__) 129a8e1175bSopenharmony_ci#define RESTORE_ASM_SYNTAX ".syntax divided \n\t" 130a8e1175bSopenharmony_ci#else 131a8e1175bSopenharmony_ci#define RESTORE_ASM_SYNTAX 132a8e1175bSopenharmony_ci#endif 133a8e1175bSopenharmony_ci 134a8e1175bSopenharmony_ci/* Convert a number into a condition in constant time. */ 135a8e1175bSopenharmony_cistatic inline mbedtls_ct_condition_t mbedtls_ct_bool(mbedtls_ct_uint_t x) 136a8e1175bSopenharmony_ci{ 137a8e1175bSopenharmony_ci /* 138a8e1175bSopenharmony_ci * Define mask-generation code that, as far as possible, will not use branches or conditional instructions. 139a8e1175bSopenharmony_ci * 140a8e1175bSopenharmony_ci * For some platforms / type sizes, we define assembly to assure this. 141a8e1175bSopenharmony_ci * 142a8e1175bSopenharmony_ci * Otherwise, we define a plain C fallback which (in May 2023) does not get optimised into 143a8e1175bSopenharmony_ci * conditional instructions or branches by trunk clang, gcc, or MSVC v19. 144a8e1175bSopenharmony_ci */ 145a8e1175bSopenharmony_ci#if defined(MBEDTLS_CT_AARCH64_ASM) && (defined(MBEDTLS_CT_SIZE_32) || defined(MBEDTLS_CT_SIZE_64)) 146a8e1175bSopenharmony_ci mbedtls_ct_uint_t s; 147a8e1175bSopenharmony_ci asm volatile ("neg %x[s], %x[x] \n\t" 148a8e1175bSopenharmony_ci "orr %x[x], %x[s], %x[x] \n\t" 149a8e1175bSopenharmony_ci "asr %x[x], %x[x], 63 \n\t" 150a8e1175bSopenharmony_ci : 151a8e1175bSopenharmony_ci [s] "=&r" (s), 152a8e1175bSopenharmony_ci [x] "+&r" (x) 153a8e1175bSopenharmony_ci : 154a8e1175bSopenharmony_ci : 155a8e1175bSopenharmony_ci ); 156a8e1175bSopenharmony_ci return (mbedtls_ct_condition_t) x; 157a8e1175bSopenharmony_ci#elif defined(MBEDTLS_CT_ARM_ASM) && defined(MBEDTLS_CT_SIZE_32) 158a8e1175bSopenharmony_ci uint32_t s; 159a8e1175bSopenharmony_ci asm volatile (".syntax unified \n\t" 160a8e1175bSopenharmony_ci "negs %[s], %[x] \n\t" 161a8e1175bSopenharmony_ci "orrs %[x], %[x], %[s] \n\t" 162a8e1175bSopenharmony_ci "asrs %[x], %[x], #31 \n\t" 163a8e1175bSopenharmony_ci RESTORE_ASM_SYNTAX 164a8e1175bSopenharmony_ci : 165a8e1175bSopenharmony_ci [s] "=&l" (s), 166a8e1175bSopenharmony_ci [x] "+&l" (x) 167a8e1175bSopenharmony_ci : 168a8e1175bSopenharmony_ci : 169a8e1175bSopenharmony_ci "cc" /* clobbers flag bits */ 170a8e1175bSopenharmony_ci ); 171a8e1175bSopenharmony_ci return (mbedtls_ct_condition_t) x; 172a8e1175bSopenharmony_ci#elif defined(MBEDTLS_CT_X86_64_ASM) && (defined(MBEDTLS_CT_SIZE_32) || defined(MBEDTLS_CT_SIZE_64)) 173a8e1175bSopenharmony_ci uint64_t s; 174a8e1175bSopenharmony_ci asm volatile ("mov %[x], %[s] \n\t" 175a8e1175bSopenharmony_ci "neg %[s] \n\t" 176a8e1175bSopenharmony_ci "or %[x], %[s] \n\t" 177a8e1175bSopenharmony_ci "sar $63, %[s] \n\t" 178a8e1175bSopenharmony_ci : 179a8e1175bSopenharmony_ci [s] "=&a" (s) 180a8e1175bSopenharmony_ci : 181a8e1175bSopenharmony_ci [x] "D" (x) 182a8e1175bSopenharmony_ci : 183a8e1175bSopenharmony_ci ); 184a8e1175bSopenharmony_ci return (mbedtls_ct_condition_t) s; 185a8e1175bSopenharmony_ci#elif defined(MBEDTLS_CT_X86_ASM) && defined(MBEDTLS_CT_SIZE_32) 186a8e1175bSopenharmony_ci uint32_t s; 187a8e1175bSopenharmony_ci asm volatile ("mov %[x], %[s] \n\t" 188a8e1175bSopenharmony_ci "neg %[s] \n\t" 189a8e1175bSopenharmony_ci "or %[s], %[x] \n\t" 190a8e1175bSopenharmony_ci "sar $31, %[x] \n\t" 191a8e1175bSopenharmony_ci : 192a8e1175bSopenharmony_ci [s] "=&c" (s), 193a8e1175bSopenharmony_ci [x] "+&a" (x) 194a8e1175bSopenharmony_ci : 195a8e1175bSopenharmony_ci : 196a8e1175bSopenharmony_ci ); 197a8e1175bSopenharmony_ci return (mbedtls_ct_condition_t) x; 198a8e1175bSopenharmony_ci#else 199a8e1175bSopenharmony_ci const mbedtls_ct_uint_t xo = mbedtls_ct_compiler_opaque(x); 200a8e1175bSopenharmony_ci#if defined(_MSC_VER) 201a8e1175bSopenharmony_ci /* MSVC has a warning about unary minus on unsigned, but this is 202a8e1175bSopenharmony_ci * well-defined and precisely what we want to do here */ 203a8e1175bSopenharmony_ci#pragma warning( push ) 204a8e1175bSopenharmony_ci#pragma warning( disable : 4146 ) 205a8e1175bSopenharmony_ci#endif 206a8e1175bSopenharmony_ci // y is negative (i.e., top bit set) iff x is non-zero 207a8e1175bSopenharmony_ci mbedtls_ct_int_t y = (-xo) | -(xo >> 1); 208a8e1175bSopenharmony_ci 209a8e1175bSopenharmony_ci // extract only the sign bit of y so that y == 1 (if x is non-zero) or 0 (if x is zero) 210a8e1175bSopenharmony_ci y = (((mbedtls_ct_uint_t) y) >> (MBEDTLS_CT_SIZE - 1)); 211a8e1175bSopenharmony_ci 212a8e1175bSopenharmony_ci // -y has all bits set (if x is non-zero), or all bits clear (if x is zero) 213a8e1175bSopenharmony_ci return (mbedtls_ct_condition_t) (-y); 214a8e1175bSopenharmony_ci#if defined(_MSC_VER) 215a8e1175bSopenharmony_ci#pragma warning( pop ) 216a8e1175bSopenharmony_ci#endif 217a8e1175bSopenharmony_ci#endif 218a8e1175bSopenharmony_ci} 219a8e1175bSopenharmony_ci 220a8e1175bSopenharmony_cistatic inline mbedtls_ct_uint_t mbedtls_ct_if(mbedtls_ct_condition_t condition, 221a8e1175bSopenharmony_ci mbedtls_ct_uint_t if1, 222a8e1175bSopenharmony_ci mbedtls_ct_uint_t if0) 223a8e1175bSopenharmony_ci{ 224a8e1175bSopenharmony_ci#if defined(MBEDTLS_CT_AARCH64_ASM) && (defined(MBEDTLS_CT_SIZE_32) || defined(MBEDTLS_CT_SIZE_64)) 225a8e1175bSopenharmony_ci asm volatile ("and %x[if1], %x[if1], %x[condition] \n\t" 226a8e1175bSopenharmony_ci "mvn %x[condition], %x[condition] \n\t" 227a8e1175bSopenharmony_ci "and %x[condition], %x[condition], %x[if0] \n\t" 228a8e1175bSopenharmony_ci "orr %x[condition], %x[if1], %x[condition]" 229a8e1175bSopenharmony_ci : 230a8e1175bSopenharmony_ci [condition] "+&r" (condition), 231a8e1175bSopenharmony_ci [if1] "+&r" (if1) 232a8e1175bSopenharmony_ci : 233a8e1175bSopenharmony_ci [if0] "r" (if0) 234a8e1175bSopenharmony_ci : 235a8e1175bSopenharmony_ci ); 236a8e1175bSopenharmony_ci return (mbedtls_ct_uint_t) condition; 237a8e1175bSopenharmony_ci#elif defined(MBEDTLS_CT_ARM_ASM) && defined(MBEDTLS_CT_SIZE_32) 238a8e1175bSopenharmony_ci asm volatile (".syntax unified \n\t" 239a8e1175bSopenharmony_ci "ands %[if1], %[if1], %[condition] \n\t" 240a8e1175bSopenharmony_ci "mvns %[condition], %[condition] \n\t" 241a8e1175bSopenharmony_ci "ands %[condition], %[condition], %[if0] \n\t" 242a8e1175bSopenharmony_ci "orrs %[condition], %[if1], %[condition] \n\t" 243a8e1175bSopenharmony_ci RESTORE_ASM_SYNTAX 244a8e1175bSopenharmony_ci : 245a8e1175bSopenharmony_ci [condition] "+&l" (condition), 246a8e1175bSopenharmony_ci [if1] "+&l" (if1) 247a8e1175bSopenharmony_ci : 248a8e1175bSopenharmony_ci [if0] "l" (if0) 249a8e1175bSopenharmony_ci : 250a8e1175bSopenharmony_ci "cc" 251a8e1175bSopenharmony_ci ); 252a8e1175bSopenharmony_ci return (mbedtls_ct_uint_t) condition; 253a8e1175bSopenharmony_ci#elif defined(MBEDTLS_CT_X86_64_ASM) && (defined(MBEDTLS_CT_SIZE_32) || defined(MBEDTLS_CT_SIZE_64)) 254a8e1175bSopenharmony_ci asm volatile ("and %[condition], %[if1] \n\t" 255a8e1175bSopenharmony_ci "not %[condition] \n\t" 256a8e1175bSopenharmony_ci "and %[condition], %[if0] \n\t" 257a8e1175bSopenharmony_ci "or %[if1], %[if0] \n\t" 258a8e1175bSopenharmony_ci : 259a8e1175bSopenharmony_ci [condition] "+&D" (condition), 260a8e1175bSopenharmony_ci [if1] "+&S" (if1), 261a8e1175bSopenharmony_ci [if0] "+&a" (if0) 262a8e1175bSopenharmony_ci : 263a8e1175bSopenharmony_ci : 264a8e1175bSopenharmony_ci ); 265a8e1175bSopenharmony_ci return if0; 266a8e1175bSopenharmony_ci#elif defined(MBEDTLS_CT_X86_ASM) && defined(MBEDTLS_CT_SIZE_32) 267a8e1175bSopenharmony_ci asm volatile ("and %[condition], %[if1] \n\t" 268a8e1175bSopenharmony_ci "not %[condition] \n\t" 269a8e1175bSopenharmony_ci "and %[if0], %[condition] \n\t" 270a8e1175bSopenharmony_ci "or %[condition], %[if1] \n\t" 271a8e1175bSopenharmony_ci : 272a8e1175bSopenharmony_ci [condition] "+&c" (condition), 273a8e1175bSopenharmony_ci [if1] "+&a" (if1) 274a8e1175bSopenharmony_ci : 275a8e1175bSopenharmony_ci [if0] "b" (if0) 276a8e1175bSopenharmony_ci : 277a8e1175bSopenharmony_ci ); 278a8e1175bSopenharmony_ci return if1; 279a8e1175bSopenharmony_ci#else 280a8e1175bSopenharmony_ci mbedtls_ct_condition_t not_cond = 281a8e1175bSopenharmony_ci (mbedtls_ct_condition_t) (~mbedtls_ct_compiler_opaque(condition)); 282a8e1175bSopenharmony_ci return (mbedtls_ct_uint_t) ((condition & if1) | (not_cond & if0)); 283a8e1175bSopenharmony_ci#endif 284a8e1175bSopenharmony_ci} 285a8e1175bSopenharmony_ci 286a8e1175bSopenharmony_cistatic inline mbedtls_ct_condition_t mbedtls_ct_uint_lt(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y) 287a8e1175bSopenharmony_ci{ 288a8e1175bSopenharmony_ci#if defined(MBEDTLS_CT_AARCH64_ASM) && (defined(MBEDTLS_CT_SIZE_32) || defined(MBEDTLS_CT_SIZE_64)) 289a8e1175bSopenharmony_ci uint64_t s1; 290a8e1175bSopenharmony_ci asm volatile ("eor %x[s1], %x[y], %x[x] \n\t" 291a8e1175bSopenharmony_ci "sub %x[x], %x[x], %x[y] \n\t" 292a8e1175bSopenharmony_ci "bic %x[x], %x[x], %x[s1] \n\t" 293a8e1175bSopenharmony_ci "and %x[s1], %x[s1], %x[y] \n\t" 294a8e1175bSopenharmony_ci "orr %x[s1], %x[x], %x[s1] \n\t" 295a8e1175bSopenharmony_ci "asr %x[x], %x[s1], 63" 296a8e1175bSopenharmony_ci : 297a8e1175bSopenharmony_ci [s1] "=&r" (s1), 298a8e1175bSopenharmony_ci [x] "+&r" (x) 299a8e1175bSopenharmony_ci : 300a8e1175bSopenharmony_ci [y] "r" (y) 301a8e1175bSopenharmony_ci : 302a8e1175bSopenharmony_ci ); 303a8e1175bSopenharmony_ci return (mbedtls_ct_condition_t) x; 304a8e1175bSopenharmony_ci#elif defined(MBEDTLS_CT_ARM_ASM) && defined(MBEDTLS_CT_SIZE_32) 305a8e1175bSopenharmony_ci uint32_t s1; 306a8e1175bSopenharmony_ci asm volatile ( 307a8e1175bSopenharmony_ci ".syntax unified \n\t" 308a8e1175bSopenharmony_ci#if defined(__thumb__) && !defined(__thumb2__) 309a8e1175bSopenharmony_ci "movs %[s1], %[x] \n\t" 310a8e1175bSopenharmony_ci "eors %[s1], %[s1], %[y] \n\t" 311a8e1175bSopenharmony_ci#else 312a8e1175bSopenharmony_ci "eors %[s1], %[x], %[y] \n\t" 313a8e1175bSopenharmony_ci#endif 314a8e1175bSopenharmony_ci "subs %[x], %[x], %[y] \n\t" 315a8e1175bSopenharmony_ci "bics %[x], %[x], %[s1] \n\t" 316a8e1175bSopenharmony_ci "ands %[y], %[s1], %[y] \n\t" 317a8e1175bSopenharmony_ci "orrs %[x], %[x], %[y] \n\t" 318a8e1175bSopenharmony_ci "asrs %[x], %[x], #31 \n\t" 319a8e1175bSopenharmony_ci RESTORE_ASM_SYNTAX 320a8e1175bSopenharmony_ci : 321a8e1175bSopenharmony_ci [s1] "=&l" (s1), 322a8e1175bSopenharmony_ci [x] "+&l" (x), 323a8e1175bSopenharmony_ci [y] "+&l" (y) 324a8e1175bSopenharmony_ci : 325a8e1175bSopenharmony_ci : 326a8e1175bSopenharmony_ci "cc" 327a8e1175bSopenharmony_ci ); 328a8e1175bSopenharmony_ci return (mbedtls_ct_condition_t) x; 329a8e1175bSopenharmony_ci#elif defined(MBEDTLS_CT_X86_64_ASM) && (defined(MBEDTLS_CT_SIZE_32) || defined(MBEDTLS_CT_SIZE_64)) 330a8e1175bSopenharmony_ci uint64_t s; 331a8e1175bSopenharmony_ci asm volatile ("mov %[x], %[s] \n\t" 332a8e1175bSopenharmony_ci "xor %[y], %[s] \n\t" 333a8e1175bSopenharmony_ci "sub %[y], %[x] \n\t" 334a8e1175bSopenharmony_ci "and %[s], %[y] \n\t" 335a8e1175bSopenharmony_ci "not %[s] \n\t" 336a8e1175bSopenharmony_ci "and %[s], %[x] \n\t" 337a8e1175bSopenharmony_ci "or %[y], %[x] \n\t" 338a8e1175bSopenharmony_ci "sar $63, %[x] \n\t" 339a8e1175bSopenharmony_ci : 340a8e1175bSopenharmony_ci [s] "=&a" (s), 341a8e1175bSopenharmony_ci [x] "+&D" (x), 342a8e1175bSopenharmony_ci [y] "+&S" (y) 343a8e1175bSopenharmony_ci : 344a8e1175bSopenharmony_ci : 345a8e1175bSopenharmony_ci ); 346a8e1175bSopenharmony_ci return (mbedtls_ct_condition_t) x; 347a8e1175bSopenharmony_ci#elif defined(MBEDTLS_CT_X86_ASM) && defined(MBEDTLS_CT_SIZE_32) 348a8e1175bSopenharmony_ci uint32_t s; 349a8e1175bSopenharmony_ci asm volatile ("mov %[x], %[s] \n\t" 350a8e1175bSopenharmony_ci "xor %[y], %[s] \n\t" 351a8e1175bSopenharmony_ci "sub %[y], %[x] \n\t" 352a8e1175bSopenharmony_ci "and %[s], %[y] \n\t" 353a8e1175bSopenharmony_ci "not %[s] \n\t" 354a8e1175bSopenharmony_ci "and %[s], %[x] \n\t" 355a8e1175bSopenharmony_ci "or %[y], %[x] \n\t" 356a8e1175bSopenharmony_ci "sar $31, %[x] \n\t" 357a8e1175bSopenharmony_ci : 358a8e1175bSopenharmony_ci [s] "=&b" (s), 359a8e1175bSopenharmony_ci [x] "+&a" (x), 360a8e1175bSopenharmony_ci [y] "+&c" (y) 361a8e1175bSopenharmony_ci : 362a8e1175bSopenharmony_ci : 363a8e1175bSopenharmony_ci ); 364a8e1175bSopenharmony_ci return (mbedtls_ct_condition_t) x; 365a8e1175bSopenharmony_ci#else 366a8e1175bSopenharmony_ci /* Ensure that the compiler cannot optimise the following operations over x and y, 367a8e1175bSopenharmony_ci * even if it knows the value of x and y. 368a8e1175bSopenharmony_ci */ 369a8e1175bSopenharmony_ci const mbedtls_ct_uint_t xo = mbedtls_ct_compiler_opaque(x); 370a8e1175bSopenharmony_ci const mbedtls_ct_uint_t yo = mbedtls_ct_compiler_opaque(y); 371a8e1175bSopenharmony_ci /* 372a8e1175bSopenharmony_ci * Check if the most significant bits (MSB) of the operands are different. 373a8e1175bSopenharmony_ci * cond is true iff the MSBs differ. 374a8e1175bSopenharmony_ci */ 375a8e1175bSopenharmony_ci mbedtls_ct_condition_t cond = mbedtls_ct_bool((xo ^ yo) >> (MBEDTLS_CT_SIZE - 1)); 376a8e1175bSopenharmony_ci 377a8e1175bSopenharmony_ci /* 378a8e1175bSopenharmony_ci * If the MSB are the same then the difference x-y will be negative (and 379a8e1175bSopenharmony_ci * have its MSB set to 1 during conversion to unsigned) if and only if x<y. 380a8e1175bSopenharmony_ci * 381a8e1175bSopenharmony_ci * If the MSB are different, then the operand with the MSB of 1 is the 382a8e1175bSopenharmony_ci * bigger. (That is if y has MSB of 1, then x<y is true and it is false if 383a8e1175bSopenharmony_ci * the MSB of y is 0.) 384a8e1175bSopenharmony_ci */ 385a8e1175bSopenharmony_ci 386a8e1175bSopenharmony_ci // Select either y, or x - y 387a8e1175bSopenharmony_ci mbedtls_ct_uint_t ret = mbedtls_ct_if(cond, yo, (mbedtls_ct_uint_t) (xo - yo)); 388a8e1175bSopenharmony_ci 389a8e1175bSopenharmony_ci // Extract only the MSB of ret 390a8e1175bSopenharmony_ci ret = ret >> (MBEDTLS_CT_SIZE - 1); 391a8e1175bSopenharmony_ci 392a8e1175bSopenharmony_ci // Convert to a condition (i.e., all bits set iff non-zero) 393a8e1175bSopenharmony_ci return mbedtls_ct_bool(ret); 394a8e1175bSopenharmony_ci#endif 395a8e1175bSopenharmony_ci} 396a8e1175bSopenharmony_ci 397a8e1175bSopenharmony_cistatic inline mbedtls_ct_condition_t mbedtls_ct_uint_ne(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y) 398a8e1175bSopenharmony_ci{ 399a8e1175bSopenharmony_ci /* diff = 0 if x == y, non-zero otherwise */ 400a8e1175bSopenharmony_ci const mbedtls_ct_uint_t diff = mbedtls_ct_compiler_opaque(x) ^ mbedtls_ct_compiler_opaque(y); 401a8e1175bSopenharmony_ci 402a8e1175bSopenharmony_ci /* all ones if x != y, 0 otherwise */ 403a8e1175bSopenharmony_ci return mbedtls_ct_bool(diff); 404a8e1175bSopenharmony_ci} 405a8e1175bSopenharmony_ci 406a8e1175bSopenharmony_cistatic inline unsigned char mbedtls_ct_uchar_in_range_if(unsigned char low, 407a8e1175bSopenharmony_ci unsigned char high, 408a8e1175bSopenharmony_ci unsigned char c, 409a8e1175bSopenharmony_ci unsigned char t) 410a8e1175bSopenharmony_ci{ 411a8e1175bSopenharmony_ci const unsigned char co = (unsigned char) mbedtls_ct_compiler_opaque(c); 412a8e1175bSopenharmony_ci const unsigned char to = (unsigned char) mbedtls_ct_compiler_opaque(t); 413a8e1175bSopenharmony_ci 414a8e1175bSopenharmony_ci /* low_mask is: 0 if low <= c, 0x...ff if low > c */ 415a8e1175bSopenharmony_ci unsigned low_mask = ((unsigned) co - low) >> 8; 416a8e1175bSopenharmony_ci /* high_mask is: 0 if c <= high, 0x...ff if c > high */ 417a8e1175bSopenharmony_ci unsigned high_mask = ((unsigned) high - co) >> 8; 418a8e1175bSopenharmony_ci 419a8e1175bSopenharmony_ci return (unsigned char) (~(low_mask | high_mask)) & to; 420a8e1175bSopenharmony_ci} 421a8e1175bSopenharmony_ci 422a8e1175bSopenharmony_ci/* ============================================================================ 423a8e1175bSopenharmony_ci * Everything below here is trivial wrapper functions 424a8e1175bSopenharmony_ci */ 425a8e1175bSopenharmony_ci 426a8e1175bSopenharmony_cistatic inline size_t mbedtls_ct_size_if(mbedtls_ct_condition_t condition, 427a8e1175bSopenharmony_ci size_t if1, 428a8e1175bSopenharmony_ci size_t if0) 429a8e1175bSopenharmony_ci{ 430a8e1175bSopenharmony_ci return (size_t) mbedtls_ct_if(condition, (mbedtls_ct_uint_t) if1, (mbedtls_ct_uint_t) if0); 431a8e1175bSopenharmony_ci} 432a8e1175bSopenharmony_ci 433a8e1175bSopenharmony_cistatic inline unsigned mbedtls_ct_uint_if(mbedtls_ct_condition_t condition, 434a8e1175bSopenharmony_ci unsigned if1, 435a8e1175bSopenharmony_ci unsigned if0) 436a8e1175bSopenharmony_ci{ 437a8e1175bSopenharmony_ci return (unsigned) mbedtls_ct_if(condition, (mbedtls_ct_uint_t) if1, (mbedtls_ct_uint_t) if0); 438a8e1175bSopenharmony_ci} 439a8e1175bSopenharmony_ci 440a8e1175bSopenharmony_cistatic inline mbedtls_ct_condition_t mbedtls_ct_bool_if(mbedtls_ct_condition_t condition, 441a8e1175bSopenharmony_ci mbedtls_ct_condition_t if1, 442a8e1175bSopenharmony_ci mbedtls_ct_condition_t if0) 443a8e1175bSopenharmony_ci{ 444a8e1175bSopenharmony_ci return (mbedtls_ct_condition_t) mbedtls_ct_if(condition, (mbedtls_ct_uint_t) if1, 445a8e1175bSopenharmony_ci (mbedtls_ct_uint_t) if0); 446a8e1175bSopenharmony_ci} 447a8e1175bSopenharmony_ci 448a8e1175bSopenharmony_ci#if defined(MBEDTLS_BIGNUM_C) 449a8e1175bSopenharmony_ci 450a8e1175bSopenharmony_cistatic inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if(mbedtls_ct_condition_t condition, 451a8e1175bSopenharmony_ci mbedtls_mpi_uint if1, 452a8e1175bSopenharmony_ci mbedtls_mpi_uint if0) 453a8e1175bSopenharmony_ci{ 454a8e1175bSopenharmony_ci return (mbedtls_mpi_uint) mbedtls_ct_if(condition, 455a8e1175bSopenharmony_ci (mbedtls_ct_uint_t) if1, 456a8e1175bSopenharmony_ci (mbedtls_ct_uint_t) if0); 457a8e1175bSopenharmony_ci} 458a8e1175bSopenharmony_ci 459a8e1175bSopenharmony_ci#endif 460a8e1175bSopenharmony_ci 461a8e1175bSopenharmony_cistatic inline size_t mbedtls_ct_size_if_else_0(mbedtls_ct_condition_t condition, size_t if1) 462a8e1175bSopenharmony_ci{ 463a8e1175bSopenharmony_ci return (size_t) (condition & if1); 464a8e1175bSopenharmony_ci} 465a8e1175bSopenharmony_ci 466a8e1175bSopenharmony_cistatic inline unsigned mbedtls_ct_uint_if_else_0(mbedtls_ct_condition_t condition, unsigned if1) 467a8e1175bSopenharmony_ci{ 468a8e1175bSopenharmony_ci return (unsigned) (condition & if1); 469a8e1175bSopenharmony_ci} 470a8e1175bSopenharmony_ci 471a8e1175bSopenharmony_cistatic inline mbedtls_ct_condition_t mbedtls_ct_bool_if_else_0(mbedtls_ct_condition_t condition, 472a8e1175bSopenharmony_ci mbedtls_ct_condition_t if1) 473a8e1175bSopenharmony_ci{ 474a8e1175bSopenharmony_ci return (mbedtls_ct_condition_t) (condition & if1); 475a8e1175bSopenharmony_ci} 476a8e1175bSopenharmony_ci 477a8e1175bSopenharmony_ci#if defined(MBEDTLS_BIGNUM_C) 478a8e1175bSopenharmony_ci 479a8e1175bSopenharmony_cistatic inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if_else_0(mbedtls_ct_condition_t condition, 480a8e1175bSopenharmony_ci mbedtls_mpi_uint if1) 481a8e1175bSopenharmony_ci{ 482a8e1175bSopenharmony_ci return (mbedtls_mpi_uint) (condition & if1); 483a8e1175bSopenharmony_ci} 484a8e1175bSopenharmony_ci 485a8e1175bSopenharmony_ci#endif /* MBEDTLS_BIGNUM_C */ 486a8e1175bSopenharmony_ci 487a8e1175bSopenharmony_cistatic inline int mbedtls_ct_error_if(mbedtls_ct_condition_t condition, int if1, int if0) 488a8e1175bSopenharmony_ci{ 489a8e1175bSopenharmony_ci /* Coverting int -> uint -> int here is safe, because we require if1 and if0 to be 490a8e1175bSopenharmony_ci * in the range -32767..0, and we require 32-bit int and uint types. 491a8e1175bSopenharmony_ci * 492a8e1175bSopenharmony_ci * This means that (0 <= -if0 < INT_MAX), so negating if0 is safe, and similarly for 493a8e1175bSopenharmony_ci * converting back to int. 494a8e1175bSopenharmony_ci */ 495a8e1175bSopenharmony_ci return -((int) mbedtls_ct_if(condition, (mbedtls_ct_uint_t) (-if1), 496a8e1175bSopenharmony_ci (mbedtls_ct_uint_t) (-if0))); 497a8e1175bSopenharmony_ci} 498a8e1175bSopenharmony_ci 499a8e1175bSopenharmony_cistatic inline int mbedtls_ct_error_if_else_0(mbedtls_ct_condition_t condition, int if1) 500a8e1175bSopenharmony_ci{ 501a8e1175bSopenharmony_ci return -((int) (condition & (-if1))); 502a8e1175bSopenharmony_ci} 503a8e1175bSopenharmony_ci 504a8e1175bSopenharmony_cistatic inline mbedtls_ct_condition_t mbedtls_ct_uint_eq(mbedtls_ct_uint_t x, 505a8e1175bSopenharmony_ci mbedtls_ct_uint_t y) 506a8e1175bSopenharmony_ci{ 507a8e1175bSopenharmony_ci return ~mbedtls_ct_uint_ne(x, y); 508a8e1175bSopenharmony_ci} 509a8e1175bSopenharmony_ci 510a8e1175bSopenharmony_cistatic inline mbedtls_ct_condition_t mbedtls_ct_uint_gt(mbedtls_ct_uint_t x, 511a8e1175bSopenharmony_ci mbedtls_ct_uint_t y) 512a8e1175bSopenharmony_ci{ 513a8e1175bSopenharmony_ci return mbedtls_ct_uint_lt(y, x); 514a8e1175bSopenharmony_ci} 515a8e1175bSopenharmony_ci 516a8e1175bSopenharmony_cistatic inline mbedtls_ct_condition_t mbedtls_ct_uint_ge(mbedtls_ct_uint_t x, 517a8e1175bSopenharmony_ci mbedtls_ct_uint_t y) 518a8e1175bSopenharmony_ci{ 519a8e1175bSopenharmony_ci return ~mbedtls_ct_uint_lt(x, y); 520a8e1175bSopenharmony_ci} 521a8e1175bSopenharmony_ci 522a8e1175bSopenharmony_cistatic inline mbedtls_ct_condition_t mbedtls_ct_uint_le(mbedtls_ct_uint_t x, 523a8e1175bSopenharmony_ci mbedtls_ct_uint_t y) 524a8e1175bSopenharmony_ci{ 525a8e1175bSopenharmony_ci return ~mbedtls_ct_uint_gt(x, y); 526a8e1175bSopenharmony_ci} 527a8e1175bSopenharmony_ci 528a8e1175bSopenharmony_cistatic inline mbedtls_ct_condition_t mbedtls_ct_bool_ne(mbedtls_ct_condition_t x, 529a8e1175bSopenharmony_ci mbedtls_ct_condition_t y) 530a8e1175bSopenharmony_ci{ 531a8e1175bSopenharmony_ci return (mbedtls_ct_condition_t) (x ^ y); 532a8e1175bSopenharmony_ci} 533a8e1175bSopenharmony_ci 534a8e1175bSopenharmony_cistatic inline mbedtls_ct_condition_t mbedtls_ct_bool_and(mbedtls_ct_condition_t x, 535a8e1175bSopenharmony_ci mbedtls_ct_condition_t y) 536a8e1175bSopenharmony_ci{ 537a8e1175bSopenharmony_ci return (mbedtls_ct_condition_t) (x & y); 538a8e1175bSopenharmony_ci} 539a8e1175bSopenharmony_ci 540a8e1175bSopenharmony_cistatic inline mbedtls_ct_condition_t mbedtls_ct_bool_or(mbedtls_ct_condition_t x, 541a8e1175bSopenharmony_ci mbedtls_ct_condition_t y) 542a8e1175bSopenharmony_ci{ 543a8e1175bSopenharmony_ci return (mbedtls_ct_condition_t) (x | y); 544a8e1175bSopenharmony_ci} 545a8e1175bSopenharmony_ci 546a8e1175bSopenharmony_cistatic inline mbedtls_ct_condition_t mbedtls_ct_bool_not(mbedtls_ct_condition_t x) 547a8e1175bSopenharmony_ci{ 548a8e1175bSopenharmony_ci return (mbedtls_ct_condition_t) (~x); 549a8e1175bSopenharmony_ci} 550a8e1175bSopenharmony_ci 551a8e1175bSopenharmony_ci#if defined(MBEDTLS_COMPILER_IS_GCC) && (__GNUC__ > 4) 552a8e1175bSopenharmony_ci/* Restore warnings for -Wredundant-decls on gcc */ 553a8e1175bSopenharmony_ci #pragma GCC diagnostic pop 554a8e1175bSopenharmony_ci#endif 555a8e1175bSopenharmony_ci 556a8e1175bSopenharmony_ci#endif /* MBEDTLS_CONSTANT_TIME_IMPL_H */ 557