Avoid UB caused by conversion to int

Signed-off-by: Manuel Pégourié-Gonnard <manuel.pegourie-gonnard@arm.com>
diff --git a/library/bignum.c b/library/bignum.c
index d934cb2..641049b 100644
--- a/library/bignum.c
+++ b/library/bignum.c
@@ -237,6 +237,45 @@
     memcpy(  Y, &T, sizeof( mbedtls_mpi ) );
 }
 
+/**
+ * Select between two sign values in constant-time.
+ *
+ * This is functionally equivalent to second ? a : b but uses only bit
+ * operations in order to avoid branches.
+ *
+ * \param[in] a         The first sign; must be either +1 or -1.
+ * \param[in] b         The second sign; must be either +1 or -1.
+ * \param[in] second    Must be either 1 (return b) or 0 (return a).
+ *
+ * \return The selected sign value.
+ */
+static int mpi_safe_cond_select_sign( int a, int b, unsigned char second )
+{
+    /* In order to avoid questions about what we can reasonnably assume about
+     * the representations of signed integers, move everything to unsigned
+     * by taking advantage of the fact that a and b are either +1 or -1. */
+    unsigned ua = a + 1;
+    unsigned ub = b + 1;
+
+    /* MSVC has a warning about unary minus on unsigned integer types,
+     * but this is well-defined and precisely what we want to do here. */
+#if defined(_MSC_VER)
+#pragma warning( push )
+#pragma warning( disable : 4146 )
+#endif
+    /* all-bits 1 if assign is 1, all-bits 0 if assign is 0 */
+    const unsigned mask = -second;
+#if defined(_MSC_VER)
+#pragma warning( pop )
+#endif
+
+    /* select ua or ub */
+    unsigned ur = ( ua & ~mask ) | ( ub & mask );
+
+    /* ur is now 0 or 2, convert back to -1 or +1 */
+    return( (int) ur - 1 );
+}
+
 /*
  * Conditionally assign dest = src, without leaking information
  * about whether the assignment was made or not.
@@ -277,7 +316,6 @@
 {
     int ret = 0;
     size_t i;
-    unsigned int mask;
     mbedtls_mpi_uint limb_mask;
     MPI_VALIDATE_RET( X != NULL );
     MPI_VALIDATE_RET( Y != NULL );
@@ -292,7 +330,6 @@
     /* make sure assign is 0 or 1 in a time-constant manner */
     assign = (assign | (unsigned char)-assign) >> 7;
     /* all-bits 1 if assign is 1, all-bits 0 if assign is 0 */
-    mask = -assign;
     limb_mask = -assign;
 
 #if defined(_MSC_VER)
@@ -301,7 +338,7 @@
 
     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, Y->n ) );
 
-    X->s = ( X->s & ~mask ) | ( Y->s & mask );
+    X->s = mpi_safe_cond_select_sign( X->s, Y->s, assign );
 
     mpi_safe_cond_assign( Y->n, X->p, Y->p, assign );
 
@@ -322,7 +359,6 @@
 {
     int ret, s;
     size_t i;
-    unsigned int sign_mask;
     mbedtls_mpi_uint limb_mask;
     mbedtls_mpi_uint tmp;
     MPI_VALIDATE_RET( X != NULL );
@@ -341,7 +377,6 @@
     /* make sure swap is 0 or 1 in a time-constant manner */
     swap = (swap | (unsigned char)-swap) >> 7;
     /* all-bits 1 if swap is 1, all-bits 0 if swap is 0 */
-    sign_mask = -swap;
     limb_mask = -swap;
 
 #if defined(_MSC_VER)
@@ -352,8 +387,8 @@
     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( Y, X->n ) );
 
     s = X->s;
-    X->s = ( X->s & ~sign_mask ) | ( Y->s & sign_mask );
-    Y->s = ( Y->s & ~sign_mask ) | (    s & sign_mask );
+    X->s = mpi_safe_cond_select_sign( X->s, Y->s, swap );
+    Y->s = mpi_safe_cond_select_sign( Y->s, s, swap );
 
 
     for( i = 0; i < X->n; i++ )