Add mpi_safe_cond_swap()
diff --git a/include/polarssl/bignum.h b/include/polarssl/bignum.h
index d98dce9..df17b12 100644
--- a/include/polarssl/bignum.h
+++ b/include/polarssl/bignum.h
@@ -236,11 +236,10 @@
  *
  * \param X        MPI to conditionally assign to
  * \param Y        Value to be assigned
- * \param assign   1: perform the assignment, 0: leave X untouched
+ * \param assign   1: perform the assignment, 0: keep X's original value
  *
  * \return         0 if successful,
  *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed,
- *                 POLARSSL_ERR_MPI_BAD_INPUT_DATA if assing is not 0 or 1
  *
  * \note           This function is equivalent to
  *                      if( assign ) mpi_copy( X, Y );
@@ -252,6 +251,25 @@
 int mpi_safe_cond_assign( mpi *X, const mpi *Y, unsigned char assign );
 
 /**
+ * \brief          Safe conditional swap X <-> Y if swap is 1
+ *
+ * \param X        First mpi value
+ * \param Y        Second mpi value
+ * \param assign   1: perform the swap, 0: keep X and Y's original values
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed,
+ *
+ * \note           This function is equivalent to
+ *                      if( assign ) mpi_swap( X, Y );
+ *                 except that it avoids leaking any information about whether
+ *                 the assignment was done or not (the above code may leak
+ *                 information through branch prediction and/or memory access
+ *                 patterns analysis).
+ */
+int mpi_safe_cond_swap( mpi *X, mpi *Y, unsigned char assign );
+
+/**
  * \brief          Set value from integer
  *
  * \param X        MPI to set
diff --git a/library/bignum.c b/library/bignum.c
index 98d534a..dd5c0bf 100644
--- a/library/bignum.c
+++ b/library/bignum.c
@@ -214,16 +214,16 @@
     int ret = 0;
     size_t i;
 
-    if( assign * ( 1 - assign ) != 0 )
-        return( POLARSSL_ERR_MPI_BAD_INPUT_DATA );
+    /* make sure assign is 0 or 1 */
+    assign = ( assign != 0 );
 
-    if( Y->n > X->n )
-        MPI_CHK( mpi_grow( X, Y->n ) );
+    MPI_CHK( mpi_grow( X, Y->n ) );
 
-    /* Do the conditional assign safely */
     X->s = X->s * (1 - assign) + Y->s * assign;
+
     for( i = 0; i < Y->n; i++ )
         X->p[i] = X->p[i] * (1 - assign) + Y->p[i] * assign;
+
     for( ; i < X->n; i++ )
         X->p[i] *= (1 - assign);
 
@@ -232,6 +232,43 @@
 }
 
 /*
+ * Conditionally swap X and Y, without leaking information
+ * about whether the swap was made or not.
+ * Here it is not ok to simply swap the pointers, which whould lead to
+ * different memory access patterns when X and Y are used afterwards.
+ */
+int mpi_safe_cond_swap( mpi *X, mpi *Y, unsigned char swap )
+{
+    int ret, s;
+    size_t i;
+    t_uint tmp;
+
+    if( X == Y )
+        return( 0 );
+
+    /* make sure swap is 0 or 1 */
+    swap = ( swap != 0 );
+
+    MPI_CHK( mpi_grow( X, Y->n ) );
+    MPI_CHK( mpi_grow( Y, X->n ) );
+
+    s = X->s;
+    X->s = X->s * (1 - swap) + Y->s * swap;
+    Y->s = Y->s * (1 - swap) +    s * swap;
+
+
+    for( i = 0; i < X->n; i++ )
+    {
+        tmp = X->p[i];
+        X->p[i] = X->p[i] * (1 - swap) + Y->p[i] * swap;
+        Y->p[i] = Y->p[i] * (1 - swap) +     tmp * swap;
+    }
+
+cleanup:
+    return( ret );
+}
+
+/*
  * Set value from integer
  */
 int mpi_lset( mpi *X, t_sint z )
diff --git a/tests/suites/test_suite_mpi.data b/tests/suites/test_suite_mpi.data
index 36ae8d6..fdbef02 100644
--- a/tests/suites/test_suite_mpi.data
+++ b/tests/suites/test_suite_mpi.data
@@ -223,6 +223,24 @@
 Test mpi_safe_cond_assign #6
 mpi_safe_cond_assign:-1:"01":-1:"02"
 
+Test mpi_safe_cond_swap #1
+mpi_safe_cond_swap:+1:"01":+1:"02"
+
+Test mpi_safe_cond_swap #2
+mpi_safe_cond_swap:+1:"FF000000000000000001":+1:"02"
+
+Test mpi_safe_cond_swap #3
+mpi_safe_cond_swap:+1:"01":+1:"FF000000000000000002"
+
+Test mpi_safe_cond_swap #4
+mpi_safe_cond_swap:+1:"01":-1:"02"
+
+Test mpi_safe_cond_swap #5
+mpi_safe_cond_swap:-1:"01":+1:"02"
+
+Test mpi_safe_cond_swap #6
+mpi_safe_cond_swap:-1:"01":-1:"02"
+
 Base test mpi_add_abs #1
 mpi_add_abs:10:"12345678":10:"642531":10:"12988209"
 
diff --git a/tests/suites/test_suite_mpi.function b/tests/suites/test_suite_mpi.function
index 394cd33..620c368 100644
--- a/tests/suites/test_suite_mpi.function
+++ b/tests/suites/test_suite_mpi.function
@@ -332,6 +332,36 @@
 /* END_CASE */
 
 /* BEGIN_CASE */
+void mpi_safe_cond_swap( int x_sign, char *x_str,
+                         int y_sign, char *y_str )
+{
+    mpi X, Y, XX, YY;
+
+    mpi_init( &X ); mpi_init( &Y );
+    mpi_init( &XX ); mpi_init( &YY );
+
+    TEST_ASSERT( mpi_read_string( &X, 16, x_str ) == 0 );
+    X.s = x_sign;
+    TEST_ASSERT( mpi_read_string( &Y, 16, y_str ) == 0 );
+    Y.s = y_sign;
+
+    TEST_ASSERT( mpi_copy( &XX, &X ) == 0 );
+    TEST_ASSERT( mpi_copy( &YY, &Y ) == 0 );
+
+    TEST_ASSERT( mpi_safe_cond_swap( &X, &Y, 0 ) == 0 );
+    TEST_ASSERT( mpi_cmp_mpi( &X, &XX ) == 0 );
+    TEST_ASSERT( mpi_cmp_mpi( &Y, &YY ) == 0 );
+
+    TEST_ASSERT( mpi_safe_cond_swap( &X, &Y, 1 ) == 0 );
+    TEST_ASSERT( mpi_cmp_mpi( &Y, &XX ) == 0 );
+    TEST_ASSERT( mpi_cmp_mpi( &X, &YY ) == 0 );
+
+    mpi_free( &X ); mpi_free( &Y );
+    mpi_free( &XX ); mpi_free( &YY );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
 void mpi_swap( int input_X,  int input_Y )
 {
     mpi X, Y, A;