blob: 470914890027b169022aa5a9fbf1019dcd5f32e0 [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 Peskinee1d83262022-12-20 19:31:09 +0100195void mpi_mod_random_values( int min, char *max_hex, int rep )
Gilles Peskinea57cf982022-12-06 22:54:09 +0100196{
197 /* Same RNG as in mpi_core_random_basic */
Gilles Peskined1aa75d2022-12-20 22:01:27 +0100198 mbedtls_test_rnd_pseudo_info rnd_core = rnd_pseudo_seed;
Gilles Peskinea57cf982022-12-06 22:54:09 +0100199 mbedtls_test_rnd_pseudo_info rnd_mod_raw;
200 memcpy( &rnd_mod_raw, &rnd_core, sizeof( rnd_core ) );
Gilles Peskineb1eea022022-12-07 22:59:27 +0100201 mbedtls_test_rnd_pseudo_info rnd_mod;
202 memcpy( &rnd_mod, &rnd_core, sizeof( rnd_core ) );
Gilles Peskinea57cf982022-12-06 22:54:09 +0100203 mbedtls_mpi_uint *R_core = NULL;
204 mbedtls_mpi_uint *R_mod_raw = NULL;
Gilles Peskineb1eea022022-12-07 22:59:27 +0100205 mbedtls_mpi_uint *R_mod_digits = NULL;
206 mbedtls_mpi_mod_residue R_mod;
Gilles Peskinea57cf982022-12-06 22:54:09 +0100207 mbedtls_mpi_mod_modulus N;
208 mbedtls_mpi_mod_modulus_init( &N );
209
Gilles Peskinee1d83262022-12-20 19:31:09 +0100210 TEST_EQUAL( mbedtls_test_read_mpi_modulus( &N, max_hex, rep ), 0 );
Gilles Peskinea57cf982022-12-06 22:54:09 +0100211 ASSERT_ALLOC( R_core, N.limbs );
212 ASSERT_ALLOC( R_mod_raw, N.limbs );
Gilles Peskineb1eea022022-12-07 22:59:27 +0100213 ASSERT_ALLOC( R_mod_digits, N.limbs );
214 TEST_EQUAL( mbedtls_mpi_mod_residue_setup( &R_mod, &N,
215 R_mod_digits, N.limbs ),
216 0 );
Gilles Peskinea57cf982022-12-06 22:54:09 +0100217
218 /* Call the core and mod random() functions with the same random stream. */
219 int core_ret = mbedtls_mpi_core_random( R_core,
220 min, N.p, N.limbs,
221 mbedtls_test_rnd_pseudo_rand,
222 &rnd_core );
223 int mod_raw_ret = mbedtls_mpi_mod_raw_random( R_mod_raw,
224 min, &N,
225 mbedtls_test_rnd_pseudo_rand,
226 &rnd_mod_raw );
Gilles Peskineb1eea022022-12-07 22:59:27 +0100227 int mod_ret = mbedtls_mpi_mod_random( &R_mod,
228 min, &N,
229 mbedtls_test_rnd_pseudo_rand,
230 &rnd_mod );
Gilles Peskinea57cf982022-12-06 22:54:09 +0100231
232 /* They must return the same status, and, on success, output the
233 * same number, with the same limb count. */
234 TEST_EQUAL( core_ret, mod_raw_ret );
Gilles Peskineb1eea022022-12-07 22:59:27 +0100235 TEST_EQUAL( core_ret, mod_ret );
Gilles Peskinea57cf982022-12-06 22:54:09 +0100236 if( core_ret == 0 )
237 {
Gilles Peskinee1d83262022-12-20 19:31:09 +0100238 TEST_EQUAL( mbedtls_mpi_mod_raw_modulus_to_canonical_rep( R_mod_raw, &N ),
239 0 );
Gilles Peskinea57cf982022-12-06 22:54:09 +0100240 ASSERT_COMPARE( R_core, N.limbs * ciL,
241 R_mod_raw, N.limbs * ciL );
Gilles Peskinee1d83262022-12-20 19:31:09 +0100242 TEST_EQUAL( mbedtls_mpi_mod_raw_modulus_to_canonical_rep( R_mod_digits, &N ),
243 0 );
Gilles Peskineb1eea022022-12-07 22:59:27 +0100244 ASSERT_COMPARE( R_core, N.limbs * ciL,
245 R_mod_digits, N.limbs * ciL );
Gilles Peskinea57cf982022-12-06 22:54:09 +0100246 }
247
248 /* Also check that they have consumed the RNG in the same way. */
249 /* This may theoretically fail on rare platforms with padding in
250 * the structure! If this is a problem in practice, change to a
251 * field-by-field comparison. */
252 ASSERT_COMPARE( &rnd_core, sizeof( rnd_core ),
253 &rnd_mod_raw, sizeof( rnd_mod_raw ) );
Gilles Peskineb1eea022022-12-07 22:59:27 +0100254 ASSERT_COMPARE( &rnd_core, sizeof( rnd_core ),
255 &rnd_mod, sizeof( rnd_mod ) );
Gilles Peskinea57cf982022-12-06 22:54:09 +0100256
257exit:
Gilles Peskined008abb2022-12-08 19:50:29 +0100258 mbedtls_test_mpi_mod_modulus_free_with_limbs( &N );
Gilles Peskinea57cf982022-12-06 22:54:09 +0100259 mbedtls_free( R_core );
260 mbedtls_free( R_mod_raw );
Gilles Peskineb1eea022022-12-07 22:59:27 +0100261 mbedtls_free( R_mod_digits );
Gilles Peskinea57cf982022-12-06 22:54:09 +0100262}
263/* END_CASE */
264
265/* BEGIN_CASE */
Gilles Peskinede09ddd2022-12-06 13:20:55 +0100266void mpi_random_many( int min, char *bound_hex, int iterations )
267{
268 /* Generate numbers in the range 1..bound-1. Do it iterations times.
269 * This function assumes that the value of bound is at least 2 and
270 * that iterations is large enough that a one-in-2^iterations chance
271 * effectively never occurs.
272 */
273
274 data_t bound_bytes = {NULL, 0};
275 mbedtls_mpi_uint *upper_bound = NULL;
276 size_t limbs;
277 size_t n_bits;
278 mbedtls_mpi_uint *result = NULL;
279 size_t b;
280 /* If upper_bound is small, stats[b] is the number of times the value b
281 * has been generated. Otherwise stats[b] is the number of times a
282 * value with bit b set has been generated. */
283 size_t *stats = NULL;
284 size_t stats_len;
285 int full_stats;
286 size_t i;
287
288 TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &upper_bound, &limbs,
289 bound_hex ) );
Gilles Peskine8781dd02022-12-06 23:05:06 +0100290 ASSERT_ALLOC( result, limbs );
Gilles Peskinede09ddd2022-12-06 13:20:55 +0100291
292 n_bits = mbedtls_mpi_core_bitlen( upper_bound, limbs );
293 /* Consider a bound "small" if it's less than 2^5. This value is chosen
294 * to be small enough that the probability of missing one value is
295 * negligible given the number of iterations. It must be less than
296 * 256 because some of the code below assumes that "small" values
297 * fit in a byte. */
298 if( n_bits <= 5 )
299 {
300 full_stats = 1;
301 stats_len = (uint8_t) upper_bound[0];
302 }
303 else
304 {
305 full_stats = 0;
306 stats_len = n_bits;
307 }
308 ASSERT_ALLOC( stats, stats_len );
309
310 for( i = 0; i < (size_t) iterations; i++ )
311 {
312 mbedtls_test_set_step( i );
313 TEST_EQUAL( 0, mbedtls_mpi_core_random( result,
314 min, upper_bound, limbs,
315 mbedtls_test_rnd_std_rand, NULL ) );
316
317 /* Temporarily use a legacy MPI for analysis, because the
318 * necessary auxiliary functions don't exist yet in core. */
319 mbedtls_mpi B = {1, limbs, upper_bound};
320 mbedtls_mpi R = {1, limbs, result};
321
322 TEST_ASSERT( mbedtls_mpi_cmp_mpi( &R, &B ) < 0 );
323 TEST_ASSERT( mbedtls_mpi_cmp_int( &R, min ) >= 0 );
324 if( full_stats )
325 {
326 uint8_t value;
327 TEST_EQUAL( 0, mbedtls_mpi_write_binary( &R, &value, 1 ) );
328 TEST_ASSERT( value < stats_len );
329 ++stats[value];
330 }
331 else
332 {
333 for( b = 0; b < n_bits; b++ )
334 stats[b] += mbedtls_mpi_get_bit( &R, b );
335 }
336 }
337
338 if( full_stats )
339 {
340 for( b = min; b < stats_len; b++ )
341 {
342 mbedtls_test_set_step( 1000000 + b );
343 /* Assert that each value has been reached at least once.
344 * This is almost guaranteed if the iteration count is large
345 * enough. This is a very crude way of checking the distribution.
346 */
347 TEST_ASSERT( stats[b] > 0 );
348 }
349 }
350 else
351 {
352 bound_bytes.len = limbs * sizeof( mbedtls_mpi_uint );
353 ASSERT_ALLOC( bound_bytes.x, bound_bytes.len );
354 mbedtls_mpi_core_write_be( upper_bound, limbs,
355 bound_bytes.x, bound_bytes.len );
356 int statistically_safe_all_the_way =
357 is_significantly_above_a_power_of_2( &bound_bytes );
358 for( b = 0; b < n_bits; b++ )
359 {
360 mbedtls_test_set_step( 1000000 + b );
361 /* Assert that each bit has been set in at least one result and
362 * clear in at least one result. Provided that iterations is not
363 * too small, it would be extremely unlikely for this not to be
364 * the case if the results are uniformly distributed.
365 *
366 * As an exception, the top bit may legitimately never be set
367 * if bound is a power of 2 or only slightly above.
368 */
369 if( statistically_safe_all_the_way || b != n_bits - 1 )
370 {
371 TEST_ASSERT( stats[b] > 0 );
372 }
373 TEST_ASSERT( stats[b] < (size_t) iterations );
374 }
375 }
376
377exit:
378 mbedtls_free( bound_bytes.x );
379 mbedtls_free( upper_bound );
380 mbedtls_free( result );
381 mbedtls_free( stats );
382}
383/* END_CASE */
384
385/* BEGIN_CASE */
386void mpi_random_sizes( int min, data_t *bound_bytes, int nlimbs, int before )
387{
388 mbedtls_mpi upper_bound;
389 mbedtls_mpi result;
390
391 mbedtls_mpi_init( &upper_bound );
392 mbedtls_mpi_init( &result );
393
394 if( before != 0 )
395 {
396 /* Set result to sign(before) * 2^(|before|-1) */
397 TEST_ASSERT( mbedtls_mpi_lset( &result, before > 0 ? 1 : -1 ) == 0 );
398 if( before < 0 )
399 before = - before;
400 TEST_ASSERT( mbedtls_mpi_shift_l( &result, before - 1 ) == 0 );
401 }
402
403 TEST_EQUAL( 0, mbedtls_mpi_grow( &result, nlimbs ) );
404 TEST_EQUAL( 0, mbedtls_mpi_read_binary( &upper_bound,
405 bound_bytes->x, bound_bytes->len ) );
406 TEST_EQUAL( 0, mbedtls_mpi_random( &result, min, &upper_bound,
407 mbedtls_test_rnd_std_rand, NULL ) );
408 TEST_ASSERT( sign_is_valid( &result ) );
409 TEST_ASSERT( mbedtls_mpi_cmp_mpi( &result, &upper_bound ) < 0 );
410 TEST_ASSERT( mbedtls_mpi_cmp_int( &result, min ) >= 0 );
411
412exit:
413 mbedtls_mpi_free( &upper_bound );
414 mbedtls_mpi_free( &result );
415}
416/* END_CASE */
417
418/* BEGIN_CASE */
Gilles Peskined878d1c2022-12-08 12:59:51 +0100419void mpi_mod_random_validation( int min, char *bound_hex,
420 int result_limbs_delta,
421 int expected_ret )
422{
423 mbedtls_mpi_uint *result_digits = NULL;
424 mbedtls_mpi_mod_modulus N;
425 mbedtls_mpi_mod_modulus_init( &N );
426
427 TEST_EQUAL( mbedtls_test_read_mpi_modulus( &N, bound_hex,
Gilles Peskinee1d83262022-12-20 19:31:09 +0100428 MBEDTLS_MPI_MOD_REP_OPT_RED ),
Gilles Peskined878d1c2022-12-08 12:59:51 +0100429 0 );
430 size_t result_limbs = N.limbs + result_limbs_delta;
431 ASSERT_ALLOC( result_digits, result_limbs );
432 /* Build a reside that might not match the modulus, to test that
433 * the library function rejects that as expected. */
434 mbedtls_mpi_mod_residue result = {result_digits, result_limbs};
435
436 TEST_EQUAL( mbedtls_mpi_mod_random( &result, min, &N,
437 mbedtls_test_rnd_std_rand, NULL ),
438 expected_ret );
439 if( expected_ret == 0 )
440 {
441 /* Success should only be expected when the result has the same
442 * size as the modulus, otherwise it's a mistake in the test data. */
443 TEST_EQUAL( result_limbs, N.limbs );
444 /* Sanity check: check that the result is in range */
Gilles Peskined878d1c2022-12-08 12:59:51 +0100445 TEST_EQUAL( mbedtls_mpi_core_lt_ct( result_digits, N.p, N.limbs ),
446 1 );
447 /* Check result >= min (changes result) */
448 TEST_EQUAL( mbedtls_mpi_core_sub_int( result_digits, result_digits, min,
449 result_limbs ),
450 0 );
451 }
452
453 /* When the result has the right number of limbs, also test mod_raw
454 * (for which this is an unchecked precondition). */
455 if( result_limbs_delta == 0 )
456 {
457 TEST_EQUAL( mbedtls_mpi_mod_raw_random( result_digits, min, &N,
458 mbedtls_test_rnd_std_rand, NULL ),
459 expected_ret );
460 if( expected_ret == 0 )
461 {
Gilles Peskined878d1c2022-12-08 12:59:51 +0100462 TEST_EQUAL( mbedtls_mpi_core_lt_ct( result_digits, N.p, N.limbs ),
463 1 );
464 TEST_EQUAL( mbedtls_mpi_core_sub_int( result_digits, result.p, min,
465 result_limbs ),
466 0 );
467 }
468 }
469
470exit:
471 mbedtls_test_mpi_mod_modulus_free_with_limbs( &N );
472 mbedtls_free( result_digits );
473}
474/* END_CASE */
475
476/* BEGIN_CASE */
Gilles Peskinede09ddd2022-12-06 13:20:55 +0100477void mpi_random_fail( int min, data_t *bound_bytes, int expected_ret )
478{
479 mbedtls_mpi upper_bound;
480 mbedtls_mpi result;
481 int actual_ret;
482
483 mbedtls_mpi_init( &upper_bound );
484 mbedtls_mpi_init( &result );
485
486 TEST_EQUAL( 0, mbedtls_mpi_read_binary( &upper_bound,
487 bound_bytes->x, bound_bytes->len ) );
488 actual_ret = mbedtls_mpi_random( &result, min, &upper_bound,
489 mbedtls_test_rnd_std_rand, NULL );
490 TEST_EQUAL( expected_ret, actual_ret );
491
492exit:
493 mbedtls_mpi_free( &upper_bound );
494 mbedtls_mpi_free( &result );
495}
496/* END_CASE */