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