blob: 0f431cd6d28522dba490192b28ac07bd25bb1247 [file] [log] [blame]
Gilles Peskinede09ddd2022-12-06 13:20:55 +01001/* BEGIN_HEADER */
2/* Dedicated test suite for mbedtls_mpi_core_random() and the upper-layer
3 * functions. Due to the complexity of how these functions are tested,
4 * we test all the layers in a single test suite, unlike the way other
5 * functions are tested with each layer in its own test suite.
Gilles Peskine071f4732022-12-14 19:00:56 +01006 *
7 * Test strategy
8 * =============
9 *
10 * There are three main goals for testing random() functions:
11 * - Parameter validation.
12 * - Correctness of outputs (well-formed, in range).
13 * - Distribution of outputs.
14 *
15 * We test parameter validation in a standard way, with unit tests with
16 * positive and negative cases:
17 * - mbedtls_mpi_core_random(): negative cases for mpi_core_random_basic.
18 * - mbedtls_mpi_mod_raw_random(), mbedtls_mpi_mod_random(): negative
19 * cases for mpi_mod_random_validation.
20 * - mbedtls_mpi_random(): mpi_random_fail.
21 *
22 * We test the correctness of outputs in positive tests:
23 * - mbedtls_mpi_core_random(): positive cases for mpi_core_random_basic,
24 * and mpi_random_many.
25 * - mbedtls_mpi_mod_raw_random(), mbedtls_mpi_mod_random(): tested indirectly
26 * via mpi_mod_random_values.
27 * - mbedtls_mpi_random(): mpi_random_sizes, plus indirectly via
28 * mpi_random_values.
29 *
30 * We test the distribution of outputs only for mbedtls_mpi_core_random(),
31 * in mpi_random_many, which runs the function multiple times. This also
32 * helps in validating the output range, through test cases with a small
33 * range where any output out of range would be very likely to lead to a
34 * test failure. For the other functions, we validate the distribution
35 * indirectly by testing that these functions consume the random generator
36 * in the same way as mbedtls_mpi_core_random(). This is done in
37 * mpi_mod_random_values and mpi_legacy_random_values.
Gilles Peskinede09ddd2022-12-06 13:20:55 +010038 */
39
40#include "mbedtls/bignum.h"
41#include "mbedtls/entropy.h"
42#include "bignum_core.h"
Gilles Peskinea57cf982022-12-06 22:54:09 +010043#include "bignum_mod_raw.h"
Gilles Peskinede09ddd2022-12-06 13:20:55 +010044#include "constant_time_internal.h"
45
46/* This test suite only manipulates non-negative bignums. */
47static int sign_is_valid( const mbedtls_mpi *X )
48{
49 return( X->s == 1 );
50}
51
Gilles Peskineacdefdd2022-12-15 15:10:36 +010052/* A common initializer for test functions that should generate the same
53 * sequences for reproducibility and good coverage. */
54const mbedtls_test_rnd_pseudo_info rnd_pseudo_seed = {
55 /* 16-word key */
56 {'T', 'h', 'i', 's', ' ', 'i', 's', ' ',
57 'a', ' ', 's', 'e', 'e', 'd', '!', 0},
58 /* 2-word initial state, should be zero */
59 0, 0};
60
Gilles Peskinede09ddd2022-12-06 13:20:55 +010061/* Test whether bytes represents (in big-endian base 256) a number b that
62 * is significantly above a power of 2. That is, b must not have a long run
63 * of unset bits after the most significant bit.
64 *
65 * Let n be the bit-size of b, i.e. the integer such that 2^n <= b < 2^{n+1}.
66 * This function returns 1 if, when drawing a number between 0 and b,
67 * the probability that this number is at least 2^n is not negligible.
68 * This probability is (b - 2^n) / b and this function checks that this
69 * number is above some threshold A. The threshold value is heuristic and
70 * based on the needs of mpi_random_many().
71 */
72static int is_significantly_above_a_power_of_2( data_t *bytes )
73{
74 const uint8_t *p = bytes->x;
75 size_t len = bytes->len;
76 unsigned x;
77
78 /* Skip leading null bytes */
79 while( len > 0 && p[0] == 0 )
80 {
81 ++p;
82 --len;
83 }
84 /* 0 is not significantly above a power of 2 */
85 if( len == 0 )
86 return( 0 );
87 /* Extract the (up to) 2 most significant bytes */
88 if( len == 1 )
89 x = p[0];
90 else
91 x = ( p[0] << 8 ) | p[1];
92
93 /* Shift the most significant bit of x to position 8 and mask it out */
94 while( ( x & 0xfe00 ) != 0 )
95 x >>= 1;
96 x &= 0x00ff;
97
98 /* At this point, x = floor((b - 2^n) / 2^(n-8)). b is significantly above
99 * a power of 2 iff x is significantly above 0 compared to 2^8.
100 * Testing x >= 2^4 amounts to picking A = 1/16 in the function
101 * description above. */
102 return( x >= 0x10 );
103}
104
105/* END_HEADER */
106
107/* BEGIN_DEPENDENCIES
108 * depends_on:MBEDTLS_BIGNUM_C
109 * END_DEPENDENCIES
110 */
111
112/* BEGIN_CASE */
113void mpi_core_random_basic( int min, char *bound_bytes, int expected_ret )
114{
115 /* Same RNG as in mpi_random_values */
Gilles Peskineacdefdd2022-12-15 15:10:36 +0100116 mbedtls_test_rnd_pseudo_info rnd = rnd_pseudo_seed;
Gilles Peskinede09ddd2022-12-06 13:20:55 +0100117 size_t limbs;
118 mbedtls_mpi_uint *lower_bound = NULL;
119 mbedtls_mpi_uint *upper_bound = NULL;
120 mbedtls_mpi_uint *result = NULL;
121
122 TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &upper_bound, &limbs,
123 bound_bytes ) );
Gilles Peskine8781dd02022-12-06 23:05:06 +0100124 ASSERT_ALLOC( lower_bound, limbs );
Gilles Peskinede09ddd2022-12-06 13:20:55 +0100125 lower_bound[0] = min;
Gilles Peskine8781dd02022-12-06 23:05:06 +0100126 ASSERT_ALLOC( result, limbs );
Gilles Peskinede09ddd2022-12-06 13:20:55 +0100127
128 TEST_EQUAL( expected_ret,
129 mbedtls_mpi_core_random( result, min, upper_bound, limbs,
130 mbedtls_test_rnd_pseudo_rand, &rnd ) );
131
132 if( expected_ret == 0 )
133 {
134 TEST_EQUAL( 0, mbedtls_mpi_core_lt_ct( result, lower_bound, limbs ) );
135 TEST_EQUAL( 1, mbedtls_mpi_core_lt_ct( result, upper_bound, limbs ) );
136 }
137
138exit:
139 mbedtls_free( lower_bound );
140 mbedtls_free( upper_bound );
141 mbedtls_free( result );
142}
143/* END_CASE */
144
145/* BEGIN_CASE */
Gilles Peskine8c32b242022-12-07 23:01:44 +0100146void mpi_legacy_random_values( int min, char *max_hex )
Gilles Peskinede09ddd2022-12-06 13:20:55 +0100147{
148 /* Same RNG as in mpi_core_random_basic */
Gilles Peskineacdefdd2022-12-15 15:10:36 +0100149 mbedtls_test_rnd_pseudo_info rnd_core = rnd_pseudo_seed;
Gilles Peskinede09ddd2022-12-06 13:20:55 +0100150 mbedtls_test_rnd_pseudo_info rnd_legacy;
151 memcpy( &rnd_legacy, &rnd_core, sizeof( rnd_core ) );
152 mbedtls_mpi max_legacy;
153 mbedtls_mpi_init( &max_legacy );
154 mbedtls_mpi_uint *R_core = NULL;
155 mbedtls_mpi R_legacy;
156 mbedtls_mpi_init( &R_legacy );
157
158 TEST_EQUAL( 0, mbedtls_test_read_mpi( &max_legacy, max_hex ) );
159 size_t limbs = max_legacy.n;
Gilles Peskine8781dd02022-12-06 23:05:06 +0100160 ASSERT_ALLOC( R_core, limbs );
Gilles Peskinede09ddd2022-12-06 13:20:55 +0100161
162 /* Call the legacy function and the core function with the same random
163 * stream. */
164 int core_ret = mbedtls_mpi_core_random( R_core, min, max_legacy.p, limbs,
165 mbedtls_test_rnd_pseudo_rand,
166 &rnd_core );
167 int legacy_ret = mbedtls_mpi_random( &R_legacy, min, &max_legacy,
168 mbedtls_test_rnd_pseudo_rand,
169 &rnd_legacy );
170
171 /* They must return the same status, and, on success, output the
172 * same number, with the same limb count. */
173 TEST_EQUAL( core_ret, legacy_ret );
174 if( core_ret == 0 )
175 {
176 ASSERT_COMPARE( R_core, limbs * ciL,
177 R_legacy.p, R_legacy.n * ciL );
178 }
179
180 /* Also check that they have consumed the RNG in the same way. */
181 /* This may theoretically fail on rare platforms with padding in
182 * the structure! If this is a problem in practice, change to a
183 * field-by-field comparison. */
184 ASSERT_COMPARE( &rnd_core, sizeof( rnd_core ),
185 &rnd_legacy, sizeof( rnd_legacy ) );
186
187exit:
188 mbedtls_mpi_free( &max_legacy );
189 mbedtls_free( R_core );
190 mbedtls_mpi_free( &R_legacy );
191}
192/* END_CASE */
193
194/* BEGIN_CASE */
Gilles Peskinea57cf982022-12-06 22:54:09 +0100195void mpi_mod_random_values( int min, char *max_hex )
196{
197 /* Same RNG as in mpi_core_random_basic */
198 mbedtls_test_rnd_pseudo_info rnd_core = {
199 {'T', 'h', 'i', 's', ' ', 'i', ',', 'a',
200 's', 'e', 'e', 'd', '!', 0},
201 0, 0};
202 mbedtls_test_rnd_pseudo_info rnd_mod_raw;
203 memcpy( &rnd_mod_raw, &rnd_core, sizeof( rnd_core ) );
Gilles Peskineb1eea022022-12-07 22:59:27 +0100204 mbedtls_test_rnd_pseudo_info rnd_mod;
205 memcpy( &rnd_mod, &rnd_core, sizeof( rnd_core ) );
Gilles Peskinea57cf982022-12-06 22:54:09 +0100206 mbedtls_mpi_uint *R_core = NULL;
207 mbedtls_mpi_uint *R_mod_raw = NULL;
Gilles Peskineb1eea022022-12-07 22:59:27 +0100208 mbedtls_mpi_uint *R_mod_digits = NULL;
209 mbedtls_mpi_mod_residue R_mod;
Gilles Peskinea57cf982022-12-06 22:54:09 +0100210 mbedtls_mpi_mod_modulus N;
211 mbedtls_mpi_mod_modulus_init( &N );
212
213 TEST_EQUAL( mbedtls_test_read_mpi_modulus( &N, max_hex,
214 MBEDTLS_MPI_MOD_REP_MONTGOMERY ),
215 0 );
216 ASSERT_ALLOC( R_core, N.limbs );
217 ASSERT_ALLOC( R_mod_raw, N.limbs );
Gilles Peskineb1eea022022-12-07 22:59:27 +0100218 ASSERT_ALLOC( R_mod_digits, N.limbs );
219 TEST_EQUAL( mbedtls_mpi_mod_residue_setup( &R_mod, &N,
220 R_mod_digits, N.limbs ),
221 0 );
Gilles Peskinea57cf982022-12-06 22:54:09 +0100222
223 /* Call the core and mod random() functions with the same random stream. */
224 int core_ret = mbedtls_mpi_core_random( R_core,
225 min, N.p, N.limbs,
226 mbedtls_test_rnd_pseudo_rand,
227 &rnd_core );
228 int mod_raw_ret = mbedtls_mpi_mod_raw_random( R_mod_raw,
229 min, &N,
230 mbedtls_test_rnd_pseudo_rand,
231 &rnd_mod_raw );
Gilles Peskineb1eea022022-12-07 22:59:27 +0100232 int mod_ret = mbedtls_mpi_mod_random( &R_mod,
233 min, &N,
234 mbedtls_test_rnd_pseudo_rand,
235 &rnd_mod );
Gilles Peskinea57cf982022-12-06 22:54:09 +0100236
237 /* They must return the same status, and, on success, output the
238 * same number, with the same limb count. */
239 TEST_EQUAL( core_ret, mod_raw_ret );
Gilles Peskineb1eea022022-12-07 22:59:27 +0100240 TEST_EQUAL( core_ret, mod_ret );
Gilles Peskinea57cf982022-12-06 22:54:09 +0100241 if( core_ret == 0 )
242 {
243 TEST_EQUAL( mbedtls_mpi_mod_raw_from_mont_rep( R_mod_raw, &N ), 0 );
244 ASSERT_COMPARE( R_core, N.limbs * ciL,
245 R_mod_raw, N.limbs * ciL );
Gilles Peskineb1eea022022-12-07 22:59:27 +0100246 TEST_EQUAL( mbedtls_mpi_mod_raw_from_mont_rep( R_mod_digits, &N ), 0 );
247 ASSERT_COMPARE( R_core, N.limbs * ciL,
248 R_mod_digits, N.limbs * ciL );
Gilles Peskinea57cf982022-12-06 22:54:09 +0100249 }
250
251 /* Also check that they have consumed the RNG in the same way. */
252 /* This may theoretically fail on rare platforms with padding in
253 * the structure! If this is a problem in practice, change to a
254 * field-by-field comparison. */
255 ASSERT_COMPARE( &rnd_core, sizeof( rnd_core ),
256 &rnd_mod_raw, sizeof( rnd_mod_raw ) );
Gilles Peskineb1eea022022-12-07 22:59:27 +0100257 ASSERT_COMPARE( &rnd_core, sizeof( rnd_core ),
258 &rnd_mod, sizeof( rnd_mod ) );
Gilles Peskinea57cf982022-12-06 22:54:09 +0100259
260exit:
Gilles Peskined008abb2022-12-08 19:50:29 +0100261 mbedtls_test_mpi_mod_modulus_free_with_limbs( &N );
Gilles Peskinea57cf982022-12-06 22:54:09 +0100262 mbedtls_free( R_core );
263 mbedtls_free( R_mod_raw );
Gilles Peskineb1eea022022-12-07 22:59:27 +0100264 mbedtls_free( R_mod_digits );
Gilles Peskinea57cf982022-12-06 22:54:09 +0100265}
266/* END_CASE */
267
268/* BEGIN_CASE */
Gilles Peskinede09ddd2022-12-06 13:20:55 +0100269void mpi_random_many( int min, char *bound_hex, int iterations )
270{
271 /* Generate numbers in the range 1..bound-1. Do it iterations times.
272 * This function assumes that the value of bound is at least 2 and
273 * that iterations is large enough that a one-in-2^iterations chance
274 * effectively never occurs.
275 */
276
277 data_t bound_bytes = {NULL, 0};
278 mbedtls_mpi_uint *upper_bound = NULL;
279 size_t limbs;
280 size_t n_bits;
281 mbedtls_mpi_uint *result = NULL;
282 size_t b;
283 /* If upper_bound is small, stats[b] is the number of times the value b
284 * has been generated. Otherwise stats[b] is the number of times a
285 * value with bit b set has been generated. */
286 size_t *stats = NULL;
287 size_t stats_len;
288 int full_stats;
289 size_t i;
290
291 TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &upper_bound, &limbs,
292 bound_hex ) );
Gilles Peskine8781dd02022-12-06 23:05:06 +0100293 ASSERT_ALLOC( result, limbs );
Gilles Peskinede09ddd2022-12-06 13:20:55 +0100294
295 n_bits = mbedtls_mpi_core_bitlen( upper_bound, limbs );
296 /* Consider a bound "small" if it's less than 2^5. This value is chosen
297 * to be small enough that the probability of missing one value is
298 * negligible given the number of iterations. It must be less than
299 * 256 because some of the code below assumes that "small" values
300 * fit in a byte. */
301 if( n_bits <= 5 )
302 {
303 full_stats = 1;
304 stats_len = (uint8_t) upper_bound[0];
305 }
306 else
307 {
308 full_stats = 0;
309 stats_len = n_bits;
310 }
311 ASSERT_ALLOC( stats, stats_len );
312
313 for( i = 0; i < (size_t) iterations; i++ )
314 {
315 mbedtls_test_set_step( i );
316 TEST_EQUAL( 0, mbedtls_mpi_core_random( result,
317 min, upper_bound, limbs,
318 mbedtls_test_rnd_std_rand, NULL ) );
319
320 /* Temporarily use a legacy MPI for analysis, because the
321 * necessary auxiliary functions don't exist yet in core. */
322 mbedtls_mpi B = {1, limbs, upper_bound};
323 mbedtls_mpi R = {1, limbs, result};
324
325 TEST_ASSERT( mbedtls_mpi_cmp_mpi( &R, &B ) < 0 );
326 TEST_ASSERT( mbedtls_mpi_cmp_int( &R, min ) >= 0 );
327 if( full_stats )
328 {
329 uint8_t value;
330 TEST_EQUAL( 0, mbedtls_mpi_write_binary( &R, &value, 1 ) );
331 TEST_ASSERT( value < stats_len );
332 ++stats[value];
333 }
334 else
335 {
336 for( b = 0; b < n_bits; b++ )
337 stats[b] += mbedtls_mpi_get_bit( &R, b );
338 }
339 }
340
341 if( full_stats )
342 {
343 for( b = min; b < stats_len; b++ )
344 {
345 mbedtls_test_set_step( 1000000 + b );
346 /* Assert that each value has been reached at least once.
347 * This is almost guaranteed if the iteration count is large
348 * enough. This is a very crude way of checking the distribution.
349 */
350 TEST_ASSERT( stats[b] > 0 );
351 }
352 }
353 else
354 {
355 bound_bytes.len = limbs * sizeof( mbedtls_mpi_uint );
356 ASSERT_ALLOC( bound_bytes.x, bound_bytes.len );
357 mbedtls_mpi_core_write_be( upper_bound, limbs,
358 bound_bytes.x, bound_bytes.len );
359 int statistically_safe_all_the_way =
360 is_significantly_above_a_power_of_2( &bound_bytes );
361 for( b = 0; b < n_bits; b++ )
362 {
363 mbedtls_test_set_step( 1000000 + b );
364 /* Assert that each bit has been set in at least one result and
365 * clear in at least one result. Provided that iterations is not
366 * too small, it would be extremely unlikely for this not to be
367 * the case if the results are uniformly distributed.
368 *
369 * As an exception, the top bit may legitimately never be set
370 * if bound is a power of 2 or only slightly above.
371 */
372 if( statistically_safe_all_the_way || b != n_bits - 1 )
373 {
374 TEST_ASSERT( stats[b] > 0 );
375 }
376 TEST_ASSERT( stats[b] < (size_t) iterations );
377 }
378 }
379
380exit:
381 mbedtls_free( bound_bytes.x );
382 mbedtls_free( upper_bound );
383 mbedtls_free( result );
384 mbedtls_free( stats );
385}
386/* END_CASE */
387
388/* BEGIN_CASE */
389void mpi_random_sizes( int min, data_t *bound_bytes, int nlimbs, int before )
390{
391 mbedtls_mpi upper_bound;
392 mbedtls_mpi result;
393
394 mbedtls_mpi_init( &upper_bound );
395 mbedtls_mpi_init( &result );
396
397 if( before != 0 )
398 {
399 /* Set result to sign(before) * 2^(|before|-1) */
400 TEST_ASSERT( mbedtls_mpi_lset( &result, before > 0 ? 1 : -1 ) == 0 );
401 if( before < 0 )
402 before = - before;
403 TEST_ASSERT( mbedtls_mpi_shift_l( &result, before - 1 ) == 0 );
404 }
405
406 TEST_EQUAL( 0, mbedtls_mpi_grow( &result, nlimbs ) );
407 TEST_EQUAL( 0, mbedtls_mpi_read_binary( &upper_bound,
408 bound_bytes->x, bound_bytes->len ) );
409 TEST_EQUAL( 0, mbedtls_mpi_random( &result, min, &upper_bound,
410 mbedtls_test_rnd_std_rand, NULL ) );
411 TEST_ASSERT( sign_is_valid( &result ) );
412 TEST_ASSERT( mbedtls_mpi_cmp_mpi( &result, &upper_bound ) < 0 );
413 TEST_ASSERT( mbedtls_mpi_cmp_int( &result, min ) >= 0 );
414
415exit:
416 mbedtls_mpi_free( &upper_bound );
417 mbedtls_mpi_free( &result );
418}
419/* END_CASE */
420
421/* BEGIN_CASE */
Gilles Peskined878d1c2022-12-08 12:59:51 +0100422void mpi_mod_random_validation( int min, char *bound_hex,
423 int result_limbs_delta,
424 int expected_ret )
425{
426 mbedtls_mpi_uint *result_digits = NULL;
427 mbedtls_mpi_mod_modulus N;
428 mbedtls_mpi_mod_modulus_init( &N );
429
430 TEST_EQUAL( mbedtls_test_read_mpi_modulus( &N, bound_hex,
431 MBEDTLS_MPI_MOD_REP_MONTGOMERY ),
432 0 );
433 size_t result_limbs = N.limbs + result_limbs_delta;
434 ASSERT_ALLOC( result_digits, result_limbs );
435 /* Build a reside that might not match the modulus, to test that
436 * the library function rejects that as expected. */
437 mbedtls_mpi_mod_residue result = {result_digits, result_limbs};
438
439 TEST_EQUAL( mbedtls_mpi_mod_random( &result, min, &N,
440 mbedtls_test_rnd_std_rand, NULL ),
441 expected_ret );
442 if( expected_ret == 0 )
443 {
444 /* Success should only be expected when the result has the same
445 * size as the modulus, otherwise it's a mistake in the test data. */
446 TEST_EQUAL( result_limbs, N.limbs );
447 /* Sanity check: check that the result is in range */
448 TEST_EQUAL( mbedtls_mpi_mod_raw_from_mont_rep( result_digits, &N ), 0 );
449 TEST_EQUAL( mbedtls_mpi_core_lt_ct( result_digits, N.p, N.limbs ),
450 1 );
451 /* Check result >= min (changes result) */
452 TEST_EQUAL( mbedtls_mpi_core_sub_int( result_digits, result_digits, min,
453 result_limbs ),
454 0 );
455 }
456
457 /* When the result has the right number of limbs, also test mod_raw
458 * (for which this is an unchecked precondition). */
459 if( result_limbs_delta == 0 )
460 {
461 TEST_EQUAL( mbedtls_mpi_mod_raw_random( result_digits, min, &N,
462 mbedtls_test_rnd_std_rand, NULL ),
463 expected_ret );
464 if( expected_ret == 0 )
465 {
466 TEST_EQUAL( mbedtls_mpi_mod_raw_from_mont_rep( result_digits, &N ), 0 );
467 TEST_EQUAL( mbedtls_mpi_core_lt_ct( result_digits, N.p, N.limbs ),
468 1 );
469 TEST_EQUAL( mbedtls_mpi_core_sub_int( result_digits, result.p, min,
470 result_limbs ),
471 0 );
472 }
473 }
474
475exit:
476 mbedtls_test_mpi_mod_modulus_free_with_limbs( &N );
477 mbedtls_free( result_digits );
478}
479/* END_CASE */
480
481/* BEGIN_CASE */
Gilles Peskinede09ddd2022-12-06 13:20:55 +0100482void mpi_random_fail( int min, data_t *bound_bytes, int expected_ret )
483{
484 mbedtls_mpi upper_bound;
485 mbedtls_mpi result;
486 int actual_ret;
487
488 mbedtls_mpi_init( &upper_bound );
489 mbedtls_mpi_init( &result );
490
491 TEST_EQUAL( 0, mbedtls_mpi_read_binary( &upper_bound,
492 bound_bytes->x, bound_bytes->len ) );
493 actual_ret = mbedtls_mpi_random( &result, min, &upper_bound,
494 mbedtls_test_rnd_std_rand, NULL );
495 TEST_EQUAL( expected_ret, actual_ret );
496
497exit:
498 mbedtls_mpi_free( &upper_bound );
499 mbedtls_mpi_free( &result );
500}
501/* END_CASE */