blob: 4ee26adb7fe8dd96bdb52c979de4bbd2593fc518 [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.
6 */
7
8#include "mbedtls/bignum.h"
9#include "mbedtls/entropy.h"
10#include "bignum_core.h"
Gilles Peskinea57cf982022-12-06 22:54:09 +010011#include "bignum_mod_raw.h"
Gilles Peskinede09ddd2022-12-06 13:20:55 +010012#include "constant_time_internal.h"
13
14/* This test suite only manipulates non-negative bignums. */
15static int sign_is_valid( const mbedtls_mpi *X )
16{
17 return( X->s == 1 );
18}
19
Gilles Peskineacdefdd2022-12-15 15:10:36 +010020/* A common initializer for test functions that should generate the same
21 * sequences for reproducibility and good coverage. */
22const mbedtls_test_rnd_pseudo_info rnd_pseudo_seed = {
23 /* 16-word key */
24 {'T', 'h', 'i', 's', ' ', 'i', 's', ' ',
25 'a', ' ', 's', 'e', 'e', 'd', '!', 0},
26 /* 2-word initial state, should be zero */
27 0, 0};
28
Gilles Peskinede09ddd2022-12-06 13:20:55 +010029/* Test whether bytes represents (in big-endian base 256) a number b that
30 * is significantly above a power of 2. That is, b must not have a long run
31 * of unset bits after the most significant bit.
32 *
33 * Let n be the bit-size of b, i.e. the integer such that 2^n <= b < 2^{n+1}.
34 * This function returns 1 if, when drawing a number between 0 and b,
35 * the probability that this number is at least 2^n is not negligible.
36 * This probability is (b - 2^n) / b and this function checks that this
37 * number is above some threshold A. The threshold value is heuristic and
38 * based on the needs of mpi_random_many().
39 */
40static int is_significantly_above_a_power_of_2( data_t *bytes )
41{
42 const uint8_t *p = bytes->x;
43 size_t len = bytes->len;
44 unsigned x;
45
46 /* Skip leading null bytes */
47 while( len > 0 && p[0] == 0 )
48 {
49 ++p;
50 --len;
51 }
52 /* 0 is not significantly above a power of 2 */
53 if( len == 0 )
54 return( 0 );
55 /* Extract the (up to) 2 most significant bytes */
56 if( len == 1 )
57 x = p[0];
58 else
59 x = ( p[0] << 8 ) | p[1];
60
61 /* Shift the most significant bit of x to position 8 and mask it out */
62 while( ( x & 0xfe00 ) != 0 )
63 x >>= 1;
64 x &= 0x00ff;
65
66 /* At this point, x = floor((b - 2^n) / 2^(n-8)). b is significantly above
67 * a power of 2 iff x is significantly above 0 compared to 2^8.
68 * Testing x >= 2^4 amounts to picking A = 1/16 in the function
69 * description above. */
70 return( x >= 0x10 );
71}
72
73/* END_HEADER */
74
75/* BEGIN_DEPENDENCIES
76 * depends_on:MBEDTLS_BIGNUM_C
77 * END_DEPENDENCIES
78 */
79
80/* BEGIN_CASE */
81void mpi_core_random_basic( int min, char *bound_bytes, int expected_ret )
82{
83 /* Same RNG as in mpi_random_values */
Gilles Peskineacdefdd2022-12-15 15:10:36 +010084 mbedtls_test_rnd_pseudo_info rnd = rnd_pseudo_seed;
Gilles Peskinede09ddd2022-12-06 13:20:55 +010085 size_t limbs;
86 mbedtls_mpi_uint *lower_bound = NULL;
87 mbedtls_mpi_uint *upper_bound = NULL;
88 mbedtls_mpi_uint *result = NULL;
89
90 TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &upper_bound, &limbs,
91 bound_bytes ) );
Gilles Peskine8781dd02022-12-06 23:05:06 +010092 ASSERT_ALLOC( lower_bound, limbs );
Gilles Peskinede09ddd2022-12-06 13:20:55 +010093 lower_bound[0] = min;
Gilles Peskine8781dd02022-12-06 23:05:06 +010094 ASSERT_ALLOC( result, limbs );
Gilles Peskinede09ddd2022-12-06 13:20:55 +010095
96 TEST_EQUAL( expected_ret,
97 mbedtls_mpi_core_random( result, min, upper_bound, limbs,
98 mbedtls_test_rnd_pseudo_rand, &rnd ) );
99
100 if( expected_ret == 0 )
101 {
102 TEST_EQUAL( 0, mbedtls_mpi_core_lt_ct( result, lower_bound, limbs ) );
103 TEST_EQUAL( 1, mbedtls_mpi_core_lt_ct( result, upper_bound, limbs ) );
104 }
105
106exit:
107 mbedtls_free( lower_bound );
108 mbedtls_free( upper_bound );
109 mbedtls_free( result );
110}
111/* END_CASE */
112
113/* BEGIN_CASE */
Gilles Peskine8c32b242022-12-07 23:01:44 +0100114void mpi_legacy_random_values( int min, char *max_hex )
Gilles Peskinede09ddd2022-12-06 13:20:55 +0100115{
116 /* Same RNG as in mpi_core_random_basic */
Gilles Peskineacdefdd2022-12-15 15:10:36 +0100117 mbedtls_test_rnd_pseudo_info rnd_core = rnd_pseudo_seed;
Gilles Peskinede09ddd2022-12-06 13:20:55 +0100118 mbedtls_test_rnd_pseudo_info rnd_legacy;
119 memcpy( &rnd_legacy, &rnd_core, sizeof( rnd_core ) );
120 mbedtls_mpi max_legacy;
121 mbedtls_mpi_init( &max_legacy );
122 mbedtls_mpi_uint *R_core = NULL;
123 mbedtls_mpi R_legacy;
124 mbedtls_mpi_init( &R_legacy );
125
126 TEST_EQUAL( 0, mbedtls_test_read_mpi( &max_legacy, max_hex ) );
127 size_t limbs = max_legacy.n;
Gilles Peskine8781dd02022-12-06 23:05:06 +0100128 ASSERT_ALLOC( R_core, limbs );
Gilles Peskinede09ddd2022-12-06 13:20:55 +0100129
130 /* Call the legacy function and the core function with the same random
131 * stream. */
132 int core_ret = mbedtls_mpi_core_random( R_core, min, max_legacy.p, limbs,
133 mbedtls_test_rnd_pseudo_rand,
134 &rnd_core );
135 int legacy_ret = mbedtls_mpi_random( &R_legacy, min, &max_legacy,
136 mbedtls_test_rnd_pseudo_rand,
137 &rnd_legacy );
138
139 /* They must return the same status, and, on success, output the
140 * same number, with the same limb count. */
141 TEST_EQUAL( core_ret, legacy_ret );
142 if( core_ret == 0 )
143 {
144 ASSERT_COMPARE( R_core, limbs * ciL,
145 R_legacy.p, R_legacy.n * ciL );
146 }
147
148 /* Also check that they have consumed the RNG in the same way. */
149 /* This may theoretically fail on rare platforms with padding in
150 * the structure! If this is a problem in practice, change to a
151 * field-by-field comparison. */
152 ASSERT_COMPARE( &rnd_core, sizeof( rnd_core ),
153 &rnd_legacy, sizeof( rnd_legacy ) );
154
155exit:
156 mbedtls_mpi_free( &max_legacy );
157 mbedtls_free( R_core );
158 mbedtls_mpi_free( &R_legacy );
159}
160/* END_CASE */
161
162/* BEGIN_CASE */
Gilles Peskinea57cf982022-12-06 22:54:09 +0100163void mpi_mod_random_values( int min, char *max_hex )
164{
165 /* Same RNG as in mpi_core_random_basic */
166 mbedtls_test_rnd_pseudo_info rnd_core = {
167 {'T', 'h', 'i', 's', ' ', 'i', ',', 'a',
168 's', 'e', 'e', 'd', '!', 0},
169 0, 0};
170 mbedtls_test_rnd_pseudo_info rnd_mod_raw;
171 memcpy( &rnd_mod_raw, &rnd_core, sizeof( rnd_core ) );
Gilles Peskineb1eea022022-12-07 22:59:27 +0100172 mbedtls_test_rnd_pseudo_info rnd_mod;
173 memcpy( &rnd_mod, &rnd_core, sizeof( rnd_core ) );
Gilles Peskinea57cf982022-12-06 22:54:09 +0100174 mbedtls_mpi_uint *R_core = NULL;
175 mbedtls_mpi_uint *R_mod_raw = NULL;
Gilles Peskineb1eea022022-12-07 22:59:27 +0100176 mbedtls_mpi_uint *R_mod_digits = NULL;
177 mbedtls_mpi_mod_residue R_mod;
Gilles Peskinea57cf982022-12-06 22:54:09 +0100178 mbedtls_mpi_mod_modulus N;
179 mbedtls_mpi_mod_modulus_init( &N );
180
181 TEST_EQUAL( mbedtls_test_read_mpi_modulus( &N, max_hex,
182 MBEDTLS_MPI_MOD_REP_MONTGOMERY ),
183 0 );
184 ASSERT_ALLOC( R_core, N.limbs );
185 ASSERT_ALLOC( R_mod_raw, N.limbs );
Gilles Peskineb1eea022022-12-07 22:59:27 +0100186 ASSERT_ALLOC( R_mod_digits, N.limbs );
187 TEST_EQUAL( mbedtls_mpi_mod_residue_setup( &R_mod, &N,
188 R_mod_digits, N.limbs ),
189 0 );
Gilles Peskinea57cf982022-12-06 22:54:09 +0100190
191 /* Call the core and mod random() functions with the same random stream. */
192 int core_ret = mbedtls_mpi_core_random( R_core,
193 min, N.p, N.limbs,
194 mbedtls_test_rnd_pseudo_rand,
195 &rnd_core );
196 int mod_raw_ret = mbedtls_mpi_mod_raw_random( R_mod_raw,
197 min, &N,
198 mbedtls_test_rnd_pseudo_rand,
199 &rnd_mod_raw );
Gilles Peskineb1eea022022-12-07 22:59:27 +0100200 int mod_ret = mbedtls_mpi_mod_random( &R_mod,
201 min, &N,
202 mbedtls_test_rnd_pseudo_rand,
203 &rnd_mod );
Gilles Peskinea57cf982022-12-06 22:54:09 +0100204
205 /* They must return the same status, and, on success, output the
206 * same number, with the same limb count. */
207 TEST_EQUAL( core_ret, mod_raw_ret );
Gilles Peskineb1eea022022-12-07 22:59:27 +0100208 TEST_EQUAL( core_ret, mod_ret );
Gilles Peskinea57cf982022-12-06 22:54:09 +0100209 if( core_ret == 0 )
210 {
211 TEST_EQUAL( mbedtls_mpi_mod_raw_from_mont_rep( R_mod_raw, &N ), 0 );
212 ASSERT_COMPARE( R_core, N.limbs * ciL,
213 R_mod_raw, N.limbs * ciL );
Gilles Peskineb1eea022022-12-07 22:59:27 +0100214 TEST_EQUAL( mbedtls_mpi_mod_raw_from_mont_rep( R_mod_digits, &N ), 0 );
215 ASSERT_COMPARE( R_core, N.limbs * ciL,
216 R_mod_digits, N.limbs * ciL );
Gilles Peskinea57cf982022-12-06 22:54:09 +0100217 }
218
219 /* Also check that they have consumed the RNG in the same way. */
220 /* This may theoretically fail on rare platforms with padding in
221 * the structure! If this is a problem in practice, change to a
222 * field-by-field comparison. */
223 ASSERT_COMPARE( &rnd_core, sizeof( rnd_core ),
224 &rnd_mod_raw, sizeof( rnd_mod_raw ) );
Gilles Peskineb1eea022022-12-07 22:59:27 +0100225 ASSERT_COMPARE( &rnd_core, sizeof( rnd_core ),
226 &rnd_mod, sizeof( rnd_mod ) );
Gilles Peskinea57cf982022-12-06 22:54:09 +0100227
228exit:
Gilles Peskined008abb2022-12-08 19:50:29 +0100229 mbedtls_test_mpi_mod_modulus_free_with_limbs( &N );
Gilles Peskinea57cf982022-12-06 22:54:09 +0100230 mbedtls_free( R_core );
231 mbedtls_free( R_mod_raw );
Gilles Peskineb1eea022022-12-07 22:59:27 +0100232 mbedtls_free( R_mod_digits );
Gilles Peskinea57cf982022-12-06 22:54:09 +0100233}
234/* END_CASE */
235
236/* BEGIN_CASE */
Gilles Peskinede09ddd2022-12-06 13:20:55 +0100237void mpi_random_many( int min, char *bound_hex, int iterations )
238{
239 /* Generate numbers in the range 1..bound-1. Do it iterations times.
240 * This function assumes that the value of bound is at least 2 and
241 * that iterations is large enough that a one-in-2^iterations chance
242 * effectively never occurs.
243 */
244
245 data_t bound_bytes = {NULL, 0};
246 mbedtls_mpi_uint *upper_bound = NULL;
247 size_t limbs;
248 size_t n_bits;
249 mbedtls_mpi_uint *result = NULL;
250 size_t b;
251 /* If upper_bound is small, stats[b] is the number of times the value b
252 * has been generated. Otherwise stats[b] is the number of times a
253 * value with bit b set has been generated. */
254 size_t *stats = NULL;
255 size_t stats_len;
256 int full_stats;
257 size_t i;
258
259 TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &upper_bound, &limbs,
260 bound_hex ) );
Gilles Peskine8781dd02022-12-06 23:05:06 +0100261 ASSERT_ALLOC( result, limbs );
Gilles Peskinede09ddd2022-12-06 13:20:55 +0100262
263 n_bits = mbedtls_mpi_core_bitlen( upper_bound, limbs );
264 /* Consider a bound "small" if it's less than 2^5. This value is chosen
265 * to be small enough that the probability of missing one value is
266 * negligible given the number of iterations. It must be less than
267 * 256 because some of the code below assumes that "small" values
268 * fit in a byte. */
269 if( n_bits <= 5 )
270 {
271 full_stats = 1;
272 stats_len = (uint8_t) upper_bound[0];
273 }
274 else
275 {
276 full_stats = 0;
277 stats_len = n_bits;
278 }
279 ASSERT_ALLOC( stats, stats_len );
280
281 for( i = 0; i < (size_t) iterations; i++ )
282 {
283 mbedtls_test_set_step( i );
284 TEST_EQUAL( 0, mbedtls_mpi_core_random( result,
285 min, upper_bound, limbs,
286 mbedtls_test_rnd_std_rand, NULL ) );
287
288 /* Temporarily use a legacy MPI for analysis, because the
289 * necessary auxiliary functions don't exist yet in core. */
290 mbedtls_mpi B = {1, limbs, upper_bound};
291 mbedtls_mpi R = {1, limbs, result};
292
293 TEST_ASSERT( mbedtls_mpi_cmp_mpi( &R, &B ) < 0 );
294 TEST_ASSERT( mbedtls_mpi_cmp_int( &R, min ) >= 0 );
295 if( full_stats )
296 {
297 uint8_t value;
298 TEST_EQUAL( 0, mbedtls_mpi_write_binary( &R, &value, 1 ) );
299 TEST_ASSERT( value < stats_len );
300 ++stats[value];
301 }
302 else
303 {
304 for( b = 0; b < n_bits; b++ )
305 stats[b] += mbedtls_mpi_get_bit( &R, b );
306 }
307 }
308
309 if( full_stats )
310 {
311 for( b = min; b < stats_len; b++ )
312 {
313 mbedtls_test_set_step( 1000000 + b );
314 /* Assert that each value has been reached at least once.
315 * This is almost guaranteed if the iteration count is large
316 * enough. This is a very crude way of checking the distribution.
317 */
318 TEST_ASSERT( stats[b] > 0 );
319 }
320 }
321 else
322 {
323 bound_bytes.len = limbs * sizeof( mbedtls_mpi_uint );
324 ASSERT_ALLOC( bound_bytes.x, bound_bytes.len );
325 mbedtls_mpi_core_write_be( upper_bound, limbs,
326 bound_bytes.x, bound_bytes.len );
327 int statistically_safe_all_the_way =
328 is_significantly_above_a_power_of_2( &bound_bytes );
329 for( b = 0; b < n_bits; b++ )
330 {
331 mbedtls_test_set_step( 1000000 + b );
332 /* Assert that each bit has been set in at least one result and
333 * clear in at least one result. Provided that iterations is not
334 * too small, it would be extremely unlikely for this not to be
335 * the case if the results are uniformly distributed.
336 *
337 * As an exception, the top bit may legitimately never be set
338 * if bound is a power of 2 or only slightly above.
339 */
340 if( statistically_safe_all_the_way || b != n_bits - 1 )
341 {
342 TEST_ASSERT( stats[b] > 0 );
343 }
344 TEST_ASSERT( stats[b] < (size_t) iterations );
345 }
346 }
347
348exit:
349 mbedtls_free( bound_bytes.x );
350 mbedtls_free( upper_bound );
351 mbedtls_free( result );
352 mbedtls_free( stats );
353}
354/* END_CASE */
355
356/* BEGIN_CASE */
357void mpi_random_sizes( int min, data_t *bound_bytes, int nlimbs, int before )
358{
359 mbedtls_mpi upper_bound;
360 mbedtls_mpi result;
361
362 mbedtls_mpi_init( &upper_bound );
363 mbedtls_mpi_init( &result );
364
365 if( before != 0 )
366 {
367 /* Set result to sign(before) * 2^(|before|-1) */
368 TEST_ASSERT( mbedtls_mpi_lset( &result, before > 0 ? 1 : -1 ) == 0 );
369 if( before < 0 )
370 before = - before;
371 TEST_ASSERT( mbedtls_mpi_shift_l( &result, before - 1 ) == 0 );
372 }
373
374 TEST_EQUAL( 0, mbedtls_mpi_grow( &result, nlimbs ) );
375 TEST_EQUAL( 0, mbedtls_mpi_read_binary( &upper_bound,
376 bound_bytes->x, bound_bytes->len ) );
377 TEST_EQUAL( 0, mbedtls_mpi_random( &result, min, &upper_bound,
378 mbedtls_test_rnd_std_rand, NULL ) );
379 TEST_ASSERT( sign_is_valid( &result ) );
380 TEST_ASSERT( mbedtls_mpi_cmp_mpi( &result, &upper_bound ) < 0 );
381 TEST_ASSERT( mbedtls_mpi_cmp_int( &result, min ) >= 0 );
382
383exit:
384 mbedtls_mpi_free( &upper_bound );
385 mbedtls_mpi_free( &result );
386}
387/* END_CASE */
388
389/* BEGIN_CASE */
390void mpi_random_fail( int min, data_t *bound_bytes, int expected_ret )
391{
392 mbedtls_mpi upper_bound;
393 mbedtls_mpi result;
394 int actual_ret;
395
396 mbedtls_mpi_init( &upper_bound );
397 mbedtls_mpi_init( &result );
398
399 TEST_EQUAL( 0, mbedtls_mpi_read_binary( &upper_bound,
400 bound_bytes->x, bound_bytes->len ) );
401 actual_ret = mbedtls_mpi_random( &result, min, &upper_bound,
402 mbedtls_test_rnd_std_rand, NULL );
403 TEST_EQUAL( expected_ret, actual_ret );
404
405exit:
406 mbedtls_mpi_free( &upper_bound );
407 mbedtls_mpi_free( &result );
408}
409/* END_CASE */