mirror of
https://github.com/Mbed-TLS/mbedtls.git
synced 2025-01-29 12:32:48 +00:00
Merge pull request #6303 from gilles-peskine-arm/bignum-core-random
Bignum: Implement mbedtls_mpi_core_random
This commit is contained in:
commit
5bf8629b2c
@ -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 ) );
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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 )
|
||||
|
@ -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 */
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
||||
|
235
tests/suites/test_suite_bignum_random.data
Normal file
235
tests/suites/test_suite_bignum_random.data
Normal file
@ -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"
|
334
tests/suites/test_suite_bignum_random.function
Normal file
334
tests/suites/test_suite_bignum_random.function
Normal file
@ -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 */
|
Loading…
x
Reference in New Issue
Block a user