Merge pull request #6208 from AndrzejKurek/tls-tests-no-md-structured

Remove the dependency on MD from TLS 1.2 tests
diff --git a/ChangeLog.d/fix-ctr-drbg-may-free-invalid-aes-context.txt b/ChangeLog.d/fix-ctr-drbg-may-free-invalid-aes-context.txt
new file mode 100644
index 0000000..fe62c28
--- /dev/null
+++ b/ChangeLog.d/fix-ctr-drbg-may-free-invalid-aes-context.txt
@@ -0,0 +1,4 @@
+Bugfix
+    * Fix mbedtls_ctr_drbg_free() on an initialized but unseeded context. When
+      MBEDTLS_AES_ALT is enabled, it could call mbedtls_aes_free() on an
+      uninitialized context.
diff --git a/include/mbedtls/ecp.h b/include/mbedtls/ecp.h
index ac8b7c0..0c1790d 100644
--- a/include/mbedtls/ecp.h
+++ b/include/mbedtls/ecp.h
@@ -918,7 +918,7 @@
  * \note            To prevent timing attacks, this function
  *                  executes the exact same sequence of base-field
  *                  operations for any valid \p m. It avoids any if-branch or
- *                  array index depending on the value of \p m. If also uses
+ *                  array index depending on the value of \p m. It also uses
  *                  \p f_rng to randomize some intermediate results.
  *
  * \param grp       The ECP group to use.
diff --git a/include/mbedtls/mbedtls_config.h b/include/mbedtls/mbedtls_config.h
index fd2391d..e9487b2 100644
--- a/include/mbedtls/mbedtls_config.h
+++ b/include/mbedtls/mbedtls_config.h
@@ -2018,6 +2018,9 @@
  * Enable the multi-precision integer library.
  *
  * Module:  library/bignum.c
+ *          library/bignum_core.c
+ *          library/bignum_mod.c
+ *          library/bignum_mod_raw.c
  * Caller:  library/dhm.c
  *          library/ecp.c
  *          library/ecdsa.c
@@ -2683,7 +2686,7 @@
  * above to be specified at runtime or compile time respectively.
  *
  * \note This abstraction layer must be enabled on Windows (including MSYS2)
- * as other module rely on it for a fixed snprintf implementation.
+ * as other modules rely on it for a fixed snprintf implementation.
  *
  * Module:  library/platform.c
  * Caller:  Most other .c files
diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
index bcf9072..3d820a5 100644
--- a/include/mbedtls/ssl.h
+++ b/include/mbedtls/ssl.h
@@ -4736,7 +4736,7 @@
  *
  * \note           When this function returns #MBEDTLS_ERR_SSL_WANT_WRITE/READ,
  *                 it must be called later with the *same* arguments,
- *                 until it returns a value greater that or equal to 0. When
+ *                 until it returns a value greater than or equal to 0. When
  *                 the function returns #MBEDTLS_ERR_SSL_WANT_WRITE there may be
  *                 some partial data in the output buffer, however this is not
  *                 yet sent.
diff --git a/include/mbedtls/ssl_ticket.h b/include/mbedtls/ssl_ticket.h
index 98fd287..b8a8a24 100644
--- a/include/mbedtls/ssl_ticket.h
+++ b/include/mbedtls/ssl_ticket.h
@@ -34,6 +34,10 @@
 #include "mbedtls/ssl.h"
 #include "mbedtls/cipher.h"
 
+#if defined(MBEDTLS_HAVE_TIME)
+#include "mbedtls/platform_time.h"
+#endif
+
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
 #include "psa/crypto.h"
 #endif
@@ -56,7 +60,9 @@
 {
     unsigned char MBEDTLS_PRIVATE(name)[MBEDTLS_SSL_TICKET_KEY_NAME_BYTES];
                                                      /*!< random key identifier              */
-    uint32_t MBEDTLS_PRIVATE(generation_time);       /*!< key generation timestamp (seconds) */
+#if defined(MBEDTLS_HAVE_TIME)
+    mbedtls_time_t MBEDTLS_PRIVATE(generation_time); /*!< key generation timestamp (seconds) */
+#endif
 #if !defined(MBEDTLS_USE_PSA_CRYPTO)
     mbedtls_cipher_context_t MBEDTLS_PRIVATE(ctx);   /*!< context for auth enc/decryption    */
 #else
diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt
index ed58a9e..378cfb4 100644
--- a/library/CMakeLists.txt
+++ b/library/CMakeLists.txt
@@ -18,6 +18,9 @@
     asn1write.c
     base64.c
     bignum.c
+    bignum_core.c
+    bignum_mod.c
+    bignum_mod_raw.c
     camellia.c
     ccm.c
     chacha20.c
diff --git a/library/Makefile b/library/Makefile
index 2f58f66..85cea6b 100644
--- a/library/Makefile
+++ b/library/Makefile
@@ -83,6 +83,9 @@
 	     asn1write.o \
 	     base64.o \
 	     bignum.o \
+	     bignum_core.o \
+	     bignum_mod.o \
+	     bignum_mod_raw.o \
 	     camellia.o \
 	     ccm.o \
 	     chacha20.o \
diff --git a/library/bignum.c b/library/bignum.c
index 55325b4..acf620f 100644
--- a/library/bignum.c
+++ b/library/bignum.c
@@ -39,6 +39,7 @@
 
 #include "mbedtls/bignum.h"
 #include "bignum_internal.h"
+#include "bignum_core.h"
 #include "bn_mul.h"
 #include "mbedtls/platform_util.h"
 #include "mbedtls/error.h"
@@ -62,19 +63,8 @@
 #define MPI_VALIDATE( cond )                                           \
     MBEDTLS_INTERNAL_VALIDATE( cond )
 
-#define ciL    (sizeof(mbedtls_mpi_uint))         /* chars in limb  */
-#define biL    (ciL << 3)               /* bits  in limb  */
-#define biH    (ciL << 2)               /* half limb size */
-
 #define MPI_SIZE_T_MAX  ( (size_t) -1 ) /* SIZE_T_MAX is not standard */
 
-/*
- * Convert between bits/chars and number of limbs
- * Divide first in order to avoid potential overflows
- */
-#define BITS_TO_LIMBS(i)  ( (i) / biL + ( (i) % biL != 0 ) )
-#define CHARS_TO_LIMBS(i) ( (i) / ciL + ( (i) % ciL != 0 ) )
-
 /* Implementation that should never be optimized out by the compiler */
 static void mbedtls_mpi_zeroize( mbedtls_mpi_uint *v, size_t n )
 {
@@ -303,10 +293,6 @@
     return( ( X->p[pos / biL] >> ( pos % biL ) ) & 0x01 );
 }
 
-/* Get a specific byte, without range checks. */
-#define GET_BYTE( X, i )                                \
-    ( ( ( X )->p[( i ) / ciL] >> ( ( ( i ) % ciL ) * 8 ) ) & 0xff )
-
 /*
  * Set a bit to a specific value of 0 or 1
  */
@@ -353,40 +339,11 @@
 }
 
 /*
- * Count leading zero bits in a given integer
- */
-static size_t mbedtls_clz( const mbedtls_mpi_uint x )
-{
-    size_t j;
-    mbedtls_mpi_uint mask = (mbedtls_mpi_uint) 1 << (biL - 1);
-
-    for( j = 0; j < biL; j++ )
-    {
-        if( x & mask ) break;
-
-        mask >>= 1;
-    }
-
-    return j;
-}
-
-/*
  * Return the number of bits
  */
 size_t mbedtls_mpi_bitlen( const mbedtls_mpi *X )
 {
-    size_t i, j;
-
-    if( X->n == 0 )
-        return( 0 );
-
-    for( i = X->n - 1; i > 0; i-- )
-        if( X->p[i] != 0 )
-            break;
-
-    j = biL - mbedtls_clz( X->p[i] );
-
-    return( ( i * biL ) + j );
+    return( mbedtls_mpi_core_bitlen( X->p, X->n ) );
 }
 
 /*
@@ -693,97 +650,6 @@
 }
 #endif /* MBEDTLS_FS_IO */
 
-
-/* Convert a big-endian byte array aligned to the size of mbedtls_mpi_uint
- * into the storage form used by mbedtls_mpi. */
-
-static mbedtls_mpi_uint mpi_uint_bigendian_to_host_c( mbedtls_mpi_uint x )
-{
-    uint8_t i;
-    unsigned char *x_ptr;
-    mbedtls_mpi_uint tmp = 0;
-
-    for( i = 0, x_ptr = (unsigned char*) &x; i < ciL; i++, x_ptr++ )
-    {
-        tmp <<= CHAR_BIT;
-        tmp |= (mbedtls_mpi_uint) *x_ptr;
-    }
-
-    return( tmp );
-}
-
-static mbedtls_mpi_uint mpi_uint_bigendian_to_host( mbedtls_mpi_uint x )
-{
-#if defined(__BYTE_ORDER__)
-
-/* Nothing to do on bigendian systems. */
-#if ( __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ )
-    return( x );
-#endif /* __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ */
-
-#if ( __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ )
-
-/* For GCC and Clang, have builtins for byte swapping. */
-#if defined(__GNUC__) && defined(__GNUC_PREREQ)
-#if __GNUC_PREREQ(4,3)
-#define have_bswap
-#endif
-#endif
-
-#if defined(__clang__) && defined(__has_builtin)
-#if __has_builtin(__builtin_bswap32)  &&                 \
-    __has_builtin(__builtin_bswap64)
-#define have_bswap
-#endif
-#endif
-
-#if defined(have_bswap)
-    /* The compiler is hopefully able to statically evaluate this! */
-    switch( sizeof(mbedtls_mpi_uint) )
-    {
-        case 4:
-            return( __builtin_bswap32(x) );
-        case 8:
-            return( __builtin_bswap64(x) );
-    }
-#endif
-#endif /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ */
-#endif /* __BYTE_ORDER__ */
-
-    /* Fall back to C-based reordering if we don't know the byte order
-     * or we couldn't use a compiler-specific builtin. */
-    return( mpi_uint_bigendian_to_host_c( x ) );
-}
-
-static void mpi_bigendian_to_host( mbedtls_mpi_uint * const p, size_t limbs )
-{
-    mbedtls_mpi_uint *cur_limb_left;
-    mbedtls_mpi_uint *cur_limb_right;
-    if( limbs == 0 )
-        return;
-
-    /*
-     * Traverse limbs and
-     * - adapt byte-order in each limb
-     * - swap the limbs themselves.
-     * For that, simultaneously traverse the limbs from left to right
-     * and from right to left, as long as the left index is not bigger
-     * than the right index (it's not a problem if limbs is odd and the
-     * indices coincide in the last iteration).
-     */
-    for( cur_limb_left = p, cur_limb_right = p + ( limbs - 1 );
-         cur_limb_left <= cur_limb_right;
-         cur_limb_left++, cur_limb_right-- )
-    {
-        mbedtls_mpi_uint tmp;
-        /* Note that if cur_limb_left == cur_limb_right,
-         * this code effectively swaps the bytes only once. */
-        tmp             = mpi_uint_bigendian_to_host( *cur_limb_left  );
-        *cur_limb_left  = mpi_uint_bigendian_to_host( *cur_limb_right );
-        *cur_limb_right = tmp;
-    }
-}
-
 /*
  * Import X from unsigned binary data, little endian
  *
@@ -794,14 +660,12 @@
                                 const unsigned char *buf, size_t buflen )
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
-    size_t i;
-    size_t const limbs = CHARS_TO_LIMBS( buflen );
+    const size_t limbs = CHARS_TO_LIMBS( buflen );
 
     /* Ensure that target MPI has exactly the necessary number of limbs */
     MBEDTLS_MPI_CHK( mbedtls_mpi_resize_clear( X, limbs ) );
 
-    for( i = 0; i < buflen; i++ )
-        X->p[i / ciL] |= ((mbedtls_mpi_uint) buf[i]) << ((i % ciL) << 3);
+    MBEDTLS_MPI_CHK( mbedtls_mpi_core_read_le( X->p, X->n, buf, buflen ) );
 
 cleanup:
 
@@ -822,9 +686,7 @@
 int mbedtls_mpi_read_binary( mbedtls_mpi *X, const unsigned char *buf, size_t buflen )
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
-    size_t const limbs    = CHARS_TO_LIMBS( buflen );
-    size_t const overhead = ( limbs * ciL ) - buflen;
-    unsigned char *Xp;
+    const size_t limbs = CHARS_TO_LIMBS( buflen );
 
     MPI_VALIDATE_RET( X != NULL );
     MPI_VALIDATE_RET( buflen == 0 || buf != NULL );
@@ -832,15 +694,7 @@
     /* Ensure that target MPI has exactly the necessary number of limbs */
     MBEDTLS_MPI_CHK( mbedtls_mpi_resize_clear( X, limbs ) );
 
-    /* Avoid calling `memcpy` with NULL source or destination argument,
-     * even if buflen is 0. */
-    if( buflen != 0 )
-    {
-        Xp = (unsigned char*) X->p;
-        memcpy( Xp + overhead, buf, buflen );
-
-        mpi_bigendian_to_host( X->p, limbs );
-    }
+    MBEDTLS_MPI_CHK( mbedtls_mpi_core_read_be( X->p, X->n, buf, buflen ) );
 
 cleanup:
 
@@ -858,37 +712,7 @@
 int mbedtls_mpi_write_binary_le( const mbedtls_mpi *X,
                                  unsigned char *buf, size_t buflen )
 {
-    size_t stored_bytes = X->n * ciL;
-    size_t bytes_to_copy;
-    size_t i;
-
-    if( stored_bytes < buflen )
-    {
-        bytes_to_copy = stored_bytes;
-    }
-    else
-    {
-        bytes_to_copy = buflen;
-
-        /* The output buffer is smaller than the allocated size of X.
-         * However X may fit if its leading bytes are zero. */
-        for( i = bytes_to_copy; i < stored_bytes; i++ )
-        {
-            if( GET_BYTE( X, i ) != 0 )
-                return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL );
-        }
-    }
-
-    for( i = 0; i < bytes_to_copy; i++ )
-        buf[i] = GET_BYTE( X, i );
-
-    if( stored_bytes < buflen )
-    {
-        /* Write trailing 0 bytes */
-        memset( buf + stored_bytes, 0, buflen - stored_bytes );
-    }
-
-    return( 0 );
+    return( mbedtls_mpi_core_write_le( X->p, X->n, buf, buflen ) );
 }
 
 /*
@@ -897,44 +721,7 @@
 int mbedtls_mpi_write_binary( const mbedtls_mpi *X,
                               unsigned char *buf, size_t buflen )
 {
-    size_t stored_bytes;
-    size_t bytes_to_copy;
-    unsigned char *p;
-    size_t i;
-
-    MPI_VALIDATE_RET( X != NULL );
-    MPI_VALIDATE_RET( buflen == 0 || buf != NULL );
-
-    stored_bytes = X->n * ciL;
-
-    if( stored_bytes < buflen )
-    {
-        /* There is enough space in the output buffer. Write initial
-         * null bytes and record the position at which to start
-         * writing the significant bytes. In this case, the execution
-         * trace of this function does not depend on the value of the
-         * number. */
-        bytes_to_copy = stored_bytes;
-        p = buf + buflen - stored_bytes;
-        memset( buf, 0, buflen - stored_bytes );
-    }
-    else
-    {
-        /* The output buffer is smaller than the allocated size of X.
-         * However X may fit if its leading bytes are zero. */
-        bytes_to_copy = buflen;
-        p = buf;
-        for( i = bytes_to_copy; i < stored_bytes; i++ )
-        {
-            if( GET_BYTE( X, i ) != 0 )
-                return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL );
-        }
-    }
-
-    for( i = 0; i < bytes_to_copy; i++ )
-        p[bytes_to_copy - i - 1] = GET_BYTE( X, i );
-
-    return( 0 );
+    return( mbedtls_mpi_core_write_be( X->p, X->n, buf, buflen ) );
 }
 
 /*
@@ -1545,7 +1332,7 @@
     /*
      * Normalize the divisor, d, and dividend, u0, u1
      */
-    s = mbedtls_clz( d );
+    s = mbedtls_mpi_core_clz( d );
     d = d << s;
 
     u1 = u1 << s;
@@ -2334,7 +2121,7 @@
     memset( X->p, 0, overhead );
     memset( (unsigned char *) X->p + limbs * ciL, 0, ( X->n - limbs ) * ciL );
     MBEDTLS_MPI_CHK( f_rng( p_rng, (unsigned char *) X->p + overhead, n_bytes ) );
-    mpi_bigendian_to_host( X->p, limbs );
+    mbedtls_mpi_core_bigendian_to_host( X->p, limbs );
 
 cleanup:
     return( ret );
@@ -2352,7 +2139,7 @@
                      void *p_rng )
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
-    size_t const limbs = CHARS_TO_LIMBS( size );
+    const size_t limbs = CHARS_TO_LIMBS( size );
 
     MPI_VALIDATE_RET( X     != NULL );
     MPI_VALIDATE_RET( f_rng != NULL );
diff --git a/library/bignum_core.c b/library/bignum_core.c
new file mode 100644
index 0000000..8e89766
--- /dev/null
+++ b/library/bignum_core.c
@@ -0,0 +1,294 @@
+/*
+ *  Core bignum functions
+ *
+ *  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.
+ */
+
+#include "common.h"
+
+#if defined(MBEDTLS_BIGNUM_C)
+
+#include <string.h>
+
+#include "mbedtls/error.h"
+#include "mbedtls/platform_util.h"
+
+#if defined(MBEDTLS_PLATFORM_C)
+#include "mbedtls/platform.h"
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#define mbedtls_printf      printf
+#define mbedtls_calloc      calloc
+#define mbedtls_free        free
+#endif
+
+#include "bignum_core.h"
+
+size_t mbedtls_mpi_core_clz( mbedtls_mpi_uint a )
+{
+    size_t j;
+    mbedtls_mpi_uint mask = (mbedtls_mpi_uint) 1 << (biL - 1);
+
+    for( j = 0; j < biL; j++ )
+    {
+        if( a & mask ) break;
+
+        mask >>= 1;
+    }
+
+    return( j );
+}
+
+size_t mbedtls_mpi_core_bitlen( const mbedtls_mpi_uint *A, size_t A_limbs )
+{
+    size_t i, j;
+
+    if( A_limbs == 0 )
+        return( 0 );
+
+    for( i = A_limbs - 1; i > 0; i-- )
+        if( A[i] != 0 )
+            break;
+
+    j = biL - mbedtls_mpi_core_clz( A[i] );
+
+    return( ( i * biL ) + j );
+}
+
+/* Convert a big-endian byte array aligned to the size of mbedtls_mpi_uint
+ * into the storage form used by mbedtls_mpi. */
+static mbedtls_mpi_uint mpi_bigendian_to_host_c( mbedtls_mpi_uint a )
+{
+    uint8_t i;
+    unsigned char *a_ptr;
+    mbedtls_mpi_uint tmp = 0;
+
+    for( i = 0, a_ptr = (unsigned char *) &a; i < ciL; i++, a_ptr++ )
+    {
+        tmp <<= CHAR_BIT;
+        tmp |= (mbedtls_mpi_uint) *a_ptr;
+    }
+
+    return( tmp );
+}
+
+static mbedtls_mpi_uint mpi_bigendian_to_host( mbedtls_mpi_uint a )
+{
+#if defined(__BYTE_ORDER__)
+
+/* Nothing to do on bigendian systems. */
+#if ( __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ )
+    return( a );
+#endif /* __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ */
+
+#if ( __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ )
+
+/* For GCC and Clang, have builtins for byte swapping. */
+#if defined(__GNUC__) && defined(__GNUC_PREREQ)
+#if __GNUC_PREREQ(4,3)
+#define have_bswap
+#endif
+#endif
+
+#if defined(__clang__) && defined(__has_builtin)
+#if __has_builtin(__builtin_bswap32)  &&                 \
+    __has_builtin(__builtin_bswap64)
+#define have_bswap
+#endif
+#endif
+
+#if defined(have_bswap)
+    /* The compiler is hopefully able to statically evaluate this! */
+    switch( sizeof(mbedtls_mpi_uint) )
+    {
+        case 4:
+            return( __builtin_bswap32(a) );
+        case 8:
+            return( __builtin_bswap64(a) );
+    }
+#endif
+#endif /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ */
+#endif /* __BYTE_ORDER__ */
+
+    /* Fall back to C-based reordering if we don't know the byte order
+     * or we couldn't use a compiler-specific builtin. */
+    return( mpi_bigendian_to_host_c( a ) );
+}
+
+void mbedtls_mpi_core_bigendian_to_host( mbedtls_mpi_uint *A,
+                                         size_t A_limbs )
+{
+    mbedtls_mpi_uint *cur_limb_left;
+    mbedtls_mpi_uint *cur_limb_right;
+    if( A_limbs == 0 )
+        return;
+
+    /*
+     * Traverse limbs and
+     * - adapt byte-order in each limb
+     * - swap the limbs themselves.
+     * For that, simultaneously traverse the limbs from left to right
+     * and from right to left, as long as the left index is not bigger
+     * than the right index (it's not a problem if limbs is odd and the
+     * indices coincide in the last iteration).
+     */
+    for( cur_limb_left = A, cur_limb_right = A + ( A_limbs - 1 );
+         cur_limb_left <= cur_limb_right;
+         cur_limb_left++, cur_limb_right-- )
+    {
+        mbedtls_mpi_uint tmp;
+        /* Note that if cur_limb_left == cur_limb_right,
+         * this code effectively swaps the bytes only once. */
+        tmp             = mpi_bigendian_to_host( *cur_limb_left  );
+        *cur_limb_left  = mpi_bigendian_to_host( *cur_limb_right );
+        *cur_limb_right = tmp;
+    }
+}
+
+int mbedtls_mpi_core_read_le( mbedtls_mpi_uint *X,
+                              size_t X_limbs,
+                              const unsigned char *input,
+                              size_t input_length )
+{
+    const size_t limbs = CHARS_TO_LIMBS( input_length );
+
+    if( X_limbs < limbs )
+        return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL );
+
+    if( X != NULL )
+    {
+        memset( X, 0, X_limbs * ciL );
+
+        for( size_t i = 0; i < input_length; i++ )
+        {
+            size_t offset = ( ( i % ciL ) << 3 );
+            X[i / ciL] |= ( (mbedtls_mpi_uint) input[i] ) << offset;
+        }
+    }
+
+    return( 0 );
+}
+
+int mbedtls_mpi_core_read_be( mbedtls_mpi_uint *X,
+                              size_t X_limbs,
+                              const unsigned char *input,
+                              size_t input_length )
+{
+    const size_t limbs = CHARS_TO_LIMBS( input_length );
+
+    if( X_limbs < limbs )
+        return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL );
+
+    /* If X_limbs is 0, input_length must also be 0 (from previous test).
+     * Nothing to do. */
+    if( X_limbs == 0 )
+        return( 0 );
+
+    memset( X, 0, X_limbs * ciL );
+
+    /* memcpy() with (NULL, 0) is undefined behaviour */
+    if( input_length != 0 )
+    {
+        size_t overhead = ( X_limbs * ciL ) - input_length;
+        unsigned char *Xp = (unsigned char *) X;
+        memcpy( Xp + overhead, input, input_length );
+    }
+
+    mbedtls_mpi_core_bigendian_to_host( X, X_limbs );
+
+    return( 0 );
+}
+
+int mbedtls_mpi_core_write_le( const mbedtls_mpi_uint *A,
+                               size_t A_limbs,
+                               unsigned char *output,
+                               size_t output_length )
+{
+    size_t stored_bytes = A_limbs * ciL;
+    size_t bytes_to_copy;
+
+    if( stored_bytes < output_length )
+    {
+        bytes_to_copy = stored_bytes;
+    }
+    else
+    {
+        bytes_to_copy = output_length;
+
+        /* The output buffer is smaller than the allocated size of A.
+         * However A may fit if its leading bytes are zero. */
+        for( size_t i = bytes_to_copy; i < stored_bytes; i++ )
+        {
+            if( GET_BYTE( A, i ) != 0 )
+                return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL );
+        }
+    }
+
+    for( size_t i = 0; i < bytes_to_copy; i++ )
+        output[i] = GET_BYTE( A, i );
+
+    if( stored_bytes < output_length )
+    {
+        /* Write trailing 0 bytes */
+        memset( output + stored_bytes, 0, output_length - stored_bytes );
+    }
+
+    return( 0 );
+}
+
+int mbedtls_mpi_core_write_be( const mbedtls_mpi_uint *X,
+                               size_t X_limbs,
+                               unsigned char *output,
+                               size_t output_length )
+{
+    size_t stored_bytes;
+    size_t bytes_to_copy;
+    unsigned char *p;
+
+    stored_bytes = X_limbs * ciL;
+
+    if( stored_bytes < output_length )
+    {
+        /* There is enough space in the output buffer. Write initial
+         * null bytes and record the position at which to start
+         * writing the significant bytes. In this case, the execution
+         * trace of this function does not depend on the value of the
+         * number. */
+        bytes_to_copy = stored_bytes;
+        p = output + output_length - stored_bytes;
+        memset( output, 0, output_length - stored_bytes );
+    }
+    else
+    {
+        /* The output buffer is smaller than the allocated size of X.
+         * However X may fit if its leading bytes are zero. */
+        bytes_to_copy = output_length;
+        p = output;
+        for( size_t i = bytes_to_copy; i < stored_bytes; i++ )
+        {
+            if( GET_BYTE( X, i ) != 0 )
+                return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL );
+        }
+    }
+
+    for( size_t i = 0; i < bytes_to_copy; i++ )
+        p[bytes_to_copy - i - 1] = GET_BYTE( X, i );
+
+    return( 0 );
+}
+
+#endif /* MBEDTLS_BIGNUM_C */
diff --git a/library/bignum_core.h b/library/bignum_core.h
new file mode 100644
index 0000000..434f52b
--- /dev/null
+++ b/library/bignum_core.h
@@ -0,0 +1,158 @@
+/**
+ *  Core bignum functions
+ *
+ *  This interface should only be used by the legacy bignum module (bignum.h)
+ *  and the modular bignum modules (bignum_mod.c, bignum_mod_raw.c). All other
+ *  modules should use the high-level modular bignum interface (bignum_mod.h)
+ *  or the legacy bignum interface (bignum.h).
+ *
+ *  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_BIGNUM_CORE_H
+#define MBEDTLS_BIGNUM_CORE_H
+
+#include "common.h"
+
+#if defined(MBEDTLS_BIGNUM_C)
+#include "mbedtls/bignum.h"
+#endif
+
+/** Count leading zero bits in a given integer.
+ *
+ * \param a     Integer to count leading zero bits.
+ *
+ * \return      The number of leading zero bits in \p a.
+ */
+size_t mbedtls_mpi_core_clz( mbedtls_mpi_uint a );
+
+/** Return the minimum number of bits required to represent the value held
+ * in the MPI.
+ *
+ * \note This function returns 0 if all the limbs of \p A are 0.
+ *
+ * \param[in] A     The address of the MPI.
+ * \param A_limbs   The number of limbs of \p A.
+ *
+ * \return      The number of bits in \p A.
+ */
+size_t mbedtls_mpi_core_bitlen( const mbedtls_mpi_uint *A, size_t A_limbs );
+
+/** Convert a big-endian byte array aligned to the size of mbedtls_mpi_uint
+ * into the storage form used by mbedtls_mpi.
+ *
+ * \param[in,out] A     The address of the MPI.
+ * \param A_limbs       The number of limbs of \p A.
+ */
+void mbedtls_mpi_core_bigendian_to_host( mbedtls_mpi_uint *A,
+                                         size_t A_limbs );
+
+/** Import X from unsigned binary data, little-endian.
+ *
+ * The MPI needs to have enough limbs to store the full value (including any
+ * most significant zero bytes in the input).
+ *
+ * \param[out] X         The address of the MPI.
+ * \param X_limbs        The number of limbs of \p X.
+ * \param[in] input      The input buffer to import from.
+ * \param input_length   The length bytes of \p input.
+ *
+ * \return       \c 0 if successful.
+ * \return       #MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if \p X isn't
+ *               large enough to hold the value in \p input.
+ */
+int mbedtls_mpi_core_read_le( mbedtls_mpi_uint *X,
+                              size_t X_limbs,
+                              const unsigned char *input,
+                              size_t input_length );
+
+/** Import X from unsigned binary data, big-endian.
+ *
+ * The MPI needs to have enough limbs to store the full value (including any
+ * most significant zero bytes in the input).
+ *
+ * \param[out] X        The address of the MPI.
+ *                      May only be #NULL if \X_limbs is 0 and \p input_length
+ *                      is 0.
+ * \param X_limbs       The number of limbs of \p X.
+ * \param[in] input     The input buffer to import from.
+ *                      May only be #NULL if \p input_length is 0.
+ * \param input_length  The length in bytes of \p input.
+ *
+ * \return       \c 0 if successful.
+ * \return       #MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if \p X isn't
+ *               large enough to hold the value in \p input.
+ */
+int mbedtls_mpi_core_read_be( mbedtls_mpi_uint *X,
+                              size_t X_limbs,
+                              const unsigned char *input,
+                              size_t input_length );
+
+/** Export A into unsigned binary data, little-endian.
+ *
+ * \note If \p output is shorter than \p A the export is still successful if the
+ *       value held in \p A fits in the buffer (that is, if enough of the most
+ *       significant bytes of \p A are 0).
+ *
+ * \param[in] A         The address of the MPI.
+ * \param A_limbs       The number of limbs of \p A.
+ * \param[out] output   The output buffer to export to.
+ * \param output_length The length in bytes of \p output.
+ *
+ * \return       \c 0 if successful.
+ * \return       #MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if \p output isn't
+ *               large enough to hold the value of \p A.
+ */
+int mbedtls_mpi_core_write_le( const mbedtls_mpi_uint *A,
+                               size_t A_limbs,
+                               unsigned char *output,
+                               size_t output_length );
+
+/** Export A into unsigned binary data, big-endian.
+ *
+ * \note If \p output is shorter than \p A the export is still successful if the
+ *       value held in \p A fits in the buffer (that is, if enough of the most
+ *       significant bytes of \p A are 0).
+ *
+ * \param[in] A         The address of the MPI.
+ * \param A_limbs       The number of limbs of \p A.
+ * \param[out] output   The output buffer to export to.
+ * \param output_length The length in bytes of \p output.
+ *
+ * \return       \c 0 if successful.
+ * \return       #MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if \p output isn't
+ *               large enough to hold the value of \p A.
+ */
+int mbedtls_mpi_core_write_be( const mbedtls_mpi_uint *A,
+                               size_t A_limbs,
+                               unsigned char *output,
+                               size_t output_length );
+
+#define ciL    ( sizeof(mbedtls_mpi_uint) )   /* chars in limb  */
+#define biL    ( ciL << 3 )                   /* bits  in limb  */
+#define biH    ( ciL << 2 )                   /* half limb size */
+
+/*
+ * Convert between bits/chars and number of limbs
+ * Divide first in order to avoid potential overflows
+ */
+#define BITS_TO_LIMBS(i)  ( (i) / biL + ( (i) % biL != 0 ) )
+#define CHARS_TO_LIMBS(i) ( (i) / ciL + ( (i) % ciL != 0 ) )
+/* Get a specific byte, without range checks. */
+#define GET_BYTE( X, i )                                \
+    ( ( (X)[(i) / ciL] >> ( ( (i) % ciL ) * 8 ) ) & 0xff )
+
+#endif /* MBEDTLS_BIGNUM_CORE_H */
diff --git a/library/bignum_mod.c b/library/bignum_mod.c
new file mode 100644
index 0000000..de28093
--- /dev/null
+++ b/library/bignum_mod.c
@@ -0,0 +1,152 @@
+/**
+ *  Modular bignum functions
+ *
+ *  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.
+ */
+
+#include "common.h"
+
+#if defined(MBEDTLS_BIGNUM_C)
+
+#include <string.h>
+
+#include "mbedtls/platform_util.h"
+#include "mbedtls/error.h"
+#include "mbedtls/bignum.h"
+
+#if defined(MBEDTLS_PLATFORM_C)
+#include "mbedtls/platform.h"
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#define mbedtls_printf      printf
+#define mbedtls_calloc      calloc
+#define mbedtls_free        free
+#endif
+
+#include "bignum_core.h"
+#include "bignum_mod.h"
+#include "bignum_mod_raw.h"
+#include "constant_time_internal.h"
+
+int mbedtls_mpi_mod_residue_setup( mbedtls_mpi_mod_residue *r,
+                                   const mbedtls_mpi_mod_modulus *m,
+                                   mbedtls_mpi_uint *p,
+                                   size_t p_limbs )
+{
+    if( p_limbs < m->limbs || !mbedtls_mpi_core_lt_ct( m->p, p, p_limbs ) )
+        return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
+
+    r->limbs = m->limbs;
+    r->p = p;
+
+    return( 0 );
+}
+
+void mbedtls_mpi_mod_residue_release( mbedtls_mpi_mod_residue *r )
+{
+    if ( r == NULL )
+        return;
+
+    r->limbs = 0;
+    r->p = NULL;
+}
+
+void mbedtls_mpi_mod_modulus_init( mbedtls_mpi_mod_modulus *m )
+{
+    if ( m == NULL )
+        return;
+
+    m->p = NULL;
+    m->limbs = 0;
+    m->bits = 0;
+    m->ext_rep = MBEDTLS_MPI_MOD_EXT_REP_INVALID;
+    m->int_rep = MBEDTLS_MPI_MOD_REP_INVALID;
+}
+
+void mbedtls_mpi_mod_modulus_free( mbedtls_mpi_mod_modulus *m )
+{
+    if ( m == NULL )
+        return;
+
+    switch( m->int_rep )
+    {
+        case MBEDTLS_MPI_MOD_REP_MONTGOMERY:
+            mbedtls_free( m->rep.mont );
+            break;
+        case MBEDTLS_MPI_MOD_REP_OPT_RED:
+            mbedtls_free( m->rep.ored );
+            break;
+        case MBEDTLS_MPI_MOD_REP_INVALID:
+            break;
+    }
+
+    m->p = NULL;
+    m->limbs = 0;
+    m->bits = 0;
+    m->ext_rep = MBEDTLS_MPI_MOD_EXT_REP_INVALID;
+    m->int_rep = MBEDTLS_MPI_MOD_REP_INVALID;
+}
+
+int mbedtls_mpi_mod_modulus_setup( mbedtls_mpi_mod_modulus *m,
+                                   const mbedtls_mpi_uint *p,
+                                   size_t p_limbs,
+                                   mbedtls_mpi_mod_ext_rep ext_rep,
+                                   mbedtls_mpi_mod_rep_selector int_rep )
+{
+    int ret = 0;
+
+    m->p = p;
+    m->limbs = p_limbs;
+    m->bits = mbedtls_mpi_core_bitlen( p, p_limbs );
+
+    switch( ext_rep )
+    {
+        case MBEDTLS_MPI_MOD_EXT_REP_LE:
+        case MBEDTLS_MPI_MOD_EXT_REP_BE:
+            m->ext_rep = ext_rep;
+            break;
+        default:
+            ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
+            goto exit;
+    }
+
+    switch( int_rep )
+    {
+        case MBEDTLS_MPI_MOD_REP_MONTGOMERY:
+            m->int_rep = int_rep;
+            m->rep.mont = NULL;
+            break;
+        case MBEDTLS_MPI_MOD_REP_OPT_RED:
+            m->int_rep = int_rep;
+            m->rep.ored = NULL;
+            break;
+        default:
+            ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
+            goto exit;
+    }
+
+exit:
+
+    if( ret != 0 )
+    {
+        mbedtls_mpi_mod_modulus_free( m );
+    }
+
+    return( ret );
+}
+
+#endif /* MBEDTLS_BIGNUM_C */
diff --git a/library/bignum_mod.h b/library/bignum_mod.h
new file mode 100644
index 0000000..9d28bc7
--- /dev/null
+++ b/library/bignum_mod.h
@@ -0,0 +1,143 @@
+/**
+ *  Modular bignum functions
+ *
+ *  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_BIGNUM_MOD_H
+#define MBEDTLS_BIGNUM_MOD_H
+
+#include "common.h"
+
+#if defined(MBEDTLS_BIGNUM_C)
+#include "mbedtls/bignum.h"
+#endif
+
+/* Skip 1 as it is slightly easier to accidentally pass to functions. */
+typedef enum
+{
+    MBEDTLS_MPI_MOD_REP_INVALID    = 0,
+    MBEDTLS_MPI_MOD_REP_MONTGOMERY = 2,
+    MBEDTLS_MPI_MOD_REP_OPT_RED
+} mbedtls_mpi_mod_rep_selector;
+
+/* Make mbedtls_mpi_mod_rep_selector and mbedtls_mpi_mod_ext_rep disjoint to
+ * make it easier to catch when they are accidentally swapped. */
+typedef enum
+{
+    MBEDTLS_MPI_MOD_EXT_REP_INVALID = 0,
+    MBEDTLS_MPI_MOD_EXT_REP_LE      = 8,
+    MBEDTLS_MPI_MOD_EXT_REP_BE
+} mbedtls_mpi_mod_ext_rep;
+
+typedef struct
+{
+    mbedtls_mpi_uint *p;
+    size_t limbs;
+} mbedtls_mpi_mod_residue;
+
+typedef void *mbedtls_mpi_mont_struct;
+typedef void *mbedtls_mpi_opt_red_struct;
+
+typedef struct {
+    const mbedtls_mpi_uint *p;
+    size_t limbs;                            // number of limbs
+    size_t bits;                             // bitlen of p
+    mbedtls_mpi_mod_ext_rep ext_rep;         // signals external representation (eg. byte order)
+    mbedtls_mpi_mod_rep_selector int_rep;    // selector to signal the active member of the union
+    union rep
+    {
+        mbedtls_mpi_mont_struct mont;
+        mbedtls_mpi_opt_red_struct ored;
+    } rep;
+} mbedtls_mpi_mod_modulus;
+
+/** Setup a residue structure.
+ *
+ * \param[out] r    The address of residue to setup. The size is determined by
+ *                  \p m.
+ *                  (In particular, it must have at least as many limbs as the
+ *                  modulus \p m.)
+ * \param[in] m     The address of the modulus related to \p r.
+ * \param[in] p     The address of the limb array storing the value of \p r.
+ *                  The memory pointed to by \p p will be used by \p r and must
+ *                  not be modified in any way until after
+ *                  mbedtls_mpi_mod_residue_release() is called.
+ * \param p_limbs   The number of limbs of \p p.
+ *
+ * \return      \c 0 if successful.
+ * \return      #MBEDTLS_ERR_MPI_BAD_INPUT_DATA if \p p_limbs is less than the
+ *              limbs in \p m or if \p p is not less than \p m.
+ */
+int mbedtls_mpi_mod_residue_setup( mbedtls_mpi_mod_residue *r,
+                                   const mbedtls_mpi_mod_modulus *m,
+                                   mbedtls_mpi_uint *p,
+                                   size_t p_limbs );
+
+/** Unbind elements of a residue structure.
+ *
+ * This function removes the reference to the limb array that was passed to
+ * mbedtls_mpi_mod_residue_setup() to make it safe to free or use again.
+ *
+ * This function invalidates \p r and it must not be used until after
+ * mbedtls_mpi_mod_residue_setup() is called on it again.
+ *
+ * \param[out] r     The address of residue to release.
+ */
+void mbedtls_mpi_mod_residue_release( mbedtls_mpi_mod_residue *r );
+
+/** Initialize a modulus structure.
+ *
+ * \param[out] m     The address of the modulus structure to initialize.
+ */
+void mbedtls_mpi_mod_modulus_init( mbedtls_mpi_mod_modulus *m );
+
+/** Setup a modulus structure.
+ *
+ * \param[out] m    The address of the modulus structure to populate.
+ * \param[in] p     The address of the limb array storing the value of \p m.
+ *                  The memory pointed to by \p p will be used by \p m and must
+ *                  not be modified in any way until after
+ *                  mbedtls_mpi_mod_modulus_free() is called.
+ * \param p_limbs   The number of limbs of \p p.
+ * \param ext_rep   The external representation to be used for residues
+ *                  associated with \p m (see #mbedtls_mpi_mod_ext_rep).
+ * \param int_rep   The internal representation to be used for residues
+ *                  associated with \p m (see #mbedtls_mpi_mod_rep_selector).
+ *
+ * \return      \c 0 if successful.
+ * \return      #MBEDTLS_ERR_MPI_BAD_INPUT_DATA if \p ext_rep or \p int_rep is
+ *              invalid.
+ */
+int mbedtls_mpi_mod_modulus_setup( mbedtls_mpi_mod_modulus *m,
+                                   const mbedtls_mpi_uint *p,
+                                   size_t p_limbs,
+                                   mbedtls_mpi_mod_ext_rep ext_rep,
+                                   mbedtls_mpi_mod_rep_selector int_rep );
+
+/** Free elements of a modulus structure.
+ *
+ * This function frees any memory allocated by mbedtls_mpi_mod_modulus_setup().
+ *
+ * \warning This function does not free the limb array passed to
+ *          mbedtls_mpi_mod_modulus_setup() only removes the reference to it,
+ *          making it safe to free or to use it again.
+ *
+ * \param[in,out] m     The address of the modulus structure to free.
+ */
+void mbedtls_mpi_mod_modulus_free( mbedtls_mpi_mod_modulus *m );
+
+#endif /* MBEDTLS_BIGNUM_MOD_H */
diff --git a/library/bignum_mod_raw.c b/library/bignum_mod_raw.c
new file mode 100644
index 0000000..8c89b2c
--- /dev/null
+++ b/library/bignum_mod_raw.c
@@ -0,0 +1,97 @@
+/*
+ *  Low-level modular bignum functions
+ *
+ *  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.
+ */
+
+#include "common.h"
+
+#if defined(MBEDTLS_BIGNUM_C)
+
+#include <string.h>
+
+#include "mbedtls/error.h"
+#include "mbedtls/platform_util.h"
+
+#if defined(MBEDTLS_PLATFORM_C)
+#include "mbedtls/platform.h"
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#define mbedtls_printf      printf
+#define mbedtls_calloc      calloc
+#define mbedtls_free        free
+#endif
+
+#include "bignum_core.h"
+#include "bignum_mod_raw.h"
+#include "bignum_mod.h"
+#include "constant_time_internal.h"
+
+int mbedtls_mpi_mod_raw_read( mbedtls_mpi_uint *X,
+                              const mbedtls_mpi_mod_modulus *m,
+                              const unsigned char *input,
+                              size_t input_length )
+{
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+
+    switch( m->ext_rep )
+    {
+        case MBEDTLS_MPI_MOD_EXT_REP_LE:
+            ret = mbedtls_mpi_core_read_le( X, m->limbs,
+                                            input, input_length );
+            break;
+        case MBEDTLS_MPI_MOD_EXT_REP_BE:
+            ret = mbedtls_mpi_core_read_be( X, m->limbs,
+                                            input, input_length );
+            break;
+        default:
+            return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
+    }
+
+    if( ret != 0 )
+        goto cleanup;
+
+    if( !mbedtls_mpi_core_lt_ct( X, m->p, m->limbs ) )
+    {
+        ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
+        goto cleanup;
+    }
+
+cleanup:
+
+    return( ret );
+}
+
+int mbedtls_mpi_mod_raw_write( const mbedtls_mpi_uint *A,
+                               const mbedtls_mpi_mod_modulus *m,
+                               unsigned char *output,
+                               size_t output_length )
+{
+    switch( m->ext_rep )
+    {
+        case MBEDTLS_MPI_MOD_EXT_REP_LE:
+            return( mbedtls_mpi_core_write_le( A, m->limbs,
+                                               output, output_length ) );
+        case MBEDTLS_MPI_MOD_EXT_REP_BE:
+            return( mbedtls_mpi_core_write_be( A, m->limbs,
+                                               output, output_length ) );
+        default:
+            return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
+    }
+}
+
+#endif /* MBEDTLS_BIGNUM_C */
diff --git a/library/bignum_mod_raw.h b/library/bignum_mod_raw.h
new file mode 100644
index 0000000..7b3a0c1
--- /dev/null
+++ b/library/bignum_mod_raw.h
@@ -0,0 +1,79 @@
+/**
+ *  Low-level modular bignum functions
+ *
+ *  This interface should only be used by the higher-level modular bignum
+ *  module (bignum_mod.c) and the ECP module (ecp.c, ecp_curves.c). All other
+ *  modules should use the high-level modular bignum interface (bignum_mod.h)
+ *  or the legacy bignum interface (bignum.h).
+ *
+ *  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_BIGNUM_MOD_RAW_H
+#define MBEDTLS_BIGNUM_MOD_RAW_H
+
+#include "common.h"
+
+#if defined(MBEDTLS_BIGNUM_C)
+#include "mbedtls/bignum.h"
+#endif
+
+#include "bignum_mod.h"
+
+/** Import X from unsigned binary data.
+ *
+ * The MPI needs to have enough limbs to store the full value (including any
+ * most significant zero bytes in the input).
+ *
+ * \param[out] X        The address of the MPI. The size is determined by \p m.
+ *                      (In particular, it must have at least as many limbs as
+ *                      the modulus \p m.)
+ * \param[in] m         The address of the modulus related to \p X.
+ * \param[in] input     The input buffer to import from.
+ * \param input_length  The length in bytes of \p input.
+ *
+ * \return       \c 0 if successful.
+ * \return       #MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if \p X isn't
+ *               large enough to hold the value in \p input.
+ * \return       #MBEDTLS_ERR_MPI_BAD_INPUT_DATA if the external representation
+ *               of \p m is invalid or \p X is not less than \p m.
+ */
+int mbedtls_mpi_mod_raw_read( mbedtls_mpi_uint *X,
+                              const mbedtls_mpi_mod_modulus *m,
+                              const unsigned char *input,
+                              size_t input_length );
+
+/** Export A into unsigned binary data.
+ *
+ * \param[in] A         The address of the MPI. The size is determined by \p m.
+ *                      (In particular, it must have at least as many limbs as
+ *                      the modulus \p m.)
+ * \param[in] m         The address of the modulus related to \p A.
+ * \param[out] output   The output buffer to export to.
+ * \param output_length The length in bytes of \p output.
+ *
+ * \return       \c 0 if successful.
+ * \return       #MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if \p output isn't
+ *               large enough to hold the value of \p A.
+ * \return       #MBEDTLS_ERR_MPI_BAD_INPUT_DATA if the external representation
+ *               of \p m is invalid.
+ */
+int mbedtls_mpi_mod_raw_write( const mbedtls_mpi_uint *A,
+                               const mbedtls_mpi_mod_modulus *m,
+                               unsigned char *output,
+                               size_t output_length );
+
+#endif /* MBEDTLS_BIGNUM_MOD_RAW_H */
diff --git a/library/constant_time.c b/library/constant_time.c
index 0dc723a..8980701 100644
--- a/library/constant_time.c
+++ b/library/constant_time.c
@@ -742,6 +742,50 @@
 }
 
 /*
+ * Compare unsigned values in constant time
+ */
+unsigned mbedtls_mpi_core_lt_ct( const mbedtls_mpi_uint *A,
+                                 const mbedtls_mpi_uint *B,
+                                 size_t limbs )
+{
+    unsigned ret, cond, done;
+
+    /* The value of any of these variables is either 0 or 1 for the rest of
+     * their scope. */
+    ret = cond = done = 0;
+
+    for( size_t i = limbs; i > 0; i-- )
+    {
+        /*
+         * If B[i - 1] < A[i - 1] then A < B is false and the result must
+         * remain 0.
+         *
+         * Again even if we can make a decision, we just mark the result and
+         * the fact that we are done and continue looping.
+         */
+        cond = mbedtls_ct_mpi_uint_lt( B[i - 1], A[i - 1] );
+        done |= cond;
+
+        /*
+         * If A[i - 1] < B[i - 1] then A < B is true.
+         *
+         * Again even if we can make a decision, we just mark the result and
+         * the fact that we are done and continue looping.
+         */
+        cond = mbedtls_ct_mpi_uint_lt( A[i - 1], B[i - 1] );
+        ret |= cond & ( 1 - done );
+        done |= cond;
+    }
+
+    /*
+     * If all the limbs were equal, then the numbers are equal, A < B is false
+     * and leaving the result 0 is correct.
+     */
+
+    return( ret );
+}
+
+/*
  * Compare signed values in constant time
  */
 int mbedtls_mpi_lt_mpi_ct( const mbedtls_mpi *X,
diff --git a/library/constant_time_internal.h b/library/constant_time_internal.h
index 9466bc3..fc24ae5 100644
--- a/library/constant_time_internal.h
+++ b/library/constant_time_internal.h
@@ -129,6 +129,23 @@
 unsigned mbedtls_ct_mpi_uint_lt( const mbedtls_mpi_uint x,
                                  const mbedtls_mpi_uint y );
 
+/**
+ * \brief          Check if one unsigned MPI is less than another in constant
+ *                 time.
+ *
+ * \param A        The left-hand MPI. This must point to an array of limbs
+ *                 with the same allocated length as \p B.
+ * \param B        The right-hand MPI. This must point to an array of limbs
+ *                 with the same allocated length as \p A.
+ * \param limbs    The number of limbs in \p A and \p B.
+ *
+ * \return         The result of the comparison:
+ *                 \c 1 if \p A is less than \p B.
+ *                 \c 0 if \p A is greater than or equal to \p B.
+ */
+unsigned mbedtls_mpi_core_lt_ct( const mbedtls_mpi_uint *A,
+                                 const mbedtls_mpi_uint *B,
+                                 size_t limbs);
 #endif /* MBEDTLS_BIGNUM_C */
 
 /** Choose between two integer values without branches.
diff --git a/library/ctr_drbg.c b/library/ctr_drbg.c
index 43f490e..8919c78 100644
--- a/library/ctr_drbg.c
+++ b/library/ctr_drbg.c
@@ -51,6 +51,7 @@
 void mbedtls_ctr_drbg_init( mbedtls_ctr_drbg_context *ctx )
 {
     memset( ctx, 0, sizeof( mbedtls_ctr_drbg_context ) );
+    mbedtls_aes_init( &ctx->aes_ctx );
     /* Indicate that the entropy nonce length is not set explicitly.
      * See mbedtls_ctr_drbg_set_nonce_len(). */
     ctx->reseed_counter = -1;
@@ -448,8 +449,6 @@
     mbedtls_mutex_init( &ctx->mutex );
 #endif
 
-    mbedtls_aes_init( &ctx->aes_ctx );
-
     ctx->f_entropy = f_entropy;
     ctx->p_entropy = p_entropy;
 
diff --git a/library/ssl_ticket.c b/library/ssl_ticket.c
index 28c4d3e..359686a 100644
--- a/library/ssl_ticket.c
+++ b/library/ssl_ticket.c
@@ -79,7 +79,7 @@
 #endif
 
 #if defined(MBEDTLS_HAVE_TIME)
-    key->generation_time = (uint32_t) mbedtls_time( NULL );
+    key->generation_time = mbedtls_time( NULL );
 #endif
 
     if( ( ret = ctx->f_rng( ctx->p_rng, key->name, sizeof( key->name ) ) ) != 0 )
@@ -122,15 +122,15 @@
 #else
     if( ctx->ticket_lifetime != 0 )
     {
-        uint32_t current_time = (uint32_t) mbedtls_time( NULL );
-        uint32_t key_time = ctx->keys[ctx->active].generation_time;
+        mbedtls_time_t current_time = mbedtls_time( NULL );
+        mbedtls_time_t key_time = ctx->keys[ctx->active].generation_time;
 
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
         psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
 #endif
 
         if( current_time >= key_time &&
-            current_time - key_time < ctx->ticket_lifetime )
+            (uint64_t) ( current_time - key_time ) < ctx->ticket_lifetime )
         {
             return( 0 );
         }
@@ -204,7 +204,7 @@
     ctx->ticket_lifetime = lifetime;
     memcpy( key->name, name, TICKET_KEY_NAME_BYTES );
 #if defined(MBEDTLS_HAVE_TIME)
-    key->generation_time = (uint32_t) mbedtls_time( NULL );
+    key->generation_time = mbedtls_time( NULL );
 #endif
     return 0;
 }
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 7a1f588..435d772 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -4927,7 +4927,14 @@
  */
 int mbedtls_ssl_check_curve( const mbedtls_ssl_context *ssl, mbedtls_ecp_group_id grp_id )
 {
-    uint16_t tls_id = mbedtls_ecp_curve_info_from_grp_id( grp_id )->tls_id;
+    const mbedtls_ecp_curve_info *grp_info =
+        mbedtls_ecp_curve_info_from_grp_id( grp_id );
+
+    if ( grp_info == NULL )
+        return -1;
+
+    uint16_t tls_id = grp_info->tls_id;
+
     return mbedtls_ssl_check_curve_tls_id( ssl, tls_id );
 }
 #endif /* MBEDTLS_ECP_C */
@@ -6570,14 +6577,27 @@
         /* If certificate uses an EC key, make sure the curve is OK.
          * This is a public key, so it can't be opaque, so can_do() is a good
          * enough check to ensure pk_ec() is safe to use here. */
-        if( mbedtls_pk_can_do( pk, MBEDTLS_PK_ECKEY ) &&
-            mbedtls_ssl_check_curve( ssl, mbedtls_pk_ec( *pk )->grp.id ) != 0 )
+        if( mbedtls_pk_can_do( pk, MBEDTLS_PK_ECKEY ) )
         {
-            ssl->session_negotiate->verify_result |= MBEDTLS_X509_BADCERT_BAD_KEY;
+            /* and in the unlikely case the above assumption no longer holds
+             * we are making sure that pk_ec() here does not return a NULL
+             */
+            const mbedtls_ecp_keypair *ec = mbedtls_pk_ec( *pk );
+            if( ec == NULL )
+            {
+                MBEDTLS_SSL_DEBUG_MSG( 1, ( "mbedtls_pk_ec() returned NULL" ) );
+                return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
+            }
 
-            MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate (EC key curve)" ) );
-            if( ret == 0 )
-                ret = MBEDTLS_ERR_SSL_BAD_CERTIFICATE;
+            if( mbedtls_ssl_check_curve( ssl, ec->grp.id ) != 0 )
+            {
+                ssl->session_negotiate->verify_result |=
+                    MBEDTLS_X509_BADCERT_BAD_KEY;
+
+                MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate (EC key curve)" ) );
+                if( ret == 0 )
+                    ret = MBEDTLS_ERR_SSL_BAD_CERTIFICATE;
+            }
         }
     }
 #endif /* MBEDTLS_ECP_C */
diff --git a/programs/fuzz/fuzz_privkey.c b/programs/fuzz/fuzz_privkey.c
index 56795d2..81ea1bc 100644
--- a/programs/fuzz/fuzz_privkey.c
+++ b/programs/fuzz/fuzz_privkey.c
@@ -11,9 +11,9 @@
 //4 Kb should be enough for every bug ;-)
 #define MAX_LEN 0x1000
 
-#if defined(MBEDTLS_PK_PARSE_C) && defined(MBEDTLS_CTR_DRBG_C)
+#if defined(MBEDTLS_PK_PARSE_C) && defined(MBEDTLS_CTR_DRBG_C) && defined(MBEDTLS_ENTROPY_C)
 const char *pers = "fuzz_privkey";
-#endif // MBEDTLS_PK_PARSE_C && MBEDTLS_CTR_DRBG_C
+#endif // MBEDTLS_PK_PARSE_C && MBEDTLS_CTR_DRBG_C && MBEDTLS_ENTROPY_C
 
 int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
 #if defined(MBEDTLS_PK_PARSE_C) && defined(MBEDTLS_CTR_DRBG_C) && defined(MBEDTLS_ENTROPY_C)
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index 2e9713b..7139fde 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -1878,7 +1878,7 @@
     # but is already disabled in the default config
 
     loc_accel_flags="$loc_accel_flags $( echo "$loc_accel_list" | sed 's/[^ ]* */-DMBEDTLS_PSA_ACCEL_&/g' )"
-    make CFLAGS="$ASAN_CFLAGS -Werror -I../tests/include -I../tests -DPSA_CRYPTO_DRIVER_TEST -DMBEDTLS_TEST_LIBTESTDRIVER1 $loc_accel_flags" LDFLAGS="-ltestdriver1 $ASAN_CFLAGS" tests
+    make CFLAGS="$ASAN_CFLAGS -Werror -I../tests/include -I../tests -I../../tests -DPSA_CRYPTO_DRIVER_TEST -DMBEDTLS_TEST_LIBTESTDRIVER1 $loc_accel_flags" LDFLAGS="-ltestdriver1 $ASAN_CFLAGS" all
 
     # There's a risk of something getting re-enabled via config_psa.h;
     # make sure it did not happen.
diff --git a/tests/scripts/check_names.py b/tests/scripts/check_names.py
index 96117a2..e204487 100755
--- a/tests/scripts/check_names.py
+++ b/tests/scripts/check_names.py
@@ -58,8 +58,9 @@
 
 # Naming patterns to check against. These are defined outside the NameCheck
 # class for ease of modification.
-MACRO_PATTERN = r"^(MBEDTLS|PSA)_[0-9A-Z_]*[0-9A-Z]$"
-CONSTANTS_PATTERN = MACRO_PATTERN
+PUBLIC_MACRO_PATTERN = r"^(MBEDTLS|PSA)_[0-9A-Z_]*[0-9A-Z]$"
+INTERNAL_MACRO_PATTERN = r"^[0-9A-Za-z_]*[0-9A-Z]$"
+CONSTANTS_PATTERN = PUBLIC_MACRO_PATTERN
 IDENTIFIER_PATTERN = r"^(mbedtls|psa)_[0-9a-z_]*[0-9a-z]$"
 
 class Match(): # pylint: disable=too-few-public-methods
@@ -249,14 +250,17 @@
             .format(str(self.excluded_files))
         )
 
-        all_macros = self.parse_macros([
+        all_macros = {"public": [], "internal": []}
+        all_macros["public"] = self.parse_macros([
             "include/mbedtls/*.h",
             "include/psa/*.h",
-            "library/*.h",
-            "tests/include/test/drivers/*.h",
             "3rdparty/everest/include/everest/everest.h",
             "3rdparty/everest/include/everest/x25519.h"
         ])
+        all_macros["internal"] = self.parse_macros([
+            "library/*.h",
+            "tests/include/test/drivers/*.h",
+        ])
         enum_consts = self.parse_enum_consts([
             "include/mbedtls/*.h",
             "library/*.h",
@@ -284,20 +288,25 @@
 
         # Remove identifier macros like mbedtls_printf or mbedtls_calloc
         identifiers_justname = [x.name for x in identifiers]
-        actual_macros = []
-        for macro in all_macros:
-            if macro.name not in identifiers_justname:
-                actual_macros.append(macro)
+        actual_macros = {"public": [], "internal": []}
+        for scope in actual_macros:
+            for macro in all_macros[scope]:
+                if macro.name not in identifiers_justname:
+                    actual_macros[scope].append(macro)
 
         self.log.debug("Found:")
         # Aligns the counts on the assumption that none exceeds 4 digits
-        self.log.debug("  {:4} Total Macros".format(len(all_macros)))
-        self.log.debug("  {:4} Non-identifier Macros".format(len(actual_macros)))
+        for scope in actual_macros:
+            self.log.debug("  {:4} Total {} Macros"
+                           .format(len(all_macros[scope]), scope))
+            self.log.debug("  {:4} {} Non-identifier Macros"
+                           .format(len(actual_macros[scope]), scope))
         self.log.debug("  {:4} Enum Constants".format(len(enum_consts)))
         self.log.debug("  {:4} Identifiers".format(len(identifiers)))
         self.log.debug("  {:4} Exported Symbols".format(len(symbols)))
         return {
-            "macros": actual_macros,
+            "public_macros": actual_macros["public"],
+            "internal_macros": actual_macros["internal"],
             "enum_consts": enum_consts,
             "identifiers": identifiers,
             "symbols": symbols,
@@ -741,7 +750,8 @@
         problems += self.check_symbols_declared_in_header()
 
         pattern_checks = [
-            ("macros", MACRO_PATTERN),
+            ("public_macros", PUBLIC_MACRO_PATTERN),
+            ("internal_macros", INTERNAL_MACRO_PATTERN),
             ("enum_consts", CONSTANTS_PATTERN),
             ("identifiers", IDENTIFIER_PATTERN)
         ]
@@ -825,7 +835,10 @@
         all_caps_names = {
             match.name
             for match
-            in self.parse_result["macros"] + self.parse_result["enum_consts"]}
+            in self.parse_result["public_macros"] +
+            self.parse_result["internal_macros"] +
+            self.parse_result["enum_consts"]
+            }
         typo_exclusion = re.compile(r"XXX|__|_$|^MBEDTLS_.*CONFIG_FILE$|"
                                     r"MBEDTLS_TEST_LIBTESTDRIVER*")
 
diff --git a/tests/suites/test_suite_mpi.data b/tests/suites/test_suite_mpi.data
index f29dcab..7573f95 100644
--- a/tests/suites/test_suite_mpi.data
+++ b/tests/suites/test_suite_mpi.data
@@ -82,6 +82,308 @@
 Test mpi_write_string #10 (Negative hex with odd number of digits)
 mpi_read_write_string:16:"-1":16:"":3:0:MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL
 
+Test mbedtls_mpi_core_io functions with null pointers
+mbedtls_mpi_core_io_null
+
+Test mbedtls_mpi_core_io_be #1 (Buffer and limbs just fit, input limb-aligned)
+mbedtls_mpi_core_io_be:"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b4424":96:24:0:0
+
+Test mbedtls_mpi_core_io_be #2  (Buffer and limbs just fit, input unaligned)
+mbedtls_mpi_core_io_be:"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b":94:24:0:0
+
+Test mbedtls_mpi_core_io_be #3 (Buffer just fits, extra limbs, input limb-aligned)
+mbedtls_mpi_core_io_be:"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b4424":96:28:0:0
+
+Test mbedtls_mpi_core_io_be #4 (Buffer just fits, extra limbs, input unaligned)
+mbedtls_mpi_core_io_be:"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b":94:28:0:0
+
+Test mbedtls_mpi_core_io_be #5 (Extra limbs, buffer aligned to extra limbs, input limb-aligned)
+mbedtls_mpi_core_io_be:"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b4424":112:28:0:0
+
+Test mbedtls_mpi_core_io_be #6 (Extra limbs, buffer aligned to extra limbs, input unaligned)
+mbedtls_mpi_core_io_be:"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b":112:28:0:0
+
+Test mbedtls_mpi_core_io_be #7 (Buffer and limbs just fit, input limb-aligned with leading zeroes)
+mbedtls_mpi_core_io_be:"00000000000000001fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b4424":88:24:0:0
+
+Test mbedtls_mpi_core_io_be #8 (Buffer and limbs just fit, input unaligned with leading zeroes)
+mbedtls_mpi_core_io_be:"00000000000000001fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b":86:24:0:0
+
+Test mbedtls_mpi_core_io_be #9 (Buffer just fits, extra limbs, input limb-aligned with leading zeroes)
+mbedtls_mpi_core_io_be:"00000000000000001fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b4424":88:28:0:0
+
+Test mbedtls_mpi_core_io_be #10 (Buffer just fits, extra limbs, input unaligned with leading zeroes)
+mbedtls_mpi_core_io_be:"00000000000000001fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b":86:28:0:0
+
+Test mbedtls_mpi_core_io_be #11 (Zero)
+mbedtls_mpi_core_io_be:"00":1:1:0:0
+
+Test mbedtls_mpi_core_io_be #12 (Zero, empty output)
+mbedtls_mpi_core_io_be:"00":0:1:0:0
+
+Test mbedtls_mpi_core_io_be #13 (Zero, empty input)
+mbedtls_mpi_core_io_be:"":1:1:0:0
+
+Test mbedtls_mpi_core_io_be #14 (One)
+mbedtls_mpi_core_io_be:"01":1:1:0:0
+
+Test mbedtls_mpi_core_io_be #15 (One limb, 32 bit)
+depends_on:MBEDTLS_HAVE_INT32
+mbedtls_mpi_core_io_be:"ff000000":4:1:0:0
+
+Test mbedtls_mpi_core_io_be #16 (One limb, 64 bit)
+depends_on:MBEDTLS_HAVE_INT64
+mbedtls_mpi_core_io_be:"ff00000000000000":8:2:0:0
+
+Test mbedtls_mpi_core_io_be #17 (not enough limbs, input limb-aligned)
+mbedtls_mpi_core_io_be:"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b4424":96:22:MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL:0
+
+Test mbedtls_mpi_core_io_be #18 (not enough limbs, input unaligned)
+mbedtls_mpi_core_io_be:"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b":94:22:MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL:0
+
+Test mbedtls_mpi_core_io_be #19 (buffer too small, input limb-aligned)
+mbedtls_mpi_core_io_be:"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b4424":95:24:0:MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL
+
+Test mbedtls_mpi_core_io_be #20 (buffer too small, input unaligned)
+mbedtls_mpi_core_io_be:"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b":93:24:0:MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL
+
+Test mbedtls_mpi_core_io_be #21 (Buffer and limbs fit, input unaligned, odd number of limbs)
+mbedtls_mpi_core_io_be:"00de4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b4424":82:21:0:0
+
+Test mbedtls_mpi_core_io_le #1 (Buffer and limbs just fit, input limb-aligned)
+mbedtls_mpi_core_io_le:"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b4424":96:24:0:0
+
+Test mbedtls_mpi_core_io_le #2  (Buffer and limbs just fit, input unaligned)
+mbedtls_mpi_core_io_le:"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b":94:24:0:0
+
+Test mbedtls_mpi_core_io_le #3 (Buffer just fits, extra limbs, input limb-aligned)
+mbedtls_mpi_core_io_le:"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b4424":96:28:0:0
+
+Test mbedtls_mpi_core_io_le #4 (Buffer just fits, extra limbs, input unaligned)
+mbedtls_mpi_core_io_le:"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b":94:28:0:0
+
+Test mbedtls_mpi_core_io_le #5 (Extra limbs, buffer aligned to extra limbs, input limb-aligned)
+mbedtls_mpi_core_io_le:"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b4424":112:28:0:0
+
+Test mbedtls_mpi_core_io_le #6 (Extra limbs, buffer aligned to extra limbs, input unaligned)
+mbedtls_mpi_core_io_le:"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b":112:28:0:0
+
+Test mbedtls_mpi_core_io_le #7 (Buffer and limbs just fit, input limb-aligned with leading zeroes)
+mbedtls_mpi_core_io_le:"1fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b44240000000000000000":88:24:0:0
+
+Test mbedtls_mpi_core_io_le #8 (Buffer and limbs just fit, input unaligned with leading zeroes)
+mbedtls_mpi_core_io_le:"1fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b0000000000000000":86:24:0:0
+
+Test mbedtls_mpi_core_io_le #9 (Buffer just fits, extra limbs, input limb-aligned with leading zeroes)
+mbedtls_mpi_core_io_le:"1fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b44240000000000000000":88:28:0:0
+
+Test mbedtls_mpi_core_io_le #10 (Buffer just fits, extra limbs, input unaligned with leading zeroes)
+mbedtls_mpi_core_io_le:"1fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b0000000000000000":86:28:0:0
+
+Test mbedtls_mpi_core_io_le #11 (Zero)
+mbedtls_mpi_core_io_le:"00":1:1:0:0
+
+Test mbedtls_mpi_core_io_le #12 (Zero, empty output)
+mbedtls_mpi_core_io_le:"00":0:1:0:0
+
+Test mbedtls_mpi_core_io_le #13 (Zero, empty input)
+mbedtls_mpi_core_io_le:"":1:1:0:0
+
+Test mbedtls_mpi_core_io_le #14 (One)
+mbedtls_mpi_core_io_le:"01":1:1:0:0
+
+Test mbedtls_mpi_core_io_le #15 (One limb)
+depends_on:MBEDTLS_HAVE_INT32
+mbedtls_mpi_core_io_le:"000000ff":4:1:0:0
+
+Test mbedtls_mpi_core_io_le #16 (One limb)
+depends_on:MBEDTLS_HAVE_INT64
+mbedtls_mpi_core_io_le:"00000000000000ff":8:2:0:0
+
+Test mbedtls_mpi_core_io_le #17 (not enough limbs, input limb-aligned)
+mbedtls_mpi_core_io_le:"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b4424":96:22:MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL:0
+
+Test mbedtls_mpi_core_io_le #18 (not enough limbs, input unaligned)
+mbedtls_mpi_core_io_le:"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b":94:22:MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL:0
+
+Test mbedtls_mpi_core_io_le #19 (buffer too small, input limb-aligned)
+mbedtls_mpi_core_io_le:"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b4424":95:24:0:MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL
+
+Test mbedtls_mpi_core_io_le #20 (buffer too small, input unaligned)
+mbedtls_mpi_core_io_le:"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b":93:24:0:MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL
+
+Test mbedtls_mpi_core_io_le #21 (Buffer and limbs fit, input unaligned, odd number of limbs)
+mbedtls_mpi_core_io_le:"de4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b442400":82:21:0:0
+
+Test mbedtls_mpi_mod_raw_io #1 BE (Buffer and limbs just fit, input limb-aligned)
+mbedtls_mpi_mod_raw_io:"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b4424":96:24:MBEDTLS_MPI_MOD_EXT_REP_BE:0:0
+
+Test mbedtls_mpi_mod_raw_io #1 LE (Buffer and limbs just fit, input limb-aligned)
+mbedtls_mpi_mod_raw_io:"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b4424":96:24:MBEDTLS_MPI_MOD_EXT_REP_LE:0:0
+
+Test mbedtls_mpi_mod_raw_io #2 BE (Buffer and limbs just fit, input unaligned)
+mbedtls_mpi_mod_raw_io:"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b":94:24:MBEDTLS_MPI_MOD_EXT_REP_BE:0:0
+
+Test mbedtls_mpi_mod_raw_io #2 LE  (Buffer and limbs just fit, input unaligned)
+mbedtls_mpi_mod_raw_io:"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b":94:24:MBEDTLS_MPI_MOD_EXT_REP_LE:0:0
+
+Test mbedtls_mpi_mod_raw_io #3 BE (Buffer just fits, extra limbs, input limb-aligned)
+mbedtls_mpi_mod_raw_io:"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b4424":96:28:MBEDTLS_MPI_MOD_EXT_REP_BE:0:0
+
+Test mbedtls_mpi_mod_raw_io #3 LE (Buffer just fits, extra limbs, input limb-aligned)
+mbedtls_mpi_mod_raw_io:"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b4424":96:28:MBEDTLS_MPI_MOD_EXT_REP_LE:0:0
+
+Test mbedtls_mpi_mod_raw_io #4 BE (Buffer just fits, extra limbs, input unaligned)
+mbedtls_mpi_mod_raw_io:"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b":94:28:MBEDTLS_MPI_MOD_EXT_REP_BE:0:0
+
+Test mbedtls_mpi_mod_raw_io #4 LE (Buffer just fits, extra limbs, input unaligned)
+mbedtls_mpi_mod_raw_io:"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b":94:28:MBEDTLS_MPI_MOD_EXT_REP_LE:0:0
+
+Test mbedtls_mpi_mod_raw_io #5 BE (Extra limbs, buffer aligned to extra limbs, input limb-aligned)
+mbedtls_mpi_mod_raw_io:"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b4424":112:28:MBEDTLS_MPI_MOD_EXT_REP_BE:0:0
+
+Test mbedtls_mpi_mod_raw_io #5 LE (Extra limbs, buffer aligned to extra limbs, input limb-aligned)
+mbedtls_mpi_mod_raw_io:"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b4424":112:28:MBEDTLS_MPI_MOD_EXT_REP_LE:0:0
+
+Test mbedtls_mpi_mod_raw_io #6 BE (Extra limbs, buffer aligned to extra limbs, input unaligned)
+mbedtls_mpi_mod_raw_io:"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b":112:28:MBEDTLS_MPI_MOD_EXT_REP_BE:0:0
+
+Test mbedtls_mpi_mod_raw_io #6 LE (Extra limbs, buffer aligned to extra limbs, input unaligned)
+mbedtls_mpi_mod_raw_io:"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b":112:28:MBEDTLS_MPI_MOD_EXT_REP_LE:0:0
+
+Test mbedtls_mpi_mod_raw_io #7 BE (Buffer and limbs just fit, input limb-aligned with leading zeroes)
+mbedtls_mpi_mod_raw_io:"00000000000000001fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b4424":88:24:MBEDTLS_MPI_MOD_EXT_REP_BE:0:0
+
+Test mbedtls_mpi_mod_raw_io #7 LE (Buffer and limbs just fit, input limb-aligned with leading zeroes)
+mbedtls_mpi_mod_raw_io:"1fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b44240000000000000000":88:24:MBEDTLS_MPI_MOD_EXT_REP_LE:0:0
+
+Test mbedtls_mpi_mod_raw_io #8 BE (Buffer and limbs just fit, input unaligned with leading zeroes)
+mbedtls_mpi_mod_raw_io:"00000000000000001fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b":86:24:MBEDTLS_MPI_MOD_EXT_REP_BE:0:0
+
+Test mbedtls_mpi_mod_raw_io #8 LE (Buffer and limbs just fit, input unaligned with leading zeroes)
+mbedtls_mpi_mod_raw_io:"1fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b0000000000000000":86:24:MBEDTLS_MPI_MOD_EXT_REP_LE:0:0
+
+Test mbedtls_mpi_mod_raw_io #9 BE (Buffer just fits, extra limbs, input limb-aligned with leading zeroes)
+mbedtls_mpi_mod_raw_io:"00000000000000001fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b4424":88:28:MBEDTLS_MPI_MOD_EXT_REP_BE:0:0
+
+Test mbedtls_mpi_mod_raw_io #9 LE (Buffer just fits, extra limbs, input limb-aligned with leading zeroes)
+mbedtls_mpi_mod_raw_io:"1fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b44240000000000000000":88:28:MBEDTLS_MPI_MOD_EXT_REP_LE:0:0
+
+Test mbedtls_mpi_mod_raw_io #10 BE (Buffer just fits, extra limbs, input unaligned with leading zeroes)
+mbedtls_mpi_mod_raw_io:"00000000000000001fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b":86:28:MBEDTLS_MPI_MOD_EXT_REP_BE:0:0
+
+Test mbedtls_mpi_mod_raw_io #10 LE (Buffer just fits, extra limbs, input unaligned with leading zeroes)
+mbedtls_mpi_mod_raw_io:"1fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b0000000000000000":86:28:MBEDTLS_MPI_MOD_EXT_REP_LE:0:0
+
+Test mbedtls_mpi_mod_raw_io #11 BE (Zero)
+mbedtls_mpi_mod_raw_io:"00":1:1:MBEDTLS_MPI_MOD_EXT_REP_BE:0:0
+
+Test mbedtls_mpi_mod_raw_io #11 LE (Zero)
+mbedtls_mpi_mod_raw_io:"00":1:1:MBEDTLS_MPI_MOD_EXT_REP_LE:0:0
+
+Test mbedtls_mpi_mod_raw_io #12 BE (Zero, empty output)
+mbedtls_mpi_mod_raw_io:"00":0:1:MBEDTLS_MPI_MOD_EXT_REP_BE:0:0
+
+Test mbedtls_mpi_mod_raw_io #12 LE (Zero, empty output)
+mbedtls_mpi_mod_raw_io:"00":0:1:MBEDTLS_MPI_MOD_EXT_REP_LE:0:0
+
+Test mbedtls_mpi_mod_raw_io #13 BE (Zero, empty input)
+mbedtls_mpi_mod_raw_io:"":1:1:MBEDTLS_MPI_MOD_EXT_REP_BE:0:0
+
+Test mbedtls_mpi_mod_raw_io #13 LE (Zero, empty input)
+mbedtls_mpi_mod_raw_io:"":1:1:MBEDTLS_MPI_MOD_EXT_REP_LE:0:0
+
+Test mbedtls_mpi_mod_raw_io #14 BE (One)
+mbedtls_mpi_mod_raw_io:"01":1:1:MBEDTLS_MPI_MOD_EXT_REP_BE:0:0
+
+Test mbedtls_mpi_mod_raw_io #14 LE (One)
+mbedtls_mpi_mod_raw_io:"01":1:1:MBEDTLS_MPI_MOD_EXT_REP_LE:0:0
+
+Test mbedtls_mpi_mod_raw_io #14 BE (One limb)
+mbedtls_mpi_mod_raw_io:"ff00000000000000":8:2:MBEDTLS_MPI_MOD_EXT_REP_BE:0:0
+
+Test mbedtls_mpi_mod_raw_io #14 LE (One limb)
+mbedtls_mpi_mod_raw_io:"00000000000000ff":8:2:MBEDTLS_MPI_MOD_EXT_REP_LE:0:0
+
+Test mbedtls_mpi_mod_raw_io #15 BE (One limb)
+depends_on:MBEDTLS_HAVE_INT32
+mbedtls_mpi_mod_raw_io:"000000ff":4:1:MBEDTLS_MPI_MOD_EXT_REP_BE:0:0
+
+Test mbedtls_mpi_mod_raw_io #15 LE (One limb)
+depends_on:MBEDTLS_HAVE_INT32
+mbedtls_mpi_mod_raw_io:"000000ff":4:1:MBEDTLS_MPI_MOD_EXT_REP_LE:0:0
+
+Test mbedtls_mpi_mod_raw_io #16 BE (One limb)
+depends_on:MBEDTLS_HAVE_INT64
+mbedtls_mpi_mod_raw_io:"00000000000000ff":8:2:MBEDTLS_MPI_MOD_EXT_REP_BE:0:0
+
+Test mbedtls_mpi_mod_raw_io #16 LE (One limb)
+depends_on:MBEDTLS_HAVE_INT64
+mbedtls_mpi_mod_raw_io:"00000000000000ff":8:2:MBEDTLS_MPI_MOD_EXT_REP_LE:0:0
+
+Test mbedtls_mpi_mod_raw_io #17 BE (not enough limbs, input limb-aligned)
+mbedtls_mpi_mod_raw_io:"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b4424":96:22:MBEDTLS_MPI_MOD_EXT_REP_BE:MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL:0
+
+Test mbedtls_mpi_mod_raw_io #17 LE (not enough limbs, input limb-aligned)
+mbedtls_mpi_mod_raw_io:"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b4424":96:22:MBEDTLS_MPI_MOD_EXT_REP_LE:MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL:0
+
+Test mbedtls_mpi_mod_raw_io #18 BE (not enough limbs, input unaligned)
+mbedtls_mpi_mod_raw_io:"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b":94:22:MBEDTLS_MPI_MOD_EXT_REP_BE:MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL:0
+
+Test mbedtls_mpi_mod_raw_io #18 LE (not enough limbs, input unaligned)
+mbedtls_mpi_mod_raw_io:"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b":94:22:MBEDTLS_MPI_MOD_EXT_REP_LE:MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL:0
+
+Test mbedtls_mpi_mod_raw_io #19 BE (buffer too small, input limb-aligned)
+mbedtls_mpi_mod_raw_io:"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b4424":95:24:MBEDTLS_MPI_MOD_EXT_REP_BE:0:MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL
+
+Test mbedtls_mpi_mod_raw_io #19 LE (buffer too small, input limb-aligned)
+mbedtls_mpi_mod_raw_io:"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b4424":95:24:MBEDTLS_MPI_MOD_EXT_REP_LE:0:MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL
+
+Test mbedtls_mpi_mod_raw_io #20 BE (buffer too small, input unaligned)
+mbedtls_mpi_mod_raw_io:"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b":93:24:MBEDTLS_MPI_MOD_EXT_REP_BE:0:MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL
+
+Test mbedtls_mpi_mod_raw_io #20 LE (buffer too small, input unaligned)
+mbedtls_mpi_mod_raw_io:"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b":93:24:MBEDTLS_MPI_MOD_EXT_REP_LE:0:MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL
+
+Test mbedtls_mpi_mod_raw_io #21 BE (modulus is equal to input)
+mbedtls_mpi_mod_raw_io:"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF":1024:256:MBEDTLS_MPI_MOD_EXT_REP_BE:MBEDTLS_ERR_MPI_BAD_INPUT_DATA:0
+
+Test mbedtls_mpi_mod_raw_io #21 LE (modulus is equal to input)
+mbedtls_mpi_mod_raw_io:"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF":1024:256:MBEDTLS_MPI_MOD_EXT_REP_LE:MBEDTLS_ERR_MPI_BAD_INPUT_DATA:0
+
+Test mbedtls_mpi_mod_raw_io #22 (reading with invalid endianness)
+mbedtls_mpi_mod_raw_io:"":1:1:MBEDTLS_MPI_MOD_EXT_REP_INVALID:MBEDTLS_ERR_MPI_BAD_INPUT_DATA:0
+
+Test mbedtls_mpi_mod_raw_io #22 (writing with invalid endianness)
+mbedtls_mpi_mod_raw_io:"":1:1:MBEDTLS_MPI_MOD_EXT_REP_INVALID:0:MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+Test mbedtls_mpi_mod_setup #1 (Both representations invalid)
+mbedtls_mpi_mod_setup:MBEDTLS_MPI_MOD_EXT_REP_INVALID:MBEDTLS_MPI_MOD_REP_INVALID:MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+Test mbedtls_mpi_mod_setup #2 (Internal representation invalid)
+mbedtls_mpi_mod_setup:MBEDTLS_MPI_MOD_EXT_REP_LE:MBEDTLS_MPI_MOD_REP_INVALID:MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+Test mbedtls_mpi_mod_setup #3 (Internal representation invalid)
+mbedtls_mpi_mod_setup:MBEDTLS_MPI_MOD_EXT_REP_BE:MBEDTLS_MPI_MOD_REP_INVALID:MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+Test mbedtls_mpi_mod_setup #4 (External representation invalid)
+mbedtls_mpi_mod_setup:MBEDTLS_MPI_MOD_EXT_REP_INVALID:MBEDTLS_MPI_MOD_REP_MONTGOMERY:MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+Test mbedtls_mpi_mod_setup #5 (External representation invalid)
+mbedtls_mpi_mod_setup:MBEDTLS_MPI_MOD_EXT_REP_INVALID:MBEDTLS_MPI_MOD_REP_OPT_RED:MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+Test mbedtls_mpi_mod_setup #6 (Both representations valid)
+mbedtls_mpi_mod_setup:MBEDTLS_MPI_MOD_EXT_REP_BE:MBEDTLS_MPI_MOD_REP_OPT_RED:0
+
+Test mbedtls_mpi_mod_setup #7 (Both representations valid)
+mbedtls_mpi_mod_setup:MBEDTLS_MPI_MOD_EXT_REP_BE:MBEDTLS_MPI_MOD_REP_MONTGOMERY:0
+
+Test mbedtls_mpi_mod_setup #8 (Both representations valid)
+mbedtls_mpi_mod_setup:MBEDTLS_MPI_MOD_EXT_REP_LE:MBEDTLS_MPI_MOD_REP_OPT_RED:0
+
+Test mbedtls_mpi_mod_setup #9 (Both representations valid)
+mbedtls_mpi_mod_setup:MBEDTLS_MPI_MOD_EXT_REP_LE:MBEDTLS_MPI_MOD_REP_MONTGOMERY:0
+
 Base test mbedtls_mpi_read_binary #1
 mbedtls_mpi_read_binary:"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b4424":"0941379D00FED1491FE15DF284DFDE4A142F68AA8D412023195CEE66883E6290FFE703F4EA5963BF212713CEE46B107C09182B5EDCD955ADAC418BF4918E2889AF48E1099D513830CEC85C26AC1E158B52620E33BA8692F893EFBB2F958B4424"
 
@@ -292,6 +594,93 @@
 Test mbedtls_mpi_cmp_mpi: large negative < 0 (1 limb)
 mbedtls_mpi_cmp_mpi:"-1230000000000000000":"0":-1
 
+mbedtls_mpi_core_lt_ct: x=y (1 limb)
+mpi_core_lt_ct:"02B5":"02B5":0
+
+mbedtls_mpi_core_lt_ct: x>y (1 limb)
+mpi_core_lt_ct:"02B5":"02B4":0
+
+mbedtls_mpi_core_lt_ct: x<y (1 limb)
+mpi_core_lt_ct:"02B5":"02B6":1
+
+mbedtls_mpi_core_lt_ct: x=y (0 limbs)
+mpi_core_lt_ct:"":"":0
+
+mbedtls_mpi_core_lt_ct: x>y (63 bit x, y first byte greater)
+mpi_core_lt_ct:"7FFFFFFFFFFFFFFF":"FF":0
+
+mbedtls_mpi_core_lt_ct: x<y (63 bit y, x first byte greater)
+mpi_core_lt_ct:"FF":"7FFFFFFFFFFFFFFF":1
+
+mbedtls_mpi_core_lt_ct: x>y (64 bit x, y=x-1)
+mpi_core_lt_ct:"8000000000000000":"7FFFFFFFFFFFFFFF":0
+
+mbedtls_mpi_core_lt_ct: x<y (64 bit y, x=y-1)
+mpi_core_lt_ct:"7FFFFFFFFFFFFFFF":"8000000000000000":1
+
+mbedtls_mpi_core_lt_ct: x>y (64 bit x, y=1)
+mpi_core_lt_ct:"8000000000000000":"01":0
+
+mbedtls_mpi_core_lt_ct: x<y (64 bit y, x=1)
+mpi_core_lt_ct:"01":"8000000000000000":1
+
+mbedtls_mpi_core_lt_ct: x>y (64 bit x, y=0)
+mpi_core_lt_ct:"8000000000000000":"00":0
+
+mbedtls_mpi_core_lt_ct: x<y (64 bit y, x=0)
+mpi_core_lt_ct:"00":"8000000000000000":1
+
+mbedtls_mpi_core_lt_ct: x>y (64 bit x, first bytes equal)
+mpi_core_lt_ct:"FFFFFFFFFFFFFFFF":"FF":0
+
+mbedtls_mpi_core_lt_ct: x<y (64 bit y, first bytes equal)
+mpi_core_lt_ct:"FF":"FFFFFFFFFFFFFFFF":1
+
+mbedtls_mpi_core_lt_ct: x>y (31 bit x, y first byte greater)
+mpi_core_lt_ct:"7FFFFFFF":"FF":0
+
+mbedtls_mpi_core_lt_ct: x<y (31 bit y, x first byte greater)
+mpi_core_lt_ct:"FF":"7FFFFFFF":1
+
+mbedtls_mpi_core_lt_ct: x>y (32 bit x, y=x-1)
+mpi_core_lt_ct:"80000000":"7FFFFFFF":0
+
+mbedtls_mpi_core_lt_ct: x<y (32 bit y, x=y-1)
+mpi_core_lt_ct:"7FFFFFFF":"80000000":1
+
+mbedtls_mpi_core_lt_ct: x>y (32 bit x, y=1)
+mpi_core_lt_ct:"80000000":"01":0
+
+mbedtls_mpi_core_lt_ct: x<y (32 bit y, x=1)
+mpi_core_lt_ct:"01":"80000000":1
+
+mbedtls_mpi_core_lt_ct: x>y (32 bit x, y=0)
+mpi_core_lt_ct:"80000000":"00":0
+
+mbedtls_mpi_core_lt_ct: x<y (32 bit y, x=0)
+mpi_core_lt_ct:"00":"80000000":1
+
+mbedtls_mpi_core_lt_ct: x>y (32 bit x, first bytes equal)
+mpi_core_lt_ct:"FFFFFFFF":"FF":0
+
+mbedtls_mpi_core_lt_ct: x<y (32 bit y, first bytes equal)
+mpi_core_lt_ct:"FF":"FFFFFFFF":1
+
+mbedtls_mpi_core_lt_ct: x<y, zero vs non-zero MS limb
+mpi_core_lt_ct:"00FFFFFFFFFFFFFFFF":"01FFFFFFFFFFFFFFFF":1
+
+mbedtls_mpi_core_lt_ct: x>y, equal MS limbs
+mpi_core_lt_ct:"EEFFFFFFFFFFFFFFFF":"EEFFFFFFFFFFFFFFF1":0
+
+mbedtls_mpi_core_lt_ct: x=y (multi-limb)
+mpi_core_lt_ct:"EEFFFFFFFFFFFFFFFF":"EEFFFFFFFFFFFFFFFF":0
+
+mbedtls_mpi_core_lt_ct: x<y (alternating limbs)
+mpi_core_lt_ct:"11FFFFFFFFFFFFFFFF":"FF1111111111111111":1
+
+mbedtls_mpi_core_lt_ct: x>y (alternating limbs)
+mpi_core_lt_ct:"FF1111111111111111":"11FFFFFFFFFFFFFFFF":0
+
 Base test mbedtls_mpi_lt_mpi_ct #1
 mbedtls_mpi_lt_mpi_ct:1:"2B5":1:"2B5":0:0
 
diff --git a/tests/suites/test_suite_mpi.function b/tests/suites/test_suite_mpi.function
index 2694a44..dae3262 100644
--- a/tests/suites/test_suite_mpi.function
+++ b/tests/suites/test_suite_mpi.function
@@ -1,6 +1,11 @@
 /* BEGIN_HEADER */
 #include "mbedtls/bignum.h"
 #include "mbedtls/entropy.h"
+#include "bignum_core.h"
+#include "bignum_mod.h"
+#include "bignum_mod_raw.h"
+#include "constant_time_internal.h"
+#include "test/constant_flow.h"
 
 #if MBEDTLS_MPI_MAX_BITS > 792
 #define MPI_MAX_BITS_LARGER_THAN_792
@@ -197,6 +202,273 @@
 /* END_CASE */
 
 /* BEGIN_CASE */
+void mbedtls_mpi_core_io_null()
+{
+    mbedtls_mpi_uint X = 0;
+    int ret;
+
+    ret = mbedtls_mpi_core_read_be( &X, 1, NULL, 0 );
+    TEST_EQUAL( ret, 0 );
+    ret = mbedtls_mpi_core_write_be( &X, 1, NULL, 0 );
+    TEST_EQUAL( ret, 0 );
+
+    ret = mbedtls_mpi_core_read_be( NULL, 0, NULL, 0 );
+    TEST_EQUAL( ret, 0 );
+    ret = mbedtls_mpi_core_write_be( NULL, 0, NULL, 0 );
+    TEST_EQUAL( ret, 0 );
+
+    ret = mbedtls_mpi_core_read_le( &X, 1, NULL, 0 );
+    TEST_EQUAL( ret, 0 );
+    ret = mbedtls_mpi_core_write_le( &X, 1, NULL, 0 );
+    TEST_EQUAL( ret, 0 );
+
+    ret = mbedtls_mpi_core_read_le( NULL, 0, NULL, 0 );
+    TEST_EQUAL( ret, 0 );
+    ret = mbedtls_mpi_core_write_le( NULL, 0, NULL, 0 );
+    TEST_EQUAL( ret, 0 );
+
+exit:
+    ;
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void mbedtls_mpi_core_io_be( data_t *input, int nb_int, int nx_32_int, int iret,
+                             int oret )
+{
+    if( iret != 0 )
+        TEST_ASSERT( oret == 0 );
+
+    TEST_ASSERT( 0 <= nb_int );
+    size_t nb = nb_int;
+
+    unsigned char buf[1024];
+    TEST_ASSERT( nb <= sizeof( buf ) );
+
+    /* nx_32_int is the number of 32 bit limbs, if we have 64 bit limbs we need
+     * to halve the number of limbs to have the same size. */
+    size_t nx;
+    TEST_ASSERT( 0 <= nx_32_int );
+    if( sizeof( mbedtls_mpi_uint ) == 8 )
+        nx = nx_32_int / 2 + nx_32_int % 2;
+    else
+        nx = nx_32_int;
+
+    mbedtls_mpi_uint X[sizeof( buf ) / sizeof( mbedtls_mpi_uint )];
+    TEST_ASSERT( nx <= sizeof( X ) / sizeof( X[0] ) );
+
+    int ret = mbedtls_mpi_core_read_be( X, nx, input->x, input->len );
+    TEST_EQUAL( ret, iret );
+
+    if( iret == 0 )
+    {
+        ret =  mbedtls_mpi_core_write_be( X, nx, buf, nb );
+        TEST_EQUAL( ret, oret );
+    }
+
+    if( ( iret == 0 ) && ( oret == 0 ) )
+    {
+        if( nb > input->len )
+        {
+            size_t leading_zeroes = nb - input->len;
+            TEST_ASSERT( memcmp( buf + nb - input->len, input->x, input->len ) == 0 );
+            for( size_t i = 0; i < leading_zeroes; i++ )
+                TEST_EQUAL( buf[i], 0 );
+        }
+        else
+        {
+            size_t leading_zeroes = input->len - nb;
+            TEST_ASSERT( memcmp( input->x + input->len - nb, buf, nb ) == 0 );
+            for( size_t i = 0; i < leading_zeroes; i++ )
+                TEST_EQUAL( input->x[i], 0 );
+        }
+    }
+
+exit:
+    ;
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void mbedtls_mpi_core_io_le( data_t *input, int nb_int, int nx_32_int, int iret,
+                             int oret )
+{
+    if( iret != 0 )
+        TEST_ASSERT( oret == 0 );
+
+    TEST_ASSERT( 0 <= nb_int );
+    size_t nb = nb_int;
+
+    unsigned char buf[1024];
+    TEST_ASSERT( nb <= sizeof( buf ) );
+
+    /* nx_32_int is the number of 32 bit limbs, if we have 64 bit limbs we need
+     * to halve the number of limbs to have the same size. */
+    size_t nx;
+    TEST_ASSERT( 0 <= nx_32_int );
+    if( sizeof( mbedtls_mpi_uint ) == 8 )
+        nx = nx_32_int / 2 + nx_32_int % 2;
+    else
+        nx = nx_32_int;
+
+    mbedtls_mpi_uint X[sizeof( buf ) / sizeof( mbedtls_mpi_uint )];
+    TEST_ASSERT( nx <= sizeof( X ) / sizeof( X[0] ) );
+
+    int ret =  mbedtls_mpi_core_read_le( X, nx, input->x, input->len );
+    TEST_EQUAL( ret, iret );
+
+    if( iret == 0 )
+    {
+        ret =  mbedtls_mpi_core_write_le( X, nx, buf, nb );
+        TEST_EQUAL( ret, oret );
+    }
+
+    if( ( iret == 0 ) && ( oret == 0 ) )
+    {
+        if( nb > input->len )
+        {
+            TEST_ASSERT( memcmp( buf, input->x, input->len ) == 0 );
+            for( size_t i = input->len; i < nb; i++ )
+                TEST_EQUAL( buf[i], 0 );
+        }
+        else
+        {
+            TEST_ASSERT( memcmp( input->x, buf, nb ) == 0 );
+            for( size_t i = nb; i < input->len; i++ )
+                TEST_EQUAL( input->x[i], 0 );
+        }
+    }
+
+exit:
+    ;
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void mbedtls_mpi_mod_setup( int ext_rep, int int_rep, int iret )
+{
+    #define MLIMBS 8
+    mbedtls_mpi_uint mp[MLIMBS];
+    mbedtls_mpi_mod_modulus m;
+    int ret;
+
+    memset( mp, 0xFF, sizeof(mp) );
+
+    mbedtls_mpi_mod_modulus_init( &m );
+    ret = mbedtls_mpi_mod_modulus_setup( &m, mp, MLIMBS, ext_rep, int_rep );
+    TEST_EQUAL( ret, iret );
+
+    /* Address sanitiser should catch if we try to free mp */
+    mbedtls_mpi_mod_modulus_free( &m );
+
+    /* Make sure that the modulus doesn't have reference to mp anymore */
+    TEST_ASSERT( m.p != mp );
+
+exit:
+    /* It should be safe to call an mbedtls free several times */
+    mbedtls_mpi_mod_modulus_free( &m );
+
+    #undef MLIMBS
+}
+/* END_CASE */
+
+
+/* BEGIN_CASE */
+void mbedtls_mpi_mod_raw_io( data_t *input, int nb_int, int nx_32_int,
+                             int iendian, int iret, int oret )
+{
+    if( iret != 0 )
+        TEST_ASSERT( oret == 0 );
+
+    TEST_ASSERT( 0 <= nb_int );
+    size_t nb = nb_int;
+
+    unsigned char buf[1024];
+    TEST_ASSERT( nb <= sizeof( buf ) );
+
+    /* nx_32_int is the number of 32 bit limbs, if we have 64 bit limbs we need
+     * to halve the number of limbs to have the same size. */
+    size_t nx;
+    TEST_ASSERT( 0 <= nx_32_int );
+    if( sizeof( mbedtls_mpi_uint ) == 8 )
+        nx = nx_32_int / 2 + nx_32_int % 2;
+    else
+        nx = nx_32_int;
+
+    mbedtls_mpi_uint X[sizeof( buf ) / sizeof( mbedtls_mpi_uint )];
+    TEST_ASSERT( nx <= sizeof( X ) / sizeof( X[0] ) );
+
+    int endian;
+    if( iendian == MBEDTLS_MPI_MOD_EXT_REP_INVALID )
+        endian = MBEDTLS_MPI_MOD_EXT_REP_LE;
+    else
+        endian = iendian;
+
+    mbedtls_mpi_mod_modulus m;
+    mbedtls_mpi_mod_modulus_init( &m );
+    mbedtls_mpi_uint init[sizeof( X ) / sizeof( X[0] )];
+    memset( init, 0xFF, sizeof( init ) );
+    int ret = mbedtls_mpi_mod_modulus_setup( &m, init, nx, endian,
+                                             MBEDTLS_MPI_MOD_REP_MONTGOMERY );
+    TEST_EQUAL( ret, 0 );
+
+    if( iendian == MBEDTLS_MPI_MOD_EXT_REP_INVALID && iret != 0 )
+        m.ext_rep = MBEDTLS_MPI_MOD_EXT_REP_INVALID;
+
+    ret = mbedtls_mpi_mod_raw_read( X, &m, input->x, input->len );
+    TEST_EQUAL( ret, iret );
+
+    if( iret == 0 )
+    {
+        if( iendian == MBEDTLS_MPI_MOD_EXT_REP_INVALID && oret != 0 )
+            m.ext_rep = MBEDTLS_MPI_MOD_EXT_REP_INVALID;
+
+        ret = mbedtls_mpi_mod_raw_write( X, &m, buf, nb );
+        TEST_EQUAL( ret, oret );
+    }
+
+    if( ( iret == 0 ) && ( oret == 0 ) )
+    {
+        if( nb > input->len )
+        {
+            if( endian == MBEDTLS_MPI_MOD_EXT_REP_BE )
+            {
+                size_t leading_zeroes = nb - input->len;
+                TEST_ASSERT( memcmp( buf + nb - input->len, input->x, input->len ) == 0 );
+                for( size_t i = 0; i < leading_zeroes; i++ )
+                    TEST_EQUAL( buf[i], 0 );
+            }
+            else
+            {
+                TEST_ASSERT( memcmp( buf, input->x, input->len ) == 0 );
+                for( size_t i = input->len; i < nb; i++ )
+                    TEST_EQUAL( buf[i], 0 );
+            }
+        }
+        else
+        {
+            if( endian == MBEDTLS_MPI_MOD_EXT_REP_BE )
+            {
+                size_t leading_zeroes = input->len - nb;
+                TEST_ASSERT( memcmp( input->x + input->len - nb, buf, nb ) == 0 );
+                for( size_t i = 0; i < leading_zeroes; i++ )
+                    TEST_EQUAL( input->x[i], 0 );
+            }
+            else
+            {
+                TEST_ASSERT( memcmp( input->x, buf, nb ) == 0 );
+                for( size_t i = nb; i < input->len; i++ )
+                    TEST_EQUAL( input->x[i], 0 );
+            }
+        }
+    }
+
+exit:
+    mbedtls_mpi_mod_modulus_free( &m );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
 void mbedtls_mpi_read_binary_le( data_t * buf, char * input_A )
 {
     mbedtls_mpi X;
@@ -456,6 +728,42 @@
 /* END_CASE */
 
 /* BEGIN_CASE */
+void mpi_core_lt_ct( data_t * input_X, data_t * input_Y, int input_ret )
+{
+    #define MAX_LEN 64
+    mbedtls_mpi_uint X[MAX_LEN];
+    mbedtls_mpi_uint Y[MAX_LEN];
+    unsigned exp_ret = input_ret;
+    unsigned ret;
+    size_t len = CHARS_TO_LIMBS(
+                    input_X->len > input_Y->len ? input_X->len : input_Y->len );
+
+    TEST_ASSERT( len <= MAX_LEN );
+
+    TEST_ASSERT( mbedtls_mpi_core_read_be( X, len, input_X->x, input_X->len )
+                 == 0 );
+    TEST_ASSERT( mbedtls_mpi_core_read_be( Y, len, input_Y->x, input_Y->len )
+                 == 0 );
+
+    TEST_CF_SECRET( X, len * sizeof( mbedtls_mpi_uint ) );
+    TEST_CF_SECRET( Y, len * sizeof( mbedtls_mpi_uint ) );
+
+    ret = mbedtls_mpi_core_lt_ct( X, Y, len );
+
+    TEST_CF_PUBLIC( X, len * sizeof( mbedtls_mpi_uint ) );
+    TEST_CF_PUBLIC( Y, len * sizeof( mbedtls_mpi_uint ) );
+    TEST_CF_PUBLIC( &ret, sizeof( ret ) );
+
+    TEST_EQUAL( ret, exp_ret );
+
+exit:
+    ;
+
+    #undef MAX_LEN
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
 void mbedtls_mpi_lt_mpi_ct( int size_X, char * input_X,
                             int size_Y, char * input_Y,
                             int input_ret, int input_err )