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;