diff --git a/library/bignum.c b/library/bignum.c index 65708c9f3a..fc4ddf6fe0 100644 --- a/library/bignum.c +++ b/library/bignum.c @@ -2032,75 +2032,19 @@ int mbedtls_mpi_random( mbedtls_mpi *X, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) { - int ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA; - int count; - unsigned lt_lower = 1, lt_upper = 0; - size_t n_bits = mbedtls_mpi_bitlen( N ); - size_t n_bytes = ( n_bits + 7 ) / 8; - mbedtls_mpi lower_bound; - if( min < 0 ) return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); if( mbedtls_mpi_cmp_int( N, min ) <= 0 ) return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); - /* - * When min == 0, each try has at worst a probability 1/2 of failing - * (the msb has a probability 1/2 of being 0, and then the result will - * be < N), so after 30 tries failure probability is a most 2**(-30). - * - * When N is just below a power of 2, as is the case when generating - * a random scalar on most elliptic curves, 1 try is enough with - * overwhelming probability. When N is just above a power of 2, - * as when generating a random scalar on secp224k1, each try has - * a probability of failing that is almost 1/2. - * - * The probabilities are almost the same if min is nonzero but negligible - * compared to N. This is always the case when N is crypto-sized, but - * it's convenient to support small N for testing purposes. When N - * is small, use a higher repeat count, otherwise the probability of - * failure is macroscopic. - */ - count = ( n_bytes > 4 ? 30 : 250 ); - - mbedtls_mpi_init( &lower_bound ); - /* Ensure that target MPI has exactly the same number of limbs * as the upper bound, even if the upper bound has leading zeros. - * This is necessary for the mbedtls_mpi_lt_mpi_ct() check. */ - MBEDTLS_MPI_CHK( mbedtls_mpi_resize_clear( X, N->n ) ); - MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &lower_bound, N->n ) ); - MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &lower_bound, min ) ); + * This is necessary for mbedtls_mpi_core_random. */ + int ret = mbedtls_mpi_resize_clear( X, N->n ); + if( ret != 0 ) + return( ret ); - /* - * Match the procedure given in RFC 6979 §3.3 (deterministic ECDSA) - * when f_rng is a suitably parametrized instance of HMAC_DRBG: - * - use the same byte ordering; - * - keep the leftmost n_bits bits of the generated octet string; - * - try until result is in the desired range. - * This also avoids any bias, which is especially important for ECDSA. - */ - do - { - MBEDTLS_MPI_CHK( mbedtls_mpi_core_fill_random( X->p, X->n, - n_bytes, - f_rng, p_rng ) ); - MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( X, 8 * n_bytes - n_bits ) ); - - if( --count == 0 ) - { - ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; - goto cleanup; - } - - MBEDTLS_MPI_CHK( mbedtls_mpi_lt_mpi_ct( X, &lower_bound, <_lower ) ); - MBEDTLS_MPI_CHK( mbedtls_mpi_lt_mpi_ct( X, N, <_upper ) ); - } - while( lt_lower != 0 || lt_upper == 0 ); - -cleanup: - mbedtls_mpi_free( &lower_bound ); - return( ret ); + return( mbedtls_mpi_core_random( X->p, min, N->p, X->n, f_rng, p_rng ) ); } /* diff --git a/library/bignum_core.c b/library/bignum_core.c index 1ce84574e5..064b1583d8 100644 --- a/library/bignum_core.c +++ b/library/bignum_core.c @@ -134,6 +134,27 @@ void mbedtls_mpi_core_bigendian_to_host( mbedtls_mpi_uint *A, } } +/* Whether min <= A, in constant time. + * A_limbs must be at least 1. */ +unsigned mbedtls_mpi_core_uint_le_mpi( mbedtls_mpi_uint min, + const mbedtls_mpi_uint *A, + size_t A_limbs ) +{ + /* min <= least significant limb? */ + unsigned min_le_lsl = 1 ^ mbedtls_ct_mpi_uint_lt( A[0], min ); + + /* limbs other than the least significant one are all zero? */ + mbedtls_mpi_uint msll_mask = 0; + for( size_t i = 1; i < A_limbs; i++ ) + msll_mask |= A[i]; + /* The most significant limbs of A are not all zero iff msll_mask != 0. */ + unsigned msll_nonzero = mbedtls_ct_mpi_uint_mask( msll_mask ) & 1; + + /* min <= A iff the lowest limb of A is >= min or the other limbs + * are not all zero. */ + return( min_le_lsl | msll_nonzero ); +} + void mbedtls_mpi_core_cond_assign( mbedtls_mpi_uint *X, const mbedtls_mpi_uint *A, size_t limbs, @@ -561,6 +582,67 @@ cleanup: return( ret ); } +int mbedtls_mpi_core_random( mbedtls_mpi_uint *X, + mbedtls_mpi_uint min, + const mbedtls_mpi_uint *N, + size_t limbs, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + unsigned ge_lower = 1, lt_upper = 0; + size_t n_bits = mbedtls_mpi_core_bitlen( N, limbs ); + size_t n_bytes = ( n_bits + 7 ) / 8; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + /* + * When min == 0, each try has at worst a probability 1/2 of failing + * (the msb has a probability 1/2 of being 0, and then the result will + * be < N), so after 30 tries failure probability is a most 2**(-30). + * + * When N is just below a power of 2, as is the case when generating + * a random scalar on most elliptic curves, 1 try is enough with + * overwhelming probability. When N is just above a power of 2, + * as when generating a random scalar on secp224k1, each try has + * a probability of failing that is almost 1/2. + * + * The probabilities are almost the same if min is nonzero but negligible + * compared to N. This is always the case when N is crypto-sized, but + * it's convenient to support small N for testing purposes. When N + * is small, use a higher repeat count, otherwise the probability of + * failure is macroscopic. + */ + int count = ( n_bytes > 4 ? 30 : 250 ); + + /* + * Match the procedure given in RFC 6979 §3.3 (deterministic ECDSA) + * when f_rng is a suitably parametrized instance of HMAC_DRBG: + * - use the same byte ordering; + * - keep the leftmost n_bits bits of the generated octet string; + * - try until result is in the desired range. + * This also avoids any bias, which is especially important for ECDSA. + */ + do + { + MBEDTLS_MPI_CHK( mbedtls_mpi_core_fill_random( X, limbs, + n_bytes, + f_rng, p_rng ) ); + mbedtls_mpi_core_shift_r( X, limbs, 8 * n_bytes - n_bits ); + + if( --count == 0 ) + { + ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; + goto cleanup; + } + + ge_lower = mbedtls_mpi_core_uint_le_mpi( min, X, limbs ); + lt_upper = mbedtls_mpi_core_lt_ct( X, N, limbs ); + } + while( ge_lower == 0 || lt_upper == 0 ); + +cleanup: + return( ret ); +} + /* BEGIN MERGE SLOT 1 */ static size_t exp_mod_get_window_size( size_t Ebits ) diff --git a/library/bignum_core.h b/library/bignum_core.h index b7af4d0aae..bfc9725d09 100644 --- a/library/bignum_core.h +++ b/library/bignum_core.h @@ -129,6 +129,22 @@ size_t mbedtls_mpi_core_bitlen( const mbedtls_mpi_uint *A, size_t A_limbs ); void mbedtls_mpi_core_bigendian_to_host( mbedtls_mpi_uint *A, size_t A_limbs ); +/** \brief Compare a machine integer with an MPI. + * + * This function operates in constant time with respect + * to the values of \p min and \p A. + * + * \param min A machine integer. + * \param[in] A An MPI. + * \param A_limbs The number of limbs of \p A. + * This must be at least 1. + * + * \return 1 if \p min is less than or equal to \p A, otherwise 0. + */ +unsigned mbedtls_mpi_core_uint_le_mpi( mbedtls_mpi_uint min, + const mbedtls_mpi_uint *A, + size_t A_limbs ); + /** * \brief Perform a safe conditional copy of an MPI which doesn't reveal * whether assignment was done or not. @@ -496,6 +512,43 @@ int mbedtls_mpi_core_fill_random( mbedtls_mpi_uint *X, size_t X_limbs, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); +/** Generate a random number uniformly in a range. + * + * This function generates a random number between \p min inclusive and + * \p N exclusive. + * + * The procedure complies with RFC 6979 §3.3 (deterministic ECDSA) + * when the RNG is a suitably parametrized instance of HMAC_DRBG + * and \p min is \c 1. + * + * \note There are `N - min` possible outputs. The lower bound + * \p min can be reached, but the upper bound \p N cannot. + * + * \param X The destination MPI, with \p limbs limbs. + * It must not be aliased with \p N or otherwise overlap it. + * \param min The minimum value to return. + * \param N The upper bound of the range, exclusive, with \p limbs limbs. + * In other words, this is one plus the maximum value to return. + * \p N must be strictly larger than \p min. + * \param limbs The number of limbs of \p N and \p X. + * This must not be 0. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG parameter to be passed to \p f_rng. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if the implementation was + * unable to find a suitable value within a limited number + * of attempts. This has a negligible probability if \p N + * is significantly larger than \p min, which is the case + * for all usual cryptographic applications. + */ +int mbedtls_mpi_core_random( mbedtls_mpi_uint *X, + mbedtls_mpi_uint min, + const mbedtls_mpi_uint *N, + size_t limbs, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + /* BEGIN MERGE SLOT 1 */ /** diff --git a/tests/suites/test_suite_bignum.function b/tests/suites/test_suite_bignum.function index 55bb2f58d2..01af2ffc06 100644 --- a/tests/suites/test_suite_bignum.function +++ b/tests/suites/test_suite_bignum.function @@ -2,6 +2,7 @@ #include "mbedtls/bignum.h" #include "mbedtls/entropy.h" #include "constant_time_internal.h" +#include "bignum_core.h" #include "test/constant_flow.h" #if MBEDTLS_MPI_MAX_BITS > 792 @@ -89,50 +90,6 @@ static int f_rng_bytes_left( void *state, unsigned char *buf, size_t len ) return( 0 ); } -/* Test whether bytes represents (in big-endian base 256) a number b that - * is significantly above a power of 2. That is, b must not have a long run - * of unset bits after the most significant bit. - * - * Let n be the bit-size of b, i.e. the integer such that 2^n <= b < 2^{n+1}. - * This function returns 1 if, when drawing a number between 0 and b, - * the probability that this number is at least 2^n is not negligible. - * This probability is (b - 2^n) / b and this function checks that this - * number is above some threshold A. The threshold value is heuristic and - * based on the needs of mpi_random_many(). - */ -static int is_significantly_above_a_power_of_2( data_t *bytes ) -{ - const uint8_t *p = bytes->x; - size_t len = bytes->len; - unsigned x; - - /* Skip leading null bytes */ - while( len > 0 && p[0] == 0 ) - { - ++p; - --len; - } - /* 0 is not significantly above a power of 2 */ - if( len == 0 ) - return( 0 ); - /* Extract the (up to) 2 most significant bytes */ - if( len == 1 ) - x = p[0]; - else - x = ( p[0] << 8 ) | p[1]; - - /* Shift the most significant bit of x to position 8 and mask it out */ - while( ( x & 0xfe00 ) != 0 ) - x >>= 1; - x &= 0x00ff; - - /* At this point, x = floor((b - 2^n) / 2^(n-8)). b is significantly above - * a power of 2 iff x is significantly above 0 compared to 2^8. - * Testing x >= 2^4 amounts to picking A = 1/16 in the function - * description above. */ - return( x >= 0x10 ); -} - /* END_HEADER */ /* BEGIN_DEPENDENCIES @@ -1294,170 +1251,6 @@ exit: } /* END_CASE */ -/* BEGIN_CASE */ -void mpi_random_many( int min, data_t *bound_bytes, int iterations ) -{ - /* Generate numbers in the range 1..bound-1. Do it iterations times. - * This function assumes that the value of bound is at least 2 and - * that iterations is large enough that a one-in-2^iterations chance - * effectively never occurs. - */ - - mbedtls_mpi upper_bound; - size_t n_bits; - mbedtls_mpi result; - size_t b; - /* If upper_bound is small, stats[b] is the number of times the value b - * has been generated. Otherwise stats[b] is the number of times a - * value with bit b set has been generated. */ - size_t *stats = NULL; - size_t stats_len; - int full_stats; - size_t i; - - mbedtls_mpi_init( &upper_bound ); - mbedtls_mpi_init( &result ); - - TEST_EQUAL( 0, mbedtls_mpi_read_binary( &upper_bound, - bound_bytes->x, bound_bytes->len ) ); - n_bits = mbedtls_mpi_bitlen( &upper_bound ); - /* Consider a bound "small" if it's less than 2^5. This value is chosen - * to be small enough that the probability of missing one value is - * negligible given the number of iterations. It must be less than - * 256 because some of the code below assumes that "small" values - * fit in a byte. */ - if( n_bits <= 5 ) - { - full_stats = 1; - stats_len = bound_bytes->x[bound_bytes->len - 1]; - } - else - { - full_stats = 0; - stats_len = n_bits; - } - ASSERT_ALLOC( stats, stats_len ); - - for( i = 0; i < (size_t) iterations; i++ ) - { - mbedtls_test_set_step( i ); - TEST_EQUAL( 0, mbedtls_mpi_random( &result, min, &upper_bound, - mbedtls_test_rnd_std_rand, NULL ) ); - - TEST_ASSERT( sign_is_valid( &result ) ); - TEST_ASSERT( mbedtls_mpi_cmp_mpi( &result, &upper_bound ) < 0 ); - TEST_ASSERT( mbedtls_mpi_cmp_int( &result, min ) >= 0 ); - if( full_stats ) - { - uint8_t value; - TEST_EQUAL( 0, mbedtls_mpi_write_binary( &result, &value, 1 ) ); - TEST_ASSERT( value < stats_len ); - ++stats[value]; - } - else - { - for( b = 0; b < n_bits; b++ ) - stats[b] += mbedtls_mpi_get_bit( &result, b ); - } - } - - if( full_stats ) - { - for( b = min; b < stats_len; b++ ) - { - mbedtls_test_set_step( 1000000 + b ); - /* Assert that each value has been reached at least once. - * This is almost guaranteed if the iteration count is large - * enough. This is a very crude way of checking the distribution. - */ - TEST_ASSERT( stats[b] > 0 ); - } - } - else - { - int statistically_safe_all_the_way = - is_significantly_above_a_power_of_2( bound_bytes ); - for( b = 0; b < n_bits; b++ ) - { - mbedtls_test_set_step( 1000000 + b ); - /* Assert that each bit has been set in at least one result and - * clear in at least one result. Provided that iterations is not - * too small, it would be extremely unlikely for this not to be - * the case if the results are uniformly distributed. - * - * As an exception, the top bit may legitimately never be set - * if bound is a power of 2 or only slightly above. - */ - if( statistically_safe_all_the_way || b != n_bits - 1 ) - { - TEST_ASSERT( stats[b] > 0 ); - } - TEST_ASSERT( stats[b] < (size_t) iterations ); - } - } - -exit: - mbedtls_mpi_free( &upper_bound ); - mbedtls_mpi_free( &result ); - mbedtls_free( stats ); -} -/* END_CASE */ - -/* BEGIN_CASE */ -void mpi_random_sizes( int min, data_t *bound_bytes, int nlimbs, int before ) -{ - mbedtls_mpi upper_bound; - mbedtls_mpi result; - - mbedtls_mpi_init( &upper_bound ); - mbedtls_mpi_init( &result ); - - if( before != 0 ) - { - /* Set result to sign(before) * 2^(|before|-1) */ - TEST_ASSERT( mbedtls_mpi_lset( &result, before > 0 ? 1 : -1 ) == 0 ); - if( before < 0 ) - before = - before; - TEST_ASSERT( mbedtls_mpi_shift_l( &result, before - 1 ) == 0 ); - } - - TEST_EQUAL( 0, mbedtls_mpi_grow( &result, nlimbs ) ); - TEST_EQUAL( 0, mbedtls_mpi_read_binary( &upper_bound, - bound_bytes->x, bound_bytes->len ) ); - TEST_EQUAL( 0, mbedtls_mpi_random( &result, min, &upper_bound, - mbedtls_test_rnd_std_rand, NULL ) ); - TEST_ASSERT( sign_is_valid( &result ) ); - TEST_ASSERT( mbedtls_mpi_cmp_mpi( &result, &upper_bound ) < 0 ); - TEST_ASSERT( mbedtls_mpi_cmp_int( &result, min ) >= 0 ); - -exit: - mbedtls_mpi_free( &upper_bound ); - mbedtls_mpi_free( &result ); -} -/* END_CASE */ - -/* BEGIN_CASE */ -void mpi_random_fail( int min, data_t *bound_bytes, int expected_ret ) -{ - mbedtls_mpi upper_bound; - mbedtls_mpi result; - int actual_ret; - - mbedtls_mpi_init( &upper_bound ); - mbedtls_mpi_init( &result ); - - TEST_EQUAL( 0, mbedtls_mpi_read_binary( &upper_bound, - bound_bytes->x, bound_bytes->len ) ); - actual_ret = mbedtls_mpi_random( &result, min, &upper_bound, - mbedtls_test_rnd_std_rand, NULL ); - TEST_EQUAL( expected_ret, actual_ret ); - -exit: - mbedtls_mpi_free( &upper_bound ); - mbedtls_mpi_free( &result ); -} -/* END_CASE */ - /* BEGIN_CASE */ void most_negative_mpi_sint( ) { @@ -1481,7 +1274,6 @@ void most_negative_mpi_sint( ) mbedtls_mpi_init( &R ); mbedtls_mpi_init( &X ); - const size_t biL = 8 * sizeof( mbedtls_mpi_sint ); mbedtls_mpi_uint most_positive_plus_1 = (mbedtls_mpi_uint) 1 << ( biL - 1 ); const mbedtls_mpi_sint most_positive = most_positive_plus_1 - 1; const mbedtls_mpi_sint most_negative = - most_positive - 1; diff --git a/tests/suites/test_suite_bignum.misc.data b/tests/suites/test_suite_bignum.misc.data index dc6830e8fa..5eda4c11ad 100644 --- a/tests/suites/test_suite_bignum.misc.data +++ b/tests/suites/test_suite_bignum.misc.data @@ -1788,176 +1788,6 @@ mpi_fill_random:16:15:0:MBEDTLS_ERR_ENTROPY_SOURCE_FAILED Fill random: MAX_SIZE bytes, RNG failure after MAX_SIZE-1 bytes mpi_fill_random:MBEDTLS_MPI_MAX_SIZE:MBEDTLS_MPI_MAX_SIZE-1:0:MBEDTLS_ERR_ENTROPY_SOURCE_FAILED -MPI random in range: 1..2 -mpi_random_many:1:"02":1000 - -MPI random in range: 1..3 -mpi_random_many:1:"03":1000 - -MPI random in range: 1..4 -mpi_random_many:1:"04":1000 - -MPI random in range: 1..5 -mpi_random_many:1:"05":1000 - -MPI random in range: 1..6 -mpi_random_many:1:"06":1000 - -MPI random in range: 1..7 -mpi_random_many:1:"07":1000 - -MPI random in range: 1..8 -mpi_random_many:1:"08":1000 - -MPI random in range: 1..9 -mpi_random_many:1:"09":1000 - -MPI random in range: 1..10 -mpi_random_many:1:"0a":1000 - -MPI random in range: 1..11 -mpi_random_many:1:"0b":1000 - -MPI random in range: 1..12 -mpi_random_many:1:"0c":1000 - -MPI random in range: 1..255 -mpi_random_many:1:"ff":200 - -MPI random in range: 1..256 -mpi_random_many:1:"0100":200 - -MPI random in range: 1..257 -mpi_random_many:1:"0101":200 - -MPI random in range: 1..272 -mpi_random_many:1:"0110":200 - -MPI random in range: 1..2^64-1 -mpi_random_many:1:"ffffffffffffffff":100 - -MPI random in range: 1..2^64 -mpi_random_many:1:"010000000000000000":100 - -MPI random in range: 1..2^64+1 -mpi_random_many:1:"010000000000000001":100 - -MPI random in range: 1..2^64+2^63 -mpi_random_many:1:"018000000000000000":100 - -MPI random in range: 1..2^65-1 -mpi_random_many:1:"01ffffffffffffffff":100 - -MPI random in range: 1..2^65 -mpi_random_many:1:"020000000000000000":100 - -MPI random in range: 1..2^65+1 -mpi_random_many:1:"020000000000000001":100 - -MPI random in range: 1..2^65+2^64 -mpi_random_many:1:"030000000000000000":100 - -MPI random in range: 1..2^66+2^65 -mpi_random_many:1:"060000000000000000":100 - -MPI random in range: 1..2^71-1 -mpi_random_many:1:"7fffffffffffffffff":100 - -MPI random in range: 1..2^71 -mpi_random_many:1:"800000000000000000":100 - -MPI random in range: 1..2^71+1 -mpi_random_many:1:"800000000000000001":100 - -MPI random in range: 1..2^71+2^70 -mpi_random_many:1:"c00000000000000000":100 - -MPI random in range: 1..2^72-1 -mpi_random_many:1:"ffffffffffffffffff":100 - -MPI random in range: 1..2^72 -mpi_random_many:1:"01000000000000000000":100 - -MPI random in range: 1..2^72+1 -mpi_random_many:1:"01000000000000000001":100 - -MPI random in range: 1..2^72+2^71 -mpi_random_many:1:"01800000000000000000":100 - -MPI random in range: 0..1 -mpi_random_many:0:"04":10000 - -MPI random in range: 0..4 -mpi_random_many:0:"04":10000 - -MPI random in range: 2..4 -mpi_random_many:2:"04":10000 - -MPI random in range: 3..4 -mpi_random_many:3:"04":10000 - -MPI random in range: smaller result -mpi_random_sizes:1:"aaaaaaaaaaaaaaaabbbbbbbbbbbbbbbb":1:0 - -MPI random in range: same size result (32-bit limbs) -mpi_random_sizes:1:"aaaaaaaaaaaaaaaa":2:0 - -MPI random in range: same size result (64-bit limbs) -mpi_random_sizes:1:"aaaaaaaaaaaaaaaa":1:0 - -MPI random in range: larger result -mpi_random_sizes:1:"aaaaaaaaaaaaaaaa":3:0 - -## The "0 limb in upper bound" tests rely on the fact that -## mbedtls_mpi_read_binary() bases the size of the MPI on the size of -## the input, without first checking for leading zeros. If this was -## not the case, the tests would still pass, but would not exercise -## the advertised behavior. -MPI random in range: leading 0 limb in upper bound #0 -mpi_random_sizes:1:"00aaaaaaaaaaaaaaaa":0:0 - -MPI random in range: leading 0 limb in upper bound #1 -mpi_random_sizes:1:"00aaaaaaaaaaaaaaaa":1:0 - -MPI random in range: leading 0 limb in upper bound #2 -mpi_random_sizes:1:"00aaaaaaaaaaaaaaaa":2:0 - -MPI random in range: leading 0 limb in upper bound #3 -mpi_random_sizes:1:"00aaaaaaaaaaaaaaaa":3:0 - -MPI random in range: leading 0 limb in upper bound #4 -mpi_random_sizes:1:"00aaaaaaaaaaaaaaaa":4:0 - -MPI random in range: previously small >0 -mpi_random_sizes:1:"1234567890":4:1 - -MPI random in range: previously small <0 -mpi_random_sizes:1:"1234567890":4:-1 - -MPI random in range: previously large >0 -mpi_random_sizes:1:"1234":4:65 - -MPI random in range: previously large <0 -mpi_random_sizes:1:"1234":4:-65 - -MPI random bad arguments: min < 0 -mpi_random_fail:-1:"04":MBEDTLS_ERR_MPI_BAD_INPUT_DATA - -MPI random bad arguments: min = N = 0 -mpi_random_fail:0:"00":MBEDTLS_ERR_MPI_BAD_INPUT_DATA - -MPI random bad arguments: min = N = 1 -mpi_random_fail:1:"01":MBEDTLS_ERR_MPI_BAD_INPUT_DATA - -MPI random bad arguments: min > N = 0 -mpi_random_fail:1:"00":MBEDTLS_ERR_MPI_BAD_INPUT_DATA - -MPI random bad arguments: min > N = 1 -mpi_random_fail:2:"01":MBEDTLS_ERR_MPI_BAD_INPUT_DATA - -MPI random bad arguments: min > N = 1, 0 limb in upper bound -mpi_random_fail:2:"000000000000000001":MBEDTLS_ERR_MPI_BAD_INPUT_DATA - Most negative mbedtls_mpi_sint most_negative_mpi_sint: diff --git a/tests/suites/test_suite_bignum_core.function b/tests/suites/test_suite_bignum_core.function index 78721158f0..9cb314bf5a 100644 --- a/tests/suites/test_suite_bignum_core.function +++ b/tests/suites/test_suite_bignum_core.function @@ -344,6 +344,56 @@ exit: } /* END_CASE */ +/* BEGIN_CASE */ +void mpi_core_uint_le_mpi( char *input_A ) +{ + mbedtls_mpi_uint *A = NULL; + size_t A_limbs = 0; + + TEST_EQUAL( mbedtls_test_read_mpi_core( &A, &A_limbs, input_A ), 0 ); + + int is_large = 0; /* nonzero limbs beyond the lowest-order one? */ + for( size_t i = 1; i < A_limbs; i++ ) + { + if( A[i] != 0 ) + { + is_large = 1; + break; + } + } + + TEST_CF_SECRET( A, A_limbs * sizeof( *A ) ); + + TEST_EQUAL( mbedtls_mpi_core_uint_le_mpi( 0, A, A_limbs ), 1 ); + TEST_EQUAL( mbedtls_mpi_core_uint_le_mpi( A[0], A, A_limbs ), 1 ); + + if( is_large ) + { + TEST_EQUAL( mbedtls_mpi_core_uint_le_mpi( A[0] + 1, + A, A_limbs ), 1 ); + TEST_EQUAL( mbedtls_mpi_core_uint_le_mpi( (mbedtls_mpi_uint)( -1 ) >> 1, + A, A_limbs ), 1 ); + TEST_EQUAL( mbedtls_mpi_core_uint_le_mpi( (mbedtls_mpi_uint)( -1 ), + A, A_limbs ), 1 ); + } + else + { + TEST_EQUAL( mbedtls_mpi_core_uint_le_mpi( A[0] + 1, + A, A_limbs ), + A[0] + 1 <= A[0] ); + TEST_EQUAL( mbedtls_mpi_core_uint_le_mpi( (mbedtls_mpi_uint)( -1 ) >> 1, + A, A_limbs ), + (mbedtls_mpi_uint)( -1 ) >> 1 <= A[0] ); + TEST_EQUAL( mbedtls_mpi_core_uint_le_mpi( (mbedtls_mpi_uint)( -1 ), + A, A_limbs ), + (mbedtls_mpi_uint)( -1 ) <= A[0] ); + } + +exit: + mbedtls_free( A ); +} +/* END_CASE */ + /* BEGIN_CASE */ void mpi_core_cond_assign( char * input_X, char * input_Y, diff --git a/tests/suites/test_suite_bignum_core.misc.data b/tests/suites/test_suite_bignum_core.misc.data index 62480e47f7..81a767a0c4 100644 --- a/tests/suites/test_suite_bignum_core.misc.data +++ b/tests/suites/test_suite_bignum_core.misc.data @@ -242,6 +242,69 @@ mpi_core_lt_ct:"11FFFFFFFFFFFFFFFF":"FF1111111111111111":1 mbedtls_mpi_core_lt_ct: x>y (alternating limbs) mpi_core_lt_ct:"FF1111111111111111":"11FFFFFFFFFFFFFFFF":0 +Test mbedtls_mpi_core_uint_le_mpi: 0 (1 limb) +mpi_core_uint_le_mpi:"00" + +Test mbedtls_mpi_core_uint_le_mpi: 0 (>=2 limbs) +mpi_core_uint_le_mpi:"000000000000000000" + +Test mbedtls_mpi_core_uint_le_mpi: 1 (1 limb) +mpi_core_uint_le_mpi:"01" + +Test mbedtls_mpi_core_uint_le_mpi: 1 (>=2 limbs) +mpi_core_uint_le_mpi:"000000000000000001" + +Test mbedtls_mpi_core_uint_le_mpi: 42 (1 limb) +mpi_core_uint_le_mpi:"2a" + +Test mbedtls_mpi_core_uint_le_mpi: 42 (>=2 limbs) +mpi_core_uint_le_mpi:"000000000000000042" + +Test mbedtls_mpi_core_uint_le_mpi: 2^31-1 +mpi_core_uint_le_mpi:"7fffffff" + +Test mbedtls_mpi_core_uint_le_mpi: 2^31-1 with leading zero limb +mpi_core_uint_le_mpi:"00000000007fffffff" + +Test mbedtls_mpi_core_uint_le_mpi: 2^32-1 +mpi_core_uint_le_mpi:"ffffffff" + +Test mbedtls_mpi_core_uint_le_mpi: 2^32-1 with leading zero limb +mpi_core_uint_le_mpi:"0000000000ffffffff" + +Test mbedtls_mpi_core_uint_le_mpi: 2^32 +mpi_core_uint_le_mpi:"10000000" + +Test mbedtls_mpi_core_uint_le_mpi: 2^32 with leading zero limb +mpi_core_uint_le_mpi:"000000000010000000" + +Test mbedtls_mpi_core_uint_le_mpi: 2^32+1 +mpi_core_uint_le_mpi:"10000001" + +Test mbedtls_mpi_core_uint_le_mpi: 2^32+1 with leading zero limb +mpi_core_uint_le_mpi:"000000000010000001" + +Test mbedtls_mpi_core_uint_le_mpi: 2^63-1 +mpi_core_uint_le_mpi:"7fffffffffffffff" + +Test mbedtls_mpi_core_uint_le_mpi: 2^63-1 with leading zero limb +mpi_core_uint_le_mpi:"007fffffffffffffff" + +Test mbedtls_mpi_core_uint_le_mpi: 2^64-1 +mpi_core_uint_le_mpi:"ffffffffffffffff" + +Test mbedtls_mpi_core_uint_le_mpi: 2^64-1 with leading zero limb +mpi_core_uint_le_mpi:"00ffffffffffffffff" + +Test mbedtls_mpi_core_uint_le_mpi: 2^64 +mpi_core_uint_le_mpi:"010000000000000000" + +Test mbedtls_mpi_core_uint_le_mpi: 2^64+1 +mpi_core_uint_le_mpi:"010000000000000001" + +Test mbedtls_mpi_core_uint_le_mpi: 2^64+2 +mpi_core_uint_le_mpi:"010000000000000002" + mbedtls_mpi_core_cond_assign: 1 limb mpi_core_cond_assign:"FFFFFFFF":"11111111":4 diff --git a/tests/suites/test_suite_bignum_random.data b/tests/suites/test_suite_bignum_random.data new file mode 100644 index 0000000000..fe290531a9 --- /dev/null +++ b/tests/suites/test_suite_bignum_random.data @@ -0,0 +1,235 @@ +MPI core random basic: 0..1 +mpi_core_random_basic:0:"01":0 + +MPI core random basic: 0..2 +mpi_core_random_basic:0:"02":0 + +MPI core random basic: 1..2 +mpi_core_random_basic:1:"02":0 + +MPI core random basic: 2^30..2^31 +mpi_core_random_basic:0x40000000:"80000000":0 + +MPI core random basic: 0..2^128 +mpi_core_random_basic:0x40000000:"0100000000000000000000000000000000":0 + +MPI core random basic: 2^30..2^129 +mpi_core_random_basic:0x40000000:"0200000000000000000000000000000000":0 + +# Use the same data values for mpi_core_random_basic->NOT_ACCEPTABLE +# and for mpi_random_values where we want to return NOT_ACCEPTABLE but +# this isn't checked at runtime. +MPI core random basic: 2^28-1..2^28 (NOT_ACCEPTABLE) +mpi_core_random_basic:0x0fffffff:"10000000":MBEDTLS_ERR_MPI_NOT_ACCEPTABLE + +MPI random legacy=core: 2^28-1..2^28 (NOT_ACCEPTABLE) +mpi_random_values:0x0fffffff:"10000000" + +MPI core random basic: 2^29-1..2^29 (NOT_ACCEPTABLE) +mpi_core_random_basic:0x1fffffff:"20000000":MBEDTLS_ERR_MPI_NOT_ACCEPTABLE + +MPI random legacy=core: 2^29-1..2^29 (NOT_ACCEPTABLE) +mpi_random_values:0x1fffffff:"20000000" + +MPI core random basic: 2^30-1..2^30 (NOT_ACCEPTABLE) +mpi_core_random_basic:0x3fffffff:"40000000":MBEDTLS_ERR_MPI_NOT_ACCEPTABLE + +MPI random legacy=core: 2^30-1..2^30 (NOT_ACCEPTABLE) +mpi_random_values:0x3fffffff:"40000000" + +MPI core random basic: 2^31-1..2^31 (NOT_ACCEPTABLE) +mpi_core_random_basic:0x7fffffff:"80000000":MBEDTLS_ERR_MPI_NOT_ACCEPTABLE + +MPI random legacy=core: 2^31-1..2^31 (NOT_ACCEPTABLE) +mpi_random_values:0x7fffffff:"80000000" + +MPI random in range: 1..2 +mpi_random_many:1:"02":1000 + +MPI random in range: 1..3 +mpi_random_many:1:"03":1000 + +MPI random in range: 1..4 +mpi_random_many:1:"04":1000 + +MPI random in range: 1..5 +mpi_random_many:1:"05":1000 + +MPI random in range: 1..6 +mpi_random_many:1:"06":1000 + +MPI random in range: 1..7 +mpi_random_many:1:"07":1000 + +MPI random in range: 1..8 +mpi_random_many:1:"08":1000 + +MPI random in range: 1..9 +mpi_random_many:1:"09":1000 + +MPI random in range: 1..10 +mpi_random_many:1:"0a":1000 + +MPI random in range: 1..11 +mpi_random_many:1:"0b":1000 + +MPI random in range: 1..12 +mpi_random_many:1:"0c":1000 + +MPI random in range: 1..255 +mpi_random_many:1:"ff":200 + +MPI random in range: 1..256 +mpi_random_many:1:"0100":200 + +MPI random in range: 1..257 +mpi_random_many:1:"0101":200 + +MPI random in range: 1..272 +mpi_random_many:1:"0110":200 + +MPI random in range: 1..2^64-1 +mpi_random_many:1:"ffffffffffffffff":100 + +MPI random in range: 1..2^64 +mpi_random_many:1:"010000000000000000":100 + +MPI random in range: 1..2^64+1 +mpi_random_many:1:"010000000000000001":100 + +MPI random in range: 1..2^64+2^63 +mpi_random_many:1:"018000000000000000":100 + +MPI random in range: 1..2^65-1 +mpi_random_many:1:"01ffffffffffffffff":100 + +MPI random in range: 1..2^65 +mpi_random_many:1:"020000000000000000":100 + +MPI random in range: 1..2^65+1 +mpi_random_many:1:"020000000000000001":100 + +MPI random in range: 1..2^65+2^64 +mpi_random_many:1:"030000000000000000":100 + +MPI random in range: 1..2^66+2^65 +mpi_random_many:1:"060000000000000000":100 + +MPI random in range: 1..2^71-1 +mpi_random_many:1:"7fffffffffffffffff":100 + +MPI random in range: 1..2^71 +mpi_random_many:1:"800000000000000000":100 + +MPI random in range: 1..2^71+1 +mpi_random_many:1:"800000000000000001":100 + +MPI random in range: 1..2^71+2^70 +mpi_random_many:1:"c00000000000000000":100 + +MPI random in range: 1..2^72-1 +mpi_random_many:1:"ffffffffffffffffff":100 + +MPI random in range: 1..2^72 +mpi_random_many:1:"01000000000000000000":100 + +MPI random in range: 1..2^72+1 +mpi_random_many:1:"01000000000000000001":100 + +MPI random in range: 1..2^72+2^71 +mpi_random_many:1:"01800000000000000000":100 + +MPI random in range: 0..1 +mpi_random_many:0:"04":10000 + +MPI random in range: 0..4 +mpi_random_many:0:"04":10000 + +MPI random in range: 2..4 +mpi_random_many:2:"04":10000 + +MPI random in range: 3..4 +mpi_random_many:3:"04":10000 + +MPI random in range: smaller result +mpi_random_sizes:1:"aaaaaaaaaaaaaaaabbbbbbbbbbbbbbbb":1:0 + +MPI random in range: same size result (32-bit limbs) +mpi_random_sizes:1:"aaaaaaaaaaaaaaaa":2:0 + +MPI random in range: same size result (64-bit limbs) +mpi_random_sizes:1:"aaaaaaaaaaaaaaaa":1:0 + +MPI random in range: larger result +mpi_random_sizes:1:"aaaaaaaaaaaaaaaa":3:0 + +## The "0 limb in upper bound" tests rely on the fact that +## mbedtls_mpi_read_binary() bases the size of the MPI on the size of +## the input, without first checking for leading zeros. If this was +## not the case, the tests would still pass, but would not exercise +## the advertised behavior. +MPI random in range: leading 0 limb in upper bound #0 +mpi_random_sizes:1:"00aaaaaaaaaaaaaaaa":0:0 + +MPI random in range: leading 0 limb in upper bound #1 +mpi_random_sizes:1:"00aaaaaaaaaaaaaaaa":1:0 + +MPI random in range: leading 0 limb in upper bound #2 +mpi_random_sizes:1:"00aaaaaaaaaaaaaaaa":2:0 + +MPI random in range: leading 0 limb in upper bound #3 +mpi_random_sizes:1:"00aaaaaaaaaaaaaaaa":3:0 + +MPI random in range: leading 0 limb in upper bound #4 +mpi_random_sizes:1:"00aaaaaaaaaaaaaaaa":4:0 + +MPI random in range: previously small >0 +mpi_random_sizes:1:"1234567890":4:1 + +MPI random in range: previously small <0 +mpi_random_sizes:1:"1234567890":4:-1 + +MPI random in range: previously large >0 +mpi_random_sizes:1:"1234":4:65 + +MPI random in range: previously large <0 +mpi_random_sizes:1:"1234":4:-65 + +MPI random bad arguments: min < 0 +mpi_random_fail:-1:"04":MBEDTLS_ERR_MPI_BAD_INPUT_DATA + +MPI random bad arguments: min = N = 0 +mpi_random_fail:0:"00":MBEDTLS_ERR_MPI_BAD_INPUT_DATA + +MPI random bad arguments: min = N = 1 +mpi_random_fail:1:"01":MBEDTLS_ERR_MPI_BAD_INPUT_DATA + +MPI random bad arguments: min > N = 0 +mpi_random_fail:1:"00":MBEDTLS_ERR_MPI_BAD_INPUT_DATA + +MPI random bad arguments: min > N = 1 +mpi_random_fail:2:"01":MBEDTLS_ERR_MPI_BAD_INPUT_DATA + +MPI random bad arguments: min > N = 1, 0 limb in upper bound +mpi_random_fail:2:"000000000000000001":MBEDTLS_ERR_MPI_BAD_INPUT_DATA + +MPI random legacy=core: 0..1 +mpi_random_values:0:"01" + +MPI random legacy=core: 0..2 +mpi_random_values:0:"02" + +MPI random legacy=core: 1..2 +mpi_random_values:1:"02" + +MPI random legacy=core: 2^30..2^31 +mpi_random_values:0x40000000:"80000000" + +MPI random legacy=core: 2^31-1..2^32-1 +mpi_random_values:0x7fffffff:"ffffffff" + +MPI random legacy=core: 0..2^256 +mpi_random_values:0:"010000000000000000000000000000000000000000000000000000000000000000" + +MPI random legacy=core: 0..2^256+1 +mpi_random_values:0:"010000000000000000000000000000000000000000000000000000000000000001" diff --git a/tests/suites/test_suite_bignum_random.function b/tests/suites/test_suite_bignum_random.function new file mode 100644 index 0000000000..184de5a405 --- /dev/null +++ b/tests/suites/test_suite_bignum_random.function @@ -0,0 +1,334 @@ +/* BEGIN_HEADER */ +/* Dedicated test suite for mbedtls_mpi_core_random() and the upper-layer + * functions. Due to the complexity of how these functions are tested, + * we test all the layers in a single test suite, unlike the way other + * functions are tested with each layer in its own test suite. + */ + +#include "mbedtls/bignum.h" +#include "mbedtls/entropy.h" +#include "bignum_core.h" +#include "constant_time_internal.h" + +/* This test suite only manipulates non-negative bignums. */ +static int sign_is_valid( const mbedtls_mpi *X ) +{ + return( X->s == 1 ); +} + +/* A common initializer for test functions that should generate the same + * sequences for reproducibility and good coverage. */ +const mbedtls_test_rnd_pseudo_info rnd_pseudo_seed = { + /* 16-word key */ + {'T', 'h', 'i', 's', ' ', 'i', 's', ' ', + 'a', ' ', 's', 'e', 'e', 'd', '!', 0}, + /* 2-word initial state, should be zero */ + 0, 0}; + +/* Test whether bytes represents (in big-endian base 256) a number b that + * is significantly above a power of 2. That is, b must not have a long run + * of unset bits after the most significant bit. + * + * Let n be the bit-size of b, i.e. the integer such that 2^n <= b < 2^{n+1}. + * This function returns 1 if, when drawing a number between 0 and b, + * the probability that this number is at least 2^n is not negligible. + * This probability is (b - 2^n) / b and this function checks that this + * number is above some threshold A. The threshold value is heuristic and + * based on the needs of mpi_random_many(). + */ +static int is_significantly_above_a_power_of_2( data_t *bytes ) +{ + const uint8_t *p = bytes->x; + size_t len = bytes->len; + unsigned x; + + /* Skip leading null bytes */ + while( len > 0 && p[0] == 0 ) + { + ++p; + --len; + } + /* 0 is not significantly above a power of 2 */ + if( len == 0 ) + return( 0 ); + /* Extract the (up to) 2 most significant bytes */ + if( len == 1 ) + x = p[0]; + else + x = ( p[0] << 8 ) | p[1]; + + /* Shift the most significant bit of x to position 8 and mask it out */ + while( ( x & 0xfe00 ) != 0 ) + x >>= 1; + x &= 0x00ff; + + /* At this point, x = floor((b - 2^n) / 2^(n-8)). b is significantly above + * a power of 2 iff x is significantly above 0 compared to 2^8. + * Testing x >= 2^4 amounts to picking A = 1/16 in the function + * description above. */ + return( x >= 0x10 ); +} + +/* END_HEADER */ + +/* BEGIN_DEPENDENCIES + * depends_on:MBEDTLS_BIGNUM_C + * END_DEPENDENCIES + */ + +/* BEGIN_CASE */ +void mpi_core_random_basic( int min, char *bound_bytes, int expected_ret ) +{ + /* Same RNG as in mpi_random_values */ + mbedtls_test_rnd_pseudo_info rnd = rnd_pseudo_seed; + size_t limbs; + mbedtls_mpi_uint *lower_bound = NULL; + mbedtls_mpi_uint *upper_bound = NULL; + mbedtls_mpi_uint *result = NULL; + + TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &upper_bound, &limbs, + bound_bytes ) ); + ASSERT_ALLOC( lower_bound, limbs ); + lower_bound[0] = min; + ASSERT_ALLOC( result, limbs ); + + TEST_EQUAL( expected_ret, + mbedtls_mpi_core_random( result, min, upper_bound, limbs, + mbedtls_test_rnd_pseudo_rand, &rnd ) ); + + if( expected_ret == 0 ) + { + TEST_EQUAL( 0, mbedtls_mpi_core_lt_ct( result, lower_bound, limbs ) ); + TEST_EQUAL( 1, mbedtls_mpi_core_lt_ct( result, upper_bound, limbs ) ); + } + +exit: + mbedtls_free( lower_bound ); + mbedtls_free( upper_bound ); + mbedtls_free( result ); +} +/* END_CASE */ + +/* BEGIN_CASE */ +void mpi_random_values( int min, char *max_hex ) +{ + /* Same RNG as in mpi_core_random_basic */ + mbedtls_test_rnd_pseudo_info rnd_core = rnd_pseudo_seed; + mbedtls_test_rnd_pseudo_info rnd_legacy; + memcpy( &rnd_legacy, &rnd_core, sizeof( rnd_core ) ); + mbedtls_mpi max_legacy; + mbedtls_mpi_init( &max_legacy ); + mbedtls_mpi_uint *R_core = NULL; + mbedtls_mpi R_legacy; + mbedtls_mpi_init( &R_legacy ); + + TEST_EQUAL( 0, mbedtls_test_read_mpi( &max_legacy, max_hex ) ); + size_t limbs = max_legacy.n; + ASSERT_ALLOC( R_core, limbs ); + + /* Call the legacy function and the core function with the same random + * stream. */ + int core_ret = mbedtls_mpi_core_random( R_core, min, max_legacy.p, limbs, + mbedtls_test_rnd_pseudo_rand, + &rnd_core ); + int legacy_ret = mbedtls_mpi_random( &R_legacy, min, &max_legacy, + mbedtls_test_rnd_pseudo_rand, + &rnd_legacy ); + + /* They must return the same status, and, on success, output the + * same number, with the same limb count. */ + TEST_EQUAL( core_ret, legacy_ret ); + if( core_ret == 0 ) + { + ASSERT_COMPARE( R_core, limbs * ciL, + R_legacy.p, R_legacy.n * ciL ); + } + + /* Also check that they have consumed the RNG in the same way. */ + /* This may theoretically fail on rare platforms with padding in + * the structure! If this is a problem in practice, change to a + * field-by-field comparison. */ + ASSERT_COMPARE( &rnd_core, sizeof( rnd_core ), + &rnd_legacy, sizeof( rnd_legacy ) ); + +exit: + mbedtls_mpi_free( &max_legacy ); + mbedtls_free( R_core ); + mbedtls_mpi_free( &R_legacy ); +} +/* END_CASE */ + +/* BEGIN_CASE */ +void mpi_random_many( int min, char *bound_hex, int iterations ) +{ + /* Generate numbers in the range 1..bound-1. Do it iterations times. + * This function assumes that the value of bound is at least 2 and + * that iterations is large enough that a one-in-2^iterations chance + * effectively never occurs. + */ + + data_t bound_bytes = {NULL, 0}; + mbedtls_mpi_uint *upper_bound = NULL; + size_t limbs; + size_t n_bits; + mbedtls_mpi_uint *result = NULL; + size_t b; + /* If upper_bound is small, stats[b] is the number of times the value b + * has been generated. Otherwise stats[b] is the number of times a + * value with bit b set has been generated. */ + size_t *stats = NULL; + size_t stats_len; + int full_stats; + size_t i; + + TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &upper_bound, &limbs, + bound_hex ) ); + ASSERT_ALLOC( result, limbs ); + + n_bits = mbedtls_mpi_core_bitlen( upper_bound, limbs ); + /* Consider a bound "small" if it's less than 2^5. This value is chosen + * to be small enough that the probability of missing one value is + * negligible given the number of iterations. It must be less than + * 256 because some of the code below assumes that "small" values + * fit in a byte. */ + if( n_bits <= 5 ) + { + full_stats = 1; + stats_len = (uint8_t) upper_bound[0]; + } + else + { + full_stats = 0; + stats_len = n_bits; + } + ASSERT_ALLOC( stats, stats_len ); + + for( i = 0; i < (size_t) iterations; i++ ) + { + mbedtls_test_set_step( i ); + TEST_EQUAL( 0, mbedtls_mpi_core_random( result, + min, upper_bound, limbs, + mbedtls_test_rnd_std_rand, NULL ) ); + + /* Temporarily use a legacy MPI for analysis, because the + * necessary auxiliary functions don't exist yet in core. */ + mbedtls_mpi B = {1, limbs, upper_bound}; + mbedtls_mpi R = {1, limbs, result}; + + TEST_ASSERT( mbedtls_mpi_cmp_mpi( &R, &B ) < 0 ); + TEST_ASSERT( mbedtls_mpi_cmp_int( &R, min ) >= 0 ); + if( full_stats ) + { + uint8_t value; + TEST_EQUAL( 0, mbedtls_mpi_write_binary( &R, &value, 1 ) ); + TEST_ASSERT( value < stats_len ); + ++stats[value]; + } + else + { + for( b = 0; b < n_bits; b++ ) + stats[b] += mbedtls_mpi_get_bit( &R, b ); + } + } + + if( full_stats ) + { + for( b = min; b < stats_len; b++ ) + { + mbedtls_test_set_step( 1000000 + b ); + /* Assert that each value has been reached at least once. + * This is almost guaranteed if the iteration count is large + * enough. This is a very crude way of checking the distribution. + */ + TEST_ASSERT( stats[b] > 0 ); + } + } + else + { + bound_bytes.len = limbs * sizeof( mbedtls_mpi_uint ); + ASSERT_ALLOC( bound_bytes.x, bound_bytes.len ); + mbedtls_mpi_core_write_be( upper_bound, limbs, + bound_bytes.x, bound_bytes.len ); + int statistically_safe_all_the_way = + is_significantly_above_a_power_of_2( &bound_bytes ); + for( b = 0; b < n_bits; b++ ) + { + mbedtls_test_set_step( 1000000 + b ); + /* Assert that each bit has been set in at least one result and + * clear in at least one result. Provided that iterations is not + * too small, it would be extremely unlikely for this not to be + * the case if the results are uniformly distributed. + * + * As an exception, the top bit may legitimately never be set + * if bound is a power of 2 or only slightly above. + */ + if( statistically_safe_all_the_way || b != n_bits - 1 ) + { + TEST_ASSERT( stats[b] > 0 ); + } + TEST_ASSERT( stats[b] < (size_t) iterations ); + } + } + +exit: + mbedtls_free( bound_bytes.x ); + mbedtls_free( upper_bound ); + mbedtls_free( result ); + mbedtls_free( stats ); +} +/* END_CASE */ + +/* BEGIN_CASE */ +void mpi_random_sizes( int min, data_t *bound_bytes, int nlimbs, int before ) +{ + mbedtls_mpi upper_bound; + mbedtls_mpi result; + + mbedtls_mpi_init( &upper_bound ); + mbedtls_mpi_init( &result ); + + if( before != 0 ) + { + /* Set result to sign(before) * 2^(|before|-1) */ + TEST_ASSERT( mbedtls_mpi_lset( &result, before > 0 ? 1 : -1 ) == 0 ); + if( before < 0 ) + before = - before; + TEST_ASSERT( mbedtls_mpi_shift_l( &result, before - 1 ) == 0 ); + } + + TEST_EQUAL( 0, mbedtls_mpi_grow( &result, nlimbs ) ); + TEST_EQUAL( 0, mbedtls_mpi_read_binary( &upper_bound, + bound_bytes->x, bound_bytes->len ) ); + TEST_EQUAL( 0, mbedtls_mpi_random( &result, min, &upper_bound, + mbedtls_test_rnd_std_rand, NULL ) ); + TEST_ASSERT( sign_is_valid( &result ) ); + TEST_ASSERT( mbedtls_mpi_cmp_mpi( &result, &upper_bound ) < 0 ); + TEST_ASSERT( mbedtls_mpi_cmp_int( &result, min ) >= 0 ); + +exit: + mbedtls_mpi_free( &upper_bound ); + mbedtls_mpi_free( &result ); +} +/* END_CASE */ + +/* BEGIN_CASE */ +void mpi_random_fail( int min, data_t *bound_bytes, int expected_ret ) +{ + mbedtls_mpi upper_bound; + mbedtls_mpi result; + int actual_ret; + + mbedtls_mpi_init( &upper_bound ); + mbedtls_mpi_init( &result ); + + TEST_EQUAL( 0, mbedtls_mpi_read_binary( &upper_bound, + bound_bytes->x, bound_bytes->len ) ); + actual_ret = mbedtls_mpi_random( &result, min, &upper_bound, + mbedtls_test_rnd_std_rand, NULL ); + TEST_EQUAL( expected_ret, actual_ret ); + +exit: + mbedtls_mpi_free( &upper_bound ); + mbedtls_mpi_free( &result ); +} +/* END_CASE */