mirror of
https://github.com/yuzu-emu/mbedtls.git
synced 2025-02-24 05:06:56 +00:00
mbedtls_ecp_gen_privkey_sw: range and coverage tests
Add unit tests for private key generation on short Weierstrass curves. These tests validate that the result is within the desired range. Additionally, they validate that after performing many iterations, the range is covered to an acceptable extent: for tiny ranges, all values must be reached; for larger ranges, all value bits must reach both 0 and 1. Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
This commit is contained in:
parent
eadf31d56a
commit
6373fab865
|
@ -312,6 +312,96 @@ genkey_mx_known_answer:447:"ffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|||
ECP generate Montgomery key: Curve448, not enough entropy
|
||||
genkey_mx_known_answer:447:"4f0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f30313233343536":""
|
||||
|
||||
ECP generate in range: 4
|
||||
genkey_sw_many:"04":1000
|
||||
|
||||
ECP generate in range: 5
|
||||
genkey_sw_many:"05":1000
|
||||
|
||||
ECP generate in range: 6
|
||||
genkey_sw_many:"06":1000
|
||||
|
||||
ECP generate in range: 7
|
||||
genkey_sw_many:"07":1000
|
||||
|
||||
ECP generate in range: 8
|
||||
genkey_sw_many:"08":1000
|
||||
|
||||
ECP generate in range: 9
|
||||
genkey_sw_many:"09":1000
|
||||
|
||||
ECP generate in range: 10
|
||||
genkey_sw_many:"0a":1000
|
||||
|
||||
ECP generate in range: 11
|
||||
genkey_sw_many:"0b":1000
|
||||
|
||||
ECP generate in range: 12
|
||||
genkey_sw_many:"0c":1000
|
||||
|
||||
ECP generate in range: 255
|
||||
genkey_sw_many:"ff":100
|
||||
|
||||
ECP generate in range: 256
|
||||
genkey_sw_many:"0100":100
|
||||
|
||||
ECP generate in range: 257
|
||||
genkey_sw_many:"0101":100
|
||||
|
||||
ECP generate in range: 272
|
||||
genkey_sw_many:"0110":100
|
||||
|
||||
ECP generate in range: 2^64-1
|
||||
genkey_sw_many:"ffffffffffffffff":100
|
||||
|
||||
ECP generate in range: 2^64
|
||||
genkey_sw_many:"010000000000000000":100
|
||||
|
||||
ECP generate in range: 2^64+1
|
||||
genkey_sw_many:"010000000000000001":100
|
||||
|
||||
ECP generate in range: 2^64+2^63
|
||||
genkey_sw_many:"018000000000000000":100
|
||||
|
||||
ECP generate in range: 2^65-1
|
||||
genkey_sw_many:"01ffffffffffffffff":100
|
||||
|
||||
ECP generate in range: 2^65
|
||||
genkey_sw_many:"020000000000000000":100
|
||||
|
||||
ECP generate in range: 2^65+1
|
||||
genkey_sw_many:"020000000000000001":100
|
||||
|
||||
ECP generate in range: 2^65+2^64
|
||||
genkey_sw_many:"030000000000000000":100
|
||||
|
||||
ECP generate in range: 2^66+2^65
|
||||
genkey_sw_many:"060000000000000000":100
|
||||
|
||||
ECP generate in range: 2^71-1
|
||||
genkey_sw_many:"7fffffffffffffffff":100
|
||||
|
||||
ECP generate in range: 2^71
|
||||
genkey_sw_many:"800000000000000000":100
|
||||
|
||||
ECP generate in range: 2^71+1
|
||||
genkey_sw_many:"800000000000000001":100
|
||||
|
||||
ECP generate in range: 2^71+2^63
|
||||
genkey_sw_many:"c00000000000000000":100
|
||||
|
||||
ECP generate in range: 2^72-1
|
||||
genkey_sw_many:"ffffffffffffffffff":100
|
||||
|
||||
ECP generate in range: 2^72
|
||||
genkey_sw_many:"01000000000000000000":100
|
||||
|
||||
ECP generate in range: 2^72+1
|
||||
genkey_sw_many:"01000000000000000001":100
|
||||
|
||||
ECP generate in range: 2^72+2^63
|
||||
genkey_sw_many:"01800000000000000000":100
|
||||
|
||||
ECP read key #1 (short weierstrass, too small)
|
||||
depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED
|
||||
mbedtls_ecp_read_key:MBEDTLS_ECP_DP_SECP192R1:"00":MBEDTLS_ERR_ECP_INVALID_KEY:0
|
||||
|
|
|
@ -15,6 +15,43 @@
|
|||
#define ECP_PT_RESET( x ) \
|
||||
mbedtls_ecp_point_free( x ); \
|
||||
mbedtls_ecp_point_init( x );
|
||||
|
||||
#if defined(MBEDTLS_TEST_HOOKS) && defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED)
|
||||
/* Test whether bytes represents (in big-endian base 256) a number B that
|
||||
* is "significantly" above a power of 2, which is defined as follows.
|
||||
* Let n be the integer such that 2^n <= B < 2^{n+1}. B is significantly
|
||||
* above a power of 2 if (B - 2^n) / 2^n is not negligible. "Negligible"
|
||||
* is defined as having a negligible chance that if you draw an integer
|
||||
* in the range [1, B-1] K times, the number will always be less than 2^n,
|
||||
* where K is the iteration count passed to genkey_sw_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;
|
||||
while( len > 0 && p[0] == 0 )
|
||||
{
|
||||
++p;
|
||||
--len;
|
||||
}
|
||||
if( len == 0 )
|
||||
return( 0 );
|
||||
else if( len == 1 )
|
||||
x = p[0];
|
||||
else
|
||||
x = ( p[0] << 8 ) | p[1];
|
||||
|
||||
if( x <= 4 )
|
||||
return( 0 );
|
||||
|
||||
while( ( x & 0x8000 ) == 0 )
|
||||
x <<= 1;
|
||||
x &= 0x7fff;
|
||||
return( x >= 0x1000 );
|
||||
}
|
||||
#endif
|
||||
|
||||
/* END_HEADER */
|
||||
|
||||
/* BEGIN_DEPENDENCIES
|
||||
|
@ -1286,6 +1323,114 @@ exit:
|
|||
}
|
||||
/* END_CASE */
|
||||
|
||||
/* BEGIN_CASE depends_on:MBEDTLS_TEST_HOOKS:MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */
|
||||
void genkey_sw_many( 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 bound;
|
||||
size_t n_bits;
|
||||
mbedtls_mpi result;
|
||||
size_t b;
|
||||
/* If 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( &bound );
|
||||
mbedtls_mpi_init( &result );
|
||||
|
||||
TEST_EQUAL( 0, mbedtls_mpi_read_binary( &bound,
|
||||
bound_bytes->x, bound_bytes->len ) );
|
||||
n_bits = mbedtls_mpi_bitlen( &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_ecp_gen_privkey_sw(
|
||||
&bound, n_bits, &result,
|
||||
mbedtls_test_rnd_std_rand, NULL ) );
|
||||
|
||||
TEST_ASSERT( mbedtls_mpi_cmp_mpi( &result, &bound ) < 0 );
|
||||
TEST_ASSERT( mbedtls_mpi_cmp_int( &result, 1 ) >= 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 = 1; 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
|
||||
{
|
||||
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( b != n_bits - 1 ||
|
||||
is_significantly_above_a_power_of_2( bound_bytes ) )
|
||||
{
|
||||
TEST_ASSERT( stats[b] > 0 );
|
||||
}
|
||||
TEST_ASSERT( stats[b] < (size_t) iterations );
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
mbedtls_mpi_free( &bound );
|
||||
mbedtls_mpi_free( &result );
|
||||
mbedtls_free( stats );
|
||||
}
|
||||
/* END_CASE */
|
||||
|
||||
/* BEGIN_CASE depends_on:MBEDTLS_SELF_TEST */
|
||||
void ecp_selftest( )
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue