Introduce new CT interface (retain old interface)

Signed-off-by: Dave Rodgman <dave.rodgman@arm.com>
diff --git a/library/constant_time.c b/library/constant_time.c
index 135a6ec..cc12c9c 100644
--- a/library/constant_time.c
+++ b/library/constant_time.c
@@ -22,17 +22,14 @@
  * might be translated to branches by some compilers on some platforms.
  */
 
+#include <limits.h>
+
 #include "common.h"
 #include "constant_time_internal.h"
 #include "mbedtls/constant_time.h"
 #include "mbedtls/error.h"
 #include "mbedtls/platform_util.h"
 
-#if defined(MBEDTLS_BIGNUM_C)
-#include "mbedtls/bignum.h"
-#include "bignum_core.h"
-#endif
-
 #if defined(MBEDTLS_SSL_TLS_C)
 #include "ssl_misc.h"
 #endif
@@ -41,10 +38,6 @@
 #include "mbedtls/rsa.h"
 #endif
 
-#if defined(MBEDTLS_BASE64_C)
-#include "constant_time_invasive.h"
-#endif
-
 #include <string.h>
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
 #define PSA_TO_MBEDTLS_ERR(status) PSA_TO_MBEDTLS_ERR_LIST(status,    \
@@ -62,13 +55,11 @@
  * Some of these definitions could be moved into alignment.h but for now they are
  * only used here.
  */
-#if defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS) && defined(MBEDTLS_HAVE_ASM)
-#if defined(__arm__) || defined(__thumb__) || defined(__thumb2__) || defined(__aarch64__)
-#define MBEDTLS_EFFICIENT_UNALIGNED_VOLATILE_ACCESS
-#endif
-#endif
+#if defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS) && \
+    (defined(MBEDTLS_CT_ARM_ASM) || defined(MBEDTLS_CT_AARCH64_ASM))
 
-#if defined(MBEDTLS_EFFICIENT_UNALIGNED_VOLATILE_ACCESS)
+#define MBEDTLS_EFFICIENT_UNALIGNED_VOLATILE_ACCESS
+
 static inline uint32_t mbedtls_get_unaligned_volatile_uint32(volatile const unsigned char *p)
 {
     /* This is UB, even where it's safe:
@@ -76,14 +67,17 @@
      * so instead the same thing is expressed in assembly below.
      */
     uint32_t r;
-#if defined(__arm__) || defined(__thumb__) || defined(__thumb2__)
+#if defined(MBEDTLS_CT_ARM_ASM)
     asm volatile ("ldr %0, [%1]" : "=r" (r) : "r" (p) :);
-#elif defined(__aarch64__)
+#elif defined(MBEDTLS_CT_AARCH64_ASM)
     asm volatile ("ldr %w0, [%1]" : "=r" (r) : "r" (p) :);
+#else
+#error No assembly defined for mbedtls_get_unaligned_volatile_uint32
 #endif
     return r;
 }
-#endif /* MBEDTLS_EFFICIENT_UNALIGNED_VOLATILE_ACCESS */
+#endif /* defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS) &&
+          (defined(MBEDTLS_CT_ARM_ASM) || defined(MBEDTLS_CT_AARCH64_ASM)) */
 
 int mbedtls_ct_memcmp(const void *a,
                       const void *b,
diff --git a/library/constant_time_impl.h b/library/constant_time_impl.h
new file mode 100644
index 0000000..218a4a6
--- /dev/null
+++ b/library/constant_time_impl.h
@@ -0,0 +1,276 @@
+/**
+ *  Constant-time functions
+ *
+ *  For readability, the static inline definitions are here, and
+ *  constant_time_internal.h has only the declarations.
+ *
+ *  This results in duplicate declarations of the form:
+ *      static inline void f() { ... }
+ *      static inline void f();
+ *  when constant_time_internal.h is included. This appears to behave
+ *  exactly as if the declaration-without-definition was not present.
+ *
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *  not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+#ifndef MBEDTLS_CONSTANT_TIME_IMPL_H
+#define MBEDTLS_CONSTANT_TIME_IMPL_H
+
+#include <stddef.h>
+
+#include "common.h"
+
+#if defined(MBEDTLS_BIGNUM_C)
+#include "mbedtls/bignum.h"
+#endif
+
+
+/* Disable asm under Memsan because it confuses Memsan and generates false errors */
+#if defined(MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN)
+#define MBEDTLS_CT_NO_ASM
+#elif defined(__has_feature)
+#if __has_feature(memory_sanitizer)
+#define MBEDTLS_CT_NO_ASM
+#endif
+#endif
+
+/* armcc5 --gnu defines __GNUC__ but doesn't support GNU's extended asm */
+#if defined(MBEDTLS_HAVE_ASM) && defined(__GNUC__) && (!defined(__ARMCC_VERSION) || \
+    __ARMCC_VERSION >= 6000000) && !defined(MBEDTLS_CT_NO_ASM)
+#define MBEDTLS_CT_ASM
+#if (defined(__arm__) || defined(__thumb__) || defined(__thumb2__))
+#define MBEDTLS_CT_ARM_ASM
+#elif defined(__aarch64__)
+#define MBEDTLS_CT_AARCH64_ASM
+#endif
+#endif
+
+#define MBEDTLS_CT_SIZE (sizeof(mbedtls_ct_uint_t) * 8)
+
+
+/* ============================================================================
+ * Core const-time primitives
+ */
+
+/** Ensure that the compiler cannot know the value of x (i.e., cannot optimise
+ * based on its value) after this function is called.
+ *
+ * If we are not using assembly, this will be fairly inefficient, so its use
+ * should be minimised.
+ */
+static inline mbedtls_ct_uint_t mbedtls_ct_compiler_opaque(mbedtls_ct_uint_t x)
+{
+#if defined(MBEDTLS_CT_ASM)
+    asm volatile ("" : [x] "+r" (x) :);
+    return x;
+#else
+    volatile mbedtls_ct_uint_t result = x;
+    return result;
+#endif
+}
+
+/* Convert a number into a condition in constant time. */
+static inline mbedtls_ct_condition_t mbedtls_ct_bool(mbedtls_ct_uint_t x)
+{
+    /*
+     * Define mask-generation code that, as far as possible, will not use branches or conditional instructions.
+     *
+     * For some platforms / type sizes, we define assembly to assure this.
+     *
+     * Otherwise, we define a plain C fallback which (in May 2023) does not get optimised into
+     * conditional instructions or branches by trunk clang, gcc, or MSVC v19.
+     */
+    const mbedtls_ct_uint_t xo = mbedtls_ct_compiler_opaque(x);
+#if defined(_MSC_VER)
+    /* MSVC has a warning about unary minus on unsigned, but this is
+     * well-defined and precisely what we want to do here */
+#pragma warning( push )
+#pragma warning( disable : 4146 )
+#endif
+    return (mbedtls_ct_condition_t) (((mbedtls_ct_int_t) ((-xo) | -(xo >> 1))) >>
+                                     (MBEDTLS_CT_SIZE - 1));
+#if defined(_MSC_VER)
+#pragma warning( pop )
+#endif
+}
+
+static inline mbedtls_ct_uint_t mbedtls_ct_if(mbedtls_ct_condition_t condition,
+                                              mbedtls_ct_uint_t if1,
+                                              mbedtls_ct_uint_t if0)
+{
+    mbedtls_ct_condition_t not_mask =
+        (mbedtls_ct_condition_t) (~mbedtls_ct_compiler_opaque(condition));
+    mbedtls_ct_condition_t mask     =
+        (mbedtls_ct_condition_t)   mbedtls_ct_compiler_opaque(condition);
+    return (mbedtls_ct_uint_t) ((mask & if1) | (not_mask & if0));
+}
+
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_lt(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y)
+{
+    /* Ensure that the compiler cannot optimise the following operations over x and y,
+     * even if it knows the value of x and y.
+     */
+    const mbedtls_ct_uint_t yo = mbedtls_ct_compiler_opaque(y);
+    /*
+     * Check if the most significant bits (MSB) of the operands are different.
+     * cond is true iff the MSBs differ.
+     */
+    mbedtls_ct_condition_t cond = mbedtls_ct_bool((x ^ yo) >> (MBEDTLS_CT_SIZE - 1));
+
+    /*
+     * If the MSB are the same then the difference x-y will be negative (and
+     * have its MSB set to 1 during conversion to unsigned) if and only if x<y.
+     *
+     * If the MSB are different, then the operand with the MSB of 1 is the
+     * bigger. (That is if y has MSB of 1, then x<y is true and it is false if
+     * the MSB of y is 0.)
+     */
+
+    // Select either y, or x - y
+    mbedtls_ct_uint_t ret = mbedtls_ct_if(cond, yo, (mbedtls_ct_uint_t) (x - yo));
+
+    // Extract only the MSB of ret
+    ret = ret >> (MBEDTLS_CT_SIZE - 1);
+
+    // Convert to a condition (i.e., all bits set iff non-zero)
+    return mbedtls_ct_bool(ret);
+}
+
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_ne(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y)
+{
+    /* diff = 0 if x == y, non-zero otherwise */
+    const mbedtls_ct_uint_t diff = mbedtls_ct_compiler_opaque(x) ^ y;
+
+    /* all ones if x != y, 0 otherwise */
+    return mbedtls_ct_bool(diff);
+}
+
+static inline unsigned char mbedtls_ct_uchar_in_range_if(unsigned char low,
+                                                         unsigned char high,
+                                                         unsigned char c,
+                                                         unsigned char t)
+{
+    const unsigned char co = (const unsigned char) mbedtls_ct_compiler_opaque(c);
+    const unsigned char to = (const unsigned char) mbedtls_ct_compiler_opaque(t);
+
+    /* low_mask is: 0 if low <= c, 0x...ff if low > c */
+    unsigned low_mask = ((unsigned) co - low) >> 8;
+    /* high_mask is: 0 if c <= high, 0x...ff if c > high */
+    unsigned high_mask = ((unsigned) high - co) >> 8;
+
+    return (unsigned char) (~(low_mask | high_mask)) & to;
+}
+
+
+/* ============================================================================
+ * Everything below here is trivial wrapper functions
+ */
+
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_eq(mbedtls_ct_uint_t x,
+                                                        mbedtls_ct_uint_t y)
+{
+    return ~mbedtls_ct_bool_ne(x, y);
+}
+
+static inline size_t mbedtls_ct_size_if(mbedtls_ct_condition_t condition,
+                                        size_t if1,
+                                        size_t if0)
+{
+    return (size_t) mbedtls_ct_if(condition, (mbedtls_ct_uint_t) if1, (mbedtls_ct_uint_t) if0);
+}
+
+static inline unsigned mbedtls_ct_uint_if_new(mbedtls_ct_condition_t condition,
+                                          unsigned if1,
+                                          unsigned if0)
+{
+    return (unsigned) mbedtls_ct_if(condition, (mbedtls_ct_uint_t) if1, (mbedtls_ct_uint_t) if0);
+}
+
+#if defined(MBEDTLS_BIGNUM_C)
+
+static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if(mbedtls_ct_condition_t condition, \
+                                                      mbedtls_mpi_uint if1, \
+                                                      mbedtls_mpi_uint if0)
+{
+    return (mbedtls_mpi_uint) mbedtls_ct_if(condition,
+                                            (mbedtls_ct_uint_t) if1,
+                                            (mbedtls_ct_uint_t) if0);
+}
+
+#endif
+
+static inline size_t mbedtls_ct_size_if0(mbedtls_ct_condition_t condition, size_t if1)
+{
+    return (size_t) (mbedtls_ct_compiler_opaque(condition) & if1);
+}
+
+static inline unsigned mbedtls_ct_uint_if0(mbedtls_ct_condition_t condition, unsigned if1)
+{
+    return (unsigned) (mbedtls_ct_compiler_opaque(condition) & if1);
+}
+
+#if defined(MBEDTLS_BIGNUM_C)
+
+static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if0(mbedtls_ct_condition_t condition,
+                                                       mbedtls_mpi_uint if1)
+{
+    return (mbedtls_mpi_uint) (mbedtls_ct_compiler_opaque(condition) & if1);
+}
+
+#endif /* MBEDTLS_BIGNUM_C */
+
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_gt(mbedtls_ct_uint_t x,
+                                                        mbedtls_ct_uint_t y)
+{
+    return mbedtls_ct_bool_lt(y, x);
+}
+
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_ge(mbedtls_ct_uint_t x,
+                                                        mbedtls_ct_uint_t y)
+{
+    return ~mbedtls_ct_bool_lt(x, y);
+}
+
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_le(mbedtls_ct_uint_t x,
+                                                        mbedtls_ct_uint_t y)
+{
+    return ~mbedtls_ct_bool_gt(x, y);
+}
+
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_xor(mbedtls_ct_condition_t x,
+                                                         mbedtls_ct_condition_t y)
+{
+    return (mbedtls_ct_condition_t) (mbedtls_ct_compiler_opaque(x) ^ mbedtls_ct_compiler_opaque(y));
+}
+
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_and(mbedtls_ct_condition_t x,
+                                                         mbedtls_ct_condition_t y)
+{
+    return (mbedtls_ct_condition_t) (mbedtls_ct_compiler_opaque(x) & mbedtls_ct_compiler_opaque(y));
+}
+
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_or(mbedtls_ct_condition_t x,
+                                                        mbedtls_ct_condition_t y)
+{
+    return (mbedtls_ct_condition_t) (mbedtls_ct_compiler_opaque(x) | mbedtls_ct_compiler_opaque(y));
+}
+
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_not(mbedtls_ct_condition_t x)
+{
+    return (mbedtls_ct_condition_t) (~mbedtls_ct_compiler_opaque(x));
+}
+
+#endif /* MBEDTLS_CONSTANT_TIME_IMPL_H */
diff --git a/library/constant_time_internal.h b/library/constant_time_internal.h
index e085478..d1e3755 100644
--- a/library/constant_time_internal.h
+++ b/library/constant_time_internal.h
@@ -20,6 +20,9 @@
 #ifndef MBEDTLS_CONSTANT_TIME_INTERNAL_H
 #define MBEDTLS_CONSTANT_TIME_INTERNAL_H
 
+#include <stdint.h>
+#include <stddef.h>
+
 #include "common.h"
 
 #if defined(MBEDTLS_BIGNUM_C)
@@ -30,8 +33,6 @@
 #include "ssl_misc.h"
 #endif
 
-#include <stddef.h>
-
 
 /** Turn a value into a mask:
  * - if \p value == 0, return the all-bits 0 mask, aka 0
@@ -220,33 +221,6 @@
 
 #endif /* MBEDTLS_SSL_SOME_SUITES_USE_MAC */
 
-#if defined(MBEDTLS_BASE64_C)
-
-/** Constant-flow char selection
- *
- * \param low   Bottom of range
- * \param high  Top of range
- * \param c     Value to compare to range
- * \param t     Value to return, if in range
- *
- * \return      \p t if \p low <= \p c <= \p high, 0 otherwise.
- */
-static inline unsigned char mbedtls_ct_uchar_in_range_if(unsigned char low,
-                                                         unsigned char high,
-                                                         unsigned char c,
-                                                         unsigned char t)
-{
-    /* low_mask is: 0 if low <= c, 0x...ff if low > c */
-    unsigned low_mask = ((unsigned) c - low) >> 8;
-    /* high_mask is: 0 if c <= high, 0x...ff if c > high */
-    unsigned high_mask = ((unsigned) high - c) >> 8;
-    return (unsigned char)
-           mbedtls_ct_uint_if(~mbedtls_ct_mpi_uint_mask(low_mask | high_mask), t, 0);
-}
-
-#endif /* MBEDTLS_BASE64_C */
-
-
 #if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT)
 
 /** Constant-flow "greater than" comparison:
@@ -284,4 +258,447 @@
 
 #endif /* defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) */
 
+
+
+/* The constant-time interface provides various operations that are likely
+ * to result in constant-time code that does not branch or use conditional
+ * instructions for secret data (for secret pointers, this also applies to
+ * the data pointed to).
+ *
+ * It has three main parts:
+ *
+ * - boolean operations (and a few non-boolean operations)
+ *   These are all named mbedtls_ct_bool_<operation>, and operate over
+ *   mbedtls_ct_condition_t.
+ *   All arguments to these operations are considered secret.
+ *   example: bool x = y | z          =>    x = mbedtls_ct_bool_or(y, z)
+ *
+ * - conditional data selection
+ *   These are all named mbedtls_ct_<type>_if and mbedtls_ct_<type>_if0
+ *   All arguments are considered secret.
+ *   example: size_t a = x ? b : c    =>    a = mbedtls_ct_size_if(x, b, c)
+ *   example: unsigned a = x ? b : 0  =>    a = mbedtls_ct_uint_if0(x, b)
+ *
+ * - block memory operations
+ *   Only some arguments are considered secret, as documented for each
+ *   function.
+ *   example: if (x) memcpy(...)      =>    mbedtls_ct_memcpy_if(x, ...)
+ *
+ * mbedtls_ct_condition_t should be treated as opaque and only manipulated
+ * via the functions in this header.
+ *
+ * mbedtls_ct_uint_t is an unsigned integer type over which constant time
+ * operations may be performed via the functions in this header. It is as big
+ * as the larger of size_t and mbedtls_mpi_uint, i.e. it is safe to cast
+ * to/from "unsigned int", "size_t", and "mbedtls_mpi_uint" (and any other
+ * not-larger integer types).
+ *
+ * For Arm (32-bit, 64-bit and Thumb), assembly implementations are used
+ * to ensure that the generated code is constant time. For other architectures,
+ * a plain C fallback designed to yield constant-time code (this has been
+ * observed to be constant-time on latest gcc, clang and MSVC as of May 2023).
+ */
+
+#if (SIZE_MAX > 0xffffffffffffffffULL)
+/* Pointer size > 64-bit */
+typedef size_t    mbedtls_ct_condition_t;
+typedef size_t    mbedtls_ct_uint_t;
+typedef ptrdiff_t mbedtls_ct_int_t;
+#define MBEDTLS_CT_TRUE  ((mbedtls_ct_condition_t) SIZE_MAX)
+#elif (SIZE_MAX > 0xffffffff) || defined(MBEDTLS_HAVE_INT64)
+/* 32-bit < pointer size < 64-bit, or 64-bit MPI */
+typedef uint64_t  mbedtls_ct_condition_t;
+typedef uint64_t  mbedtls_ct_uint_t;
+typedef int64_t   mbedtls_ct_int_t;
+#define MBEDTLS_CT_TRUE  ((mbedtls_ct_condition_t) UINT64_MAX)
+#else
+/* Pointer size < 32-bit, and no 64-bit MPIs */
+typedef uint32_t  mbedtls_ct_condition_t;
+typedef uint32_t  mbedtls_ct_uint_t;
+typedef int32_t   mbedtls_ct_int_t;
+#define MBEDTLS_CT_TRUE  ((mbedtls_ct_condition_t) UINT32_MAX)
+#endif
+#define MBEDTLS_CT_FALSE ((mbedtls_ct_condition_t) 0)
+
+/* constant_time_impl.h contains all the static inline implementations,
+ * so that constant_time_internal.h is more readable.
+ */
+#include "constant_time_impl.h"
+
+
+/* ============================================================================
+ * Boolean operations
+ */
+
+/** Convert a number into a mbedtls_ct_condition_t.
+ *
+ * \param x Number to convert.
+ *
+ * \return MBEDTLS_CT_TRUE if \p x != 0, or MBEDTLS_CT_FALSE if \p x == 0
+ *
+ */
+static inline mbedtls_ct_condition_t mbedtls_ct_bool(mbedtls_ct_uint_t x);
+
+/** Boolean "not equal" operation.
+ *
+ * Functionally equivalent to:
+ *
+ * \p x != \p y
+ *
+ * \param x     The first value to analyze.
+ * \param y     The second value to analyze.
+ *
+ * \return      MBEDTLS_CT_TRUE if \p x != \p y, otherwise MBEDTLS_CT_FALSE.
+ */
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_ne(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y);
+
+/** Boolean "equals" operation.
+ *
+ * Functionally equivalent to:
+ *
+ * \p x == \p y
+ *
+ * \param x     The first value to analyze.
+ * \param y     The second value to analyze.
+ *
+ * \return      MBEDTLS_CT_TRUE if \p x == \p y, otherwise MBEDTLS_CT_FALSE.
+ */
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_eq(mbedtls_ct_uint_t x,
+                                                        mbedtls_ct_uint_t y);
+
+/** Boolean "less than" operation.
+ *
+ * Functionally equivalent to:
+ *
+ * \p x < \p y
+ *
+ * \param x     The first value to analyze.
+ * \param y     The second value to analyze.
+ *
+ * \return      MBEDTLS_CT_TRUE if \p x < \p y, otherwise MBEDTLS_CT_FALSE.
+ */
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_lt(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y);
+
+/** Boolean "greater than" operation.
+ *
+ * Functionally equivalent to:
+ *
+ * \p x > \p y
+ *
+ * \param x     The first value to analyze.
+ * \param y     The second value to analyze.
+ *
+ * \return      MBEDTLS_CT_TRUE if \p x > \p y, otherwise MBEDTLS_CT_FALSE.
+ */
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_gt(mbedtls_ct_uint_t x,
+                                                        mbedtls_ct_uint_t y);
+
+/** Boolean "greater or equal" operation.
+ *
+ * Functionally equivalent to:
+ *
+ * \p x >= \p y
+ *
+ * \param x     The first value to analyze.
+ * \param y     The second value to analyze.
+ *
+ * \return      MBEDTLS_CT_TRUE if \p x >= \p y,
+ *              otherwise MBEDTLS_CT_FALSE.
+ */
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_ge(mbedtls_ct_uint_t x,
+                                                        mbedtls_ct_uint_t y);
+
+/** Boolean "less than or equal" operation.
+ *
+ * Functionally equivalent to:
+ *
+ * \p x <= \p y
+ *
+ * \param x     The first value to analyze.
+ * \param y     The second value to analyze.
+ *
+ * \return      MBEDTLS_CT_TRUE if \p x <= \p y,
+ *              otherwise MBEDTLS_CT_FALSE.
+ */
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_le(mbedtls_ct_uint_t x,
+                                                        mbedtls_ct_uint_t y);
+
+/** Boolean "xor" operation.
+ *
+ * Functionally equivalent to:
+ *
+ * \p x ^ \p y
+ *
+ * \param x     The first value to analyze.
+ * \param y     The second value to analyze.
+ *
+ * \note        This is more efficient than mbedtls_ct_bool_ne if both arguments are
+ *              mbedtls_ct_condition_t.
+ *
+ * \return      MBEDTLS_CT_TRUE if \p x ^ \p y,
+ *              otherwise MBEDTLS_CT_FALSE.
+ */
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_xor(mbedtls_ct_condition_t x,
+                                                         mbedtls_ct_condition_t y);
+
+/** Boolean "and" operation.
+ *
+ * Functionally equivalent to:
+ *
+ * \p x && \p y
+ *
+ * \param x     The first value to analyze.
+ * \param y     The second value to analyze.
+ *
+ * \return      MBEDTLS_CT_TRUE if \p x && \p y,
+ *              otherwise MBEDTLS_CT_FALSE.
+ */
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_and(mbedtls_ct_condition_t x,
+                                                         mbedtls_ct_condition_t y);
+
+/** Boolean "or" operation.
+ *
+ * Functionally equivalent to:
+ *
+ * \p x || \p y
+ *
+ * \param x     The first value to analyze.
+ * \param y     The second value to analyze.
+ *
+ * \return      MBEDTLS_CT_TRUE if \p x || \p y,
+ *              otherwise MBEDTLS_CT_FALSE.
+ */
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_or(mbedtls_ct_condition_t x,
+                                                        mbedtls_ct_condition_t y);
+
+/** Boolean "not" operation.
+ *
+ * Functionally equivalent to:
+ *
+ * ! \p x
+ *
+ * \param x     The value to invert
+ *
+ * \return      MBEDTLS_CT_FALSE if \p x, otherwise MBEDTLS_CT_TRUE.
+ */
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_not(mbedtls_ct_condition_t x);
+
+
+/* ============================================================================
+ * Data selection operations
+ */
+
+/** Choose between two size_t values.
+ *
+ * Functionally equivalent to:
+ *
+ * condition ? if1 : if0.
+ *
+ * \param condition     Condition to test.
+ * \param if1           Value to use if \p condition == MBEDTLS_CT_TRUE.
+ * \param if0           Value to use if \p condition == MBEDTLS_CT_FALSE.
+ *
+ * \return  \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise \c if0.
+ */
+static inline size_t mbedtls_ct_size_if(mbedtls_ct_condition_t condition,
+                                        size_t if1,
+                                        size_t if0);
+
+/** Choose between two unsigned values.
+ *
+ * Functionally equivalent to:
+ *
+ * condition ? if1 : if0.
+ *
+ * \param condition     Condition to test.
+ * \param if1           Value to use if \p condition == MBEDTLS_CT_TRUE.
+ * \param if0           Value to use if \p condition == MBEDTLS_CT_FALSE.
+ *
+ * \return  \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise \c if0.
+ */
+static inline unsigned mbedtls_ct_uint_if_new(mbedtls_ct_condition_t condition,
+                                          unsigned if1,
+                                          unsigned if0);
+
+#if defined(MBEDTLS_BIGNUM_C)
+
+/** Choose between two mbedtls_mpi_uint values.
+ *
+ * Functionally equivalent to:
+ *
+ * condition ? if1 : if0.
+ *
+ * \param condition     Condition to test.
+ * \param if1           Value to use if \p condition == MBEDTLS_CT_TRUE.
+ * \param if0           Value to use if \p condition == MBEDTLS_CT_FALSE.
+ *
+ * \return  \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise \c if0.
+ */
+static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if(mbedtls_ct_condition_t condition, \
+                                                      mbedtls_mpi_uint if1, \
+                                                      mbedtls_mpi_uint if0);
+
+#endif
+
+/** Choose between an unsigned value and 0.
+ *
+ * Functionally equivalent to:
+ *
+ * condition ? if1 : 0.
+ *
+ * Functionally equivalent tombedtls_ct_uint_if(condition, if1, 0) but
+ * results in smaller code size.
+ *
+ * \param condition     Condition to test.
+ * \param if1           Value to use if \p condition == MBEDTLS_CT_TRUE.
+ *
+ * \return  \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise 0.
+ */
+static inline unsigned mbedtls_ct_uint_if0(mbedtls_ct_condition_t condition, unsigned if1);
+
+#if defined(MBEDTLS_BIGNUM_C)
+
+/** Choose between an mbedtls_mpi_uint value and 0.
+ *
+ * Functionally equivalent to:
+ *
+ * condition ? if1 : 0.
+ *
+ * Functionally equivalent tombedtls_ct_mpi_uint_if(condition, if1, 0) but
+ * results in smaller code size.
+ *
+ * \param condition     Condition to test.
+ * \param if1           Value to use if \p condition == MBEDTLS_CT_TRUE.
+ *
+ * \return  \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise 0.
+ */
+static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if0(mbedtls_ct_condition_t condition,
+                                                       mbedtls_mpi_uint if1);
+
+#endif
+
+/** Constant-flow char selection
+ *
+ * \param low   Secret. Bottom of range
+ * \param high  Secret. Top of range
+ * \param c     Secret. Value to compare to range
+ * \param t     Secret. Value to return, if in range
+ *
+ * \return      \p t if \p low <= \p c <= \p high, 0 otherwise.
+ */
+static inline unsigned char mbedtls_ct_uchar_in_range_if(unsigned char low,
+                                                         unsigned char high,
+                                                         unsigned char c,
+                                                         unsigned char t);
+
+
+/* ============================================================================
+ * Block memory operations
+ */
+
+#if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT)
+
+/** Conditionally set a block of memory to zero.
+ *
+ * Regardless of the condition, every byte will be read once and written to
+ * once.
+ *
+ * \param condition     Secret. Condition to test.
+ * \param buf           Secret. Pointer to the start of the buffer.
+ * \param len           Number of bytes to set to zero.
+ *
+ * \warning Unlike mbedtls_platform_zeroize, this does not have the same guarantees
+ * about not being optimised away if the memory is never read again.
+ */
+void mbedtls_ct_zeroize_if(mbedtls_ct_condition_t condition, void *buf, size_t len);
+
+/** Shift some data towards the left inside a buffer.
+ *
+ * Functionally equivalent to:
+ *
+ * memmove(start, start + offset, total - offset);
+ * memset(start + (total - offset), 0, offset);
+ *
+ * Timing independence comes at the expense of performance.
+ *
+ * \param start     Secret. Pointer to the start of the buffer.
+ * \param total     Total size of the buffer.
+ * \param offset    Secret. Offset from which to copy \p total - \p offset bytes.
+ */
+void mbedtls_ct_memmove_left(void *start,
+                             size_t total,
+                             size_t offset);
+
+#endif /* defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) */
+
+/** Conditional memcpy.
+ *
+ * Functionally equivalent to:
+ *
+ * if (condition) {
+ *      memcpy(dest, src1, len);
+ * } else {
+ *      if (src2 != NULL)
+ *          memcpy(dest, src2, len);
+ * }
+ *
+ * It will always read len bytes from src1.
+ * If src2 != NULL, it will always read len bytes from src2.
+ * If src2 == NULL, it will instead read len bytes from dest (as if src2 == dest).
+ *
+ * \param condition The condition
+ * \param dest      Secret. Destination pointer.
+ * \param src1      Secret. Pointer to copy from (if \p condition == MBEDTLS_CT_TRUE). Shouldn't overlap with \p dest.
+ * \param src2      Secret (contents only - may branch to test if src2 == NULL).
+ *                  Pointer to copy from (if \p condition == MBEDTLS_CT_FALSE and \p src2 is not NULL). Shouldn't overlap with \p dest. May be NULL.
+ * \param len       Number of bytes to copy.
+ */
+void mbedtls_ct_memcpy_if(mbedtls_ct_condition_t condition,
+                          unsigned char *dest,
+                          const unsigned char *src1,
+                          const unsigned char *src2,
+                          size_t len
+                          );
+
+/** Copy data from a secret position.
+ *
+ * Functionally equivalent to:
+ *
+ * memcpy(dst, src + offset, len)
+ *
+ * This function copies \p len bytes from \p src_base + \p offset to \p
+ * dst, with a code flow and memory access pattern that does not depend on
+ * \p offset, but only on \p offset_min, \p offset_max and \p len.
+ *
+ * \note                This function reads from \p dest, but the value that
+ *                      is read does not influence the result and this
+ *                      function's behavior is well-defined regardless of the
+ *                      contents of the buffers. This may result in false
+ *                      positives from static or dynamic analyzers, especially
+ *                      if \p dest is not initialized.
+ *
+ * \param dest          Secret. The destination buffer. This must point to a writable
+ *                      buffer of at least \p len bytes.
+ * \param src           Secret. The base of the source buffer. This must point to a
+ *                      readable buffer of at least \p offset_max + \p len
+ *                      bytes. Shouldn't overlap with \p dest.
+ * \param offset        Secret. The offset in the source buffer from which to copy.
+ *                      This must be no less than \p offset_min and no greater
+ *                      than \p offset_max.
+ * \param offset_min    The minimal value of \p offset.
+ * \param offset_max    The maximal value of \p offset.
+ * \param len           The number of bytes to copy.
+ */
+void mbedtls_ct_memcpy_offset(unsigned char *dest,
+                              const unsigned char *src,
+                              size_t offset,
+                              size_t offset_min,
+                              size_t offset_max,
+                              size_t len);
+
+/* Documented in include/mbedtls/constant_time.h. a and b are secret. */
+int mbedtls_ct_memcmp(const void *a,
+                      const void *b,
+                      size_t n);
+
 #endif /* MBEDTLS_CONSTANT_TIME_INTERNAL_H */
diff --git a/library/constant_time_invasive.h b/library/constant_time_invasive.h
deleted file mode 100644
index c176b28..0000000
--- a/library/constant_time_invasive.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/**
- * \file constant_time_invasive.h
- *
- * \brief Constant-time module: interfaces for invasive testing only.
- *
- * The interfaces in this file are intended for testing purposes only.
- * They SHOULD NOT be made available in library integrations except when
- * building the library for testing.
- */
-/*
- *  Copyright The Mbed TLS Contributors
- *  SPDX-License-Identifier: Apache-2.0
- *
- *  Licensed under the Apache License, Version 2.0 (the "License"); you may
- *  not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-#ifndef MBEDTLS_CONSTANT_TIME_INVASIVE_H
-#define MBEDTLS_CONSTANT_TIME_INVASIVE_H
-
-#include "common.h"
-
-#if defined(MBEDTLS_TEST_HOOKS)
-
-/** Turn a value into a mask:
- * - if \p low <= \p c <= \p high,
- *   return the all-bits 1 mask, aka (unsigned) -1
- * - otherwise, return the all-bits 0 mask, aka 0
- *
- * \param low   The value to analyze.
- * \param high  The value to analyze.
- * \param c     The value to analyze.
- *
- * \return      All-bits-one if \p low <= \p c <= \p high, otherwise zero.
- */
-unsigned char mbedtls_ct_uchar_mask_of_range(unsigned char low,
-                                             unsigned char high,
-                                             unsigned char c);
-
-#endif /* MBEDTLS_TEST_HOOKS */
-
-#endif /* MBEDTLS_CONSTANT_TIME_INVASIVE_H */