Merge pull request #3028 from gilles-peskine-arm/mpi_copy_shrink-2.7

Backport 2.7: Improve robustness and testing of mbedtls_mpi_copy
diff --git a/library/bignum.c b/library/bignum.c
index 9692127..827a3cb 100644
--- a/library/bignum.c
+++ b/library/bignum.c
@@ -151,9 +151,10 @@
     mbedtls_mpi_uint *p;
     size_t i;
 
-    /* Actually resize up in this case */
+    /* Actually resize up if there are currently fewer than nblimbs limbs. */
     if( X->n <= nblimbs )
         return( mbedtls_mpi_grow( X, nblimbs ) );
+    /* After this point, then X->n > nblimbs and in particular X->n > 0. */
 
     for( i = X->n - 1; i > 0; i-- )
         if( X->p[i] != 0 )
@@ -190,7 +191,7 @@
     if( X == Y )
         return( 0 );
 
-    if( Y->p == NULL )
+    if( Y->n == 0 )
     {
         mbedtls_mpi_free( X );
         return( 0 );
diff --git a/tests/suites/test_suite_mpi.data b/tests/suites/test_suite_mpi.data
index 9f53e22..a6a6423 100644
--- a/tests/suites/test_suite_mpi.data
+++ b/tests/suites/test_suite_mpi.data
@@ -274,37 +274,106 @@
 Base test mbedtls_mpi_cmp_abs (Mix values) #3
 mbedtls_mpi_cmp_abs:10:"-2":10:"1":1
 
-Base test mbedtls_mpi_copy #1
-mbedtls_mpi_copy:0:1500
+Copy zero (1 limb) to positive (1 limb)
+mbedtls_mpi_copy_sint:0:1500
 
-Base test mpi_copy_self #1
+Copy zero (1 limb) to negative (1 limb)
+mbedtls_mpi_copy_sint:0:-1500
+
+Copy positive (1 limb) to zero (1 limb)
+mbedtls_mpi_copy_sint:1500:0
+
+Copy negative (1 limb) to zero (1 limb)
+mbedtls_mpi_copy_sint:-1500:0
+
+Copy positive (1 limb) to negative (1 limb)
+mbedtls_mpi_copy_sint:1500:-42
+
+Copy negative (1 limb) to positive (1 limb)
+mbedtls_mpi_copy_sint:-42:1500
+
+Copy zero (null) to zero (null)
+mbedtls_mpi_copy_binary:"":""
+
+Copy zero (null) to positive (1 limb)
+mbedtls_mpi_copy_binary:"":"1234"
+
+Copy positive (1 limb) to zero (null)
+mbedtls_mpi_copy_binary:"1234":""
+
+Copy positive to larger
+mbedtls_mpi_copy_binary:"bead":"ca5cadedb01dfaceacc01ade"
+
+Copy positive to smaller
+mbedtls_mpi_copy_binary:"ca5cadedb01dfaceacc01ade":"bead"
+
+Copy self: positive (1 limb)
 mpi_copy_self:14
 
-Base test mbedtls_mpi_swap #1
-mbedtls_mpi_swap:0:1500
+Copy self: zero (1 limb)
+mpi_copy_self:0
 
-Test mbedtls_mpi_shrink #1
+Swap zero (1 limb) with positive (1 limb)
+mbedtls_mpi_swap_sint:0:1500
+
+Swap zero (1 limb) with negative (1 limb)
+mbedtls_mpi_swap_sint:0:-1500
+
+Swap positive (1 limb) with zero (1 limb)
+mbedtls_mpi_swap_sint:1500:0
+
+Swap negative (1 limb) with zero (1 limb)
+mbedtls_mpi_swap_sint:-1500:0
+
+Swap positive (1 limb) with negative (1 limb)
+mbedtls_mpi_swap_sint:1500:-42
+
+Swap negative (1 limb) with positive (1 limb)
+mbedtls_mpi_swap_sint:-42:1500
+
+Swap zero (null) with zero (null)
+mbedtls_mpi_swap_binary:"":""
+
+Swap zero (null) with positive (1 limb)
+mbedtls_mpi_swap_binary:"":"1234"
+
+Swap positive (1 limb) with zero (null)
+mbedtls_mpi_swap_binary:"1234":""
+
+Swap positive with larger
+mbedtls_mpi_swap_binary:"bead":"ca5cadedb01dfaceacc01ade"
+
+Swap positive with smaller
+mbedtls_mpi_swap_binary:"ca5cadedb01dfaceacc01ade":"bead"
+
+Swap self: 1 limb
+mpi_swap_self:"face"
+
+Swap self: null
+mpi_swap_self:""
+
+Shrink 2 limbs in a buffer of size 2 to 4
 mbedtls_mpi_shrink:2:2:4:4
 
-Test mbedtls_mpi_shrink #2
+Shrink 2 limbs in a buffer of size 4 to 4
 mbedtls_mpi_shrink:4:2:4:4
 
-Test mbedtls_mpi_shrink #3
+Shrink 2 limbs in a buffer of size 8 to 4
 mbedtls_mpi_shrink:8:2:4:4
 
-Test mbedtls_mpi_shrink #4
+Shrink 4 limbs in a buffer of size 8 to 4
 mbedtls_mpi_shrink:8:4:4:4
 
-Test mbedtls_mpi_shrink #5
+Shrink 6 limbs in a buffer of size 8 to 4 yielding 6
 mbedtls_mpi_shrink:8:6:4:6
 
-Test mbedtls_mpi_shrink #6
+Shrink 2 limbs in a buffer of size 4 to 0 yielding 2
 mbedtls_mpi_shrink:4:2:0:2
 
-Test mbedtls_mpi_shrink #7
+Shrink 1 limbs in a buffer of size 4 to 0 yielding 1
 mbedtls_mpi_shrink:4:1:0:1
 
-Test mbedtls_mpi_shrink #8
+Shrink 0 limbs in a buffer of size 4 to 0 yielding 1
 mbedtls_mpi_shrink:4:0:0:1
 
 Test mbedtls_mpi_safe_cond_assign #1
diff --git a/tests/suites/test_suite_mpi.function b/tests/suites/test_suite_mpi.function
index f63f2e6..6f5abf3 100644
--- a/tests/suites/test_suite_mpi.function
+++ b/tests/suites/test_suite_mpi.function
@@ -374,22 +374,40 @@
 /* END_CASE */
 
 /* BEGIN_CASE */
-void mbedtls_mpi_copy( int input_X, int input_A )
+void mbedtls_mpi_copy_sint( int input_X, int input_Y )
 {
-    mbedtls_mpi X, Y, A;
-    mbedtls_mpi_init( &X ); mbedtls_mpi_init( &Y ); mbedtls_mpi_init( &A );
+    mbedtls_mpi X, Y;
+    mbedtls_mpi_init( &X ); mbedtls_mpi_init( &Y );
 
     TEST_ASSERT( mbedtls_mpi_lset( &X, input_X ) == 0 );
-    TEST_ASSERT( mbedtls_mpi_lset( &Y, input_A ) == 0 );
-    TEST_ASSERT( mbedtls_mpi_lset( &A, input_A ) == 0 );
-    TEST_ASSERT( mbedtls_mpi_cmp_mpi( &X, &Y ) != 0 );
-    TEST_ASSERT( mbedtls_mpi_cmp_mpi( &Y, &A ) == 0 );
+    TEST_ASSERT( mbedtls_mpi_lset( &Y, input_Y ) == 0 );
+
     TEST_ASSERT( mbedtls_mpi_copy( &Y, &X ) == 0 );
-    TEST_ASSERT( mbedtls_mpi_cmp_mpi( &X, &Y ) == 0 );
-    TEST_ASSERT( mbedtls_mpi_cmp_mpi( &Y, &A ) != 0 );
+    TEST_ASSERT( mbedtls_mpi_cmp_int( &X, input_X ) == 0 );
+    TEST_ASSERT( mbedtls_mpi_cmp_int( &Y, input_X ) == 0 );
 
 exit:
-    mbedtls_mpi_free( &X ); mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &A );
+    mbedtls_mpi_free( &X ); mbedtls_mpi_free( &Y );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void mbedtls_mpi_copy_binary( char *input_X, char *input_Y )
+{
+    mbedtls_mpi X, Y, X0;
+    mbedtls_mpi_init( &X ); mbedtls_mpi_init( &Y ); mbedtls_mpi_init( &X0 );
+
+    TEST_ASSERT( mbedtls_mpi_read_string( &X, 16, input_X ) == 0 );
+    TEST_ASSERT( mbedtls_mpi_read_string( &Y, 16, input_Y ) == 0 );
+    TEST_ASSERT( mbedtls_mpi_read_string( &X0, 16, input_X ) == 0 );
+    TEST_ASSERT( mbedtls_mpi_cmp_mpi( &X, &X0 ) == 0 );
+
+    TEST_ASSERT( mbedtls_mpi_copy( &Y, &X ) == 0 );
+    TEST_ASSERT( mbedtls_mpi_cmp_mpi( &X, &X0 ) == 0 );
+    TEST_ASSERT( mbedtls_mpi_cmp_mpi( &Y, &X0 ) == 0 );
+
+exit:
+    mbedtls_mpi_free( &X ); mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &X0 );
 }
 /* END_CASE */
 
@@ -481,22 +499,61 @@
 /* END_CASE */
 
 /* BEGIN_CASE */
-void mbedtls_mpi_swap( int input_X,  int input_Y )
+void mbedtls_mpi_swap_sint( int input_X, int input_Y )
 {
-    mbedtls_mpi X, Y, A;
-    mbedtls_mpi_init( &X ); mbedtls_mpi_init( &Y ); mbedtls_mpi_init( &A );
+    mbedtls_mpi X, Y;
+    mbedtls_mpi_init( &X ); mbedtls_mpi_init( &Y );
 
     TEST_ASSERT( mbedtls_mpi_lset( &X, input_X ) == 0 );
     TEST_ASSERT( mbedtls_mpi_lset( &Y, input_Y ) == 0 );
-    TEST_ASSERT( mbedtls_mpi_lset( &A, input_X ) == 0 );
-    TEST_ASSERT( mbedtls_mpi_cmp_mpi( &X, &Y ) != 0 );
-    TEST_ASSERT( mbedtls_mpi_cmp_mpi( &X, &A ) == 0 );
+    TEST_ASSERT( mbedtls_mpi_cmp_int( &X, input_X ) == 0 );
+    TEST_ASSERT( mbedtls_mpi_cmp_int( &Y, input_Y ) == 0 );
+
     mbedtls_mpi_swap( &X, &Y );
-    TEST_ASSERT( mbedtls_mpi_cmp_mpi( &X, &Y ) != 0 );
-    TEST_ASSERT( mbedtls_mpi_cmp_mpi( &Y, &A ) == 0 );
+    TEST_ASSERT( mbedtls_mpi_cmp_int( &X, input_Y ) == 0 );
+    TEST_ASSERT( mbedtls_mpi_cmp_int( &Y, input_X ) == 0 );
 
 exit:
-    mbedtls_mpi_free( &X ); mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &A );
+    mbedtls_mpi_free( &X ); mbedtls_mpi_free( &Y );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void mbedtls_mpi_swap_binary( char *input_X, char *input_Y )
+{
+    mbedtls_mpi X, Y, X0, Y0;
+    mbedtls_mpi_init( &X ); mbedtls_mpi_init( &Y );
+    mbedtls_mpi_init( &X0 ); mbedtls_mpi_init( &Y0 );
+
+    TEST_ASSERT( mbedtls_mpi_read_string( &X, 16, input_X ) == 0 );
+    TEST_ASSERT( mbedtls_mpi_read_string( &Y, 16, input_Y ) == 0 );
+    TEST_ASSERT( mbedtls_mpi_read_string( &X0, 16, input_X ) == 0 );
+    TEST_ASSERT( mbedtls_mpi_read_string( &Y0, 16, input_Y ) == 0 );
+
+    mbedtls_mpi_swap( &X, &Y );
+    TEST_ASSERT( mbedtls_mpi_cmp_mpi( &X, &Y0 ) == 0 );
+    TEST_ASSERT( mbedtls_mpi_cmp_mpi( &Y, &X0 ) == 0 );
+
+exit:
+    mbedtls_mpi_free( &X ); mbedtls_mpi_free( &Y );
+    mbedtls_mpi_free( &X0 ); mbedtls_mpi_free( &Y0 );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void mpi_swap_self( char *input_X )
+{
+    mbedtls_mpi X, X0;
+    mbedtls_mpi_init( &X ); mbedtls_mpi_init( &X0 );
+
+    TEST_ASSERT( mbedtls_mpi_read_string( &X, 16, input_X ) == 0 );
+    TEST_ASSERT( mbedtls_mpi_read_string( &X0, 16, input_X ) == 0 );
+
+    mbedtls_mpi_swap( &X, &X );
+    TEST_ASSERT( mbedtls_mpi_cmp_mpi( &X, &X0 ) == 0 );
+
+exit:
+    mbedtls_mpi_free( &X ); mbedtls_mpi_free( &X0 );
 }
 /* END_CASE */