blob: 7a66073281b78313e75871e729b67fcf111a8c29 [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"
11#include "constant_time_internal.h"
12
13/* This test suite only manipulates non-negative bignums. */
14static int sign_is_valid( const mbedtls_mpi *X )
15{
16 return( X->s == 1 );
17}
18
19/* Test whether bytes represents (in big-endian base 256) a number b that
20 * is significantly above a power of 2. That is, b must not have a long run
21 * of unset bits after the most significant bit.
22 *
23 * Let n be the bit-size of b, i.e. the integer such that 2^n <= b < 2^{n+1}.
24 * This function returns 1 if, when drawing a number between 0 and b,
25 * the probability that this number is at least 2^n is not negligible.
26 * This probability is (b - 2^n) / b and this function checks that this
27 * number is above some threshold A. The threshold value is heuristic and
28 * based on the needs of mpi_random_many().
29 */
30static int is_significantly_above_a_power_of_2( data_t *bytes )
31{
32 const uint8_t *p = bytes->x;
33 size_t len = bytes->len;
34 unsigned x;
35
36 /* Skip leading null bytes */
37 while( len > 0 && p[0] == 0 )
38 {
39 ++p;
40 --len;
41 }
42 /* 0 is not significantly above a power of 2 */
43 if( len == 0 )
44 return( 0 );
45 /* Extract the (up to) 2 most significant bytes */
46 if( len == 1 )
47 x = p[0];
48 else
49 x = ( p[0] << 8 ) | p[1];
50
51 /* Shift the most significant bit of x to position 8 and mask it out */
52 while( ( x & 0xfe00 ) != 0 )
53 x >>= 1;
54 x &= 0x00ff;
55
56 /* At this point, x = floor((b - 2^n) / 2^(n-8)). b is significantly above
57 * a power of 2 iff x is significantly above 0 compared to 2^8.
58 * Testing x >= 2^4 amounts to picking A = 1/16 in the function
59 * description above. */
60 return( x >= 0x10 );
61}
62
63/* END_HEADER */
64
65/* BEGIN_DEPENDENCIES
66 * depends_on:MBEDTLS_BIGNUM_C
67 * END_DEPENDENCIES
68 */
69
70/* BEGIN_CASE */
71void mpi_core_random_basic( int min, char *bound_bytes, int expected_ret )
72{
73 /* Same RNG as in mpi_random_values */
74 mbedtls_test_rnd_pseudo_info rnd = {
75 {'T', 'h', 'i', 's', ' ', 'i', ',', 'a',
76 's', 'e', 'e', 'd', '!', 0},
77 0, 0};
78 size_t limbs;
79 mbedtls_mpi_uint *lower_bound = NULL;
80 mbedtls_mpi_uint *upper_bound = NULL;
81 mbedtls_mpi_uint *result = NULL;
82
83 TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &upper_bound, &limbs,
84 bound_bytes ) );
85 ASSERT_ALLOC( lower_bound, limbs * ciL );
86 lower_bound[0] = min;
87 ASSERT_ALLOC( result, limbs * ciL );
88
89 TEST_EQUAL( expected_ret,
90 mbedtls_mpi_core_random( result, min, upper_bound, limbs,
91 mbedtls_test_rnd_pseudo_rand, &rnd ) );
92
93 if( expected_ret == 0 )
94 {
95 TEST_EQUAL( 0, mbedtls_mpi_core_lt_ct( result, lower_bound, limbs ) );
96 TEST_EQUAL( 1, mbedtls_mpi_core_lt_ct( result, upper_bound, limbs ) );
97 }
98
99exit:
100 mbedtls_free( lower_bound );
101 mbedtls_free( upper_bound );
102 mbedtls_free( result );
103}
104/* END_CASE */
105
106/* BEGIN_CASE */
107void mpi_random_values( int min, char *max_hex )
108{
109 /* Same RNG as in mpi_core_random_basic */
110 mbedtls_test_rnd_pseudo_info rnd_core = {
111 {'T', 'h', 'i', 's', ' ', 'i', ',', 'a',
112 's', 'e', 'e', 'd', '!', 0},
113 0, 0};
114 mbedtls_test_rnd_pseudo_info rnd_legacy;
115 memcpy( &rnd_legacy, &rnd_core, sizeof( rnd_core ) );
116 mbedtls_mpi max_legacy;
117 mbedtls_mpi_init( &max_legacy );
118 mbedtls_mpi_uint *R_core = NULL;
119 mbedtls_mpi R_legacy;
120 mbedtls_mpi_init( &R_legacy );
121
122 TEST_EQUAL( 0, mbedtls_test_read_mpi( &max_legacy, max_hex ) );
123 size_t limbs = max_legacy.n;
124 ASSERT_ALLOC( R_core, limbs * ciL );
125
126 /* Call the legacy function and the core function with the same random
127 * stream. */
128 int core_ret = mbedtls_mpi_core_random( R_core, min, max_legacy.p, limbs,
129 mbedtls_test_rnd_pseudo_rand,
130 &rnd_core );
131 int legacy_ret = mbedtls_mpi_random( &R_legacy, min, &max_legacy,
132 mbedtls_test_rnd_pseudo_rand,
133 &rnd_legacy );
134
135 /* They must return the same status, and, on success, output the
136 * same number, with the same limb count. */
137 TEST_EQUAL( core_ret, legacy_ret );
138 if( core_ret == 0 )
139 {
140 ASSERT_COMPARE( R_core, limbs * ciL,
141 R_legacy.p, R_legacy.n * ciL );
142 }
143
144 /* Also check that they have consumed the RNG in the same way. */
145 /* This may theoretically fail on rare platforms with padding in
146 * the structure! If this is a problem in practice, change to a
147 * field-by-field comparison. */
148 ASSERT_COMPARE( &rnd_core, sizeof( rnd_core ),
149 &rnd_legacy, sizeof( rnd_legacy ) );
150
151exit:
152 mbedtls_mpi_free( &max_legacy );
153 mbedtls_free( R_core );
154 mbedtls_mpi_free( &R_legacy );
155}
156/* END_CASE */
157
158/* BEGIN_CASE */
159void mpi_random_many( int min, char *bound_hex, int iterations )
160{
161 /* Generate numbers in the range 1..bound-1. Do it iterations times.
162 * This function assumes that the value of bound is at least 2 and
163 * that iterations is large enough that a one-in-2^iterations chance
164 * effectively never occurs.
165 */
166
167 data_t bound_bytes = {NULL, 0};
168 mbedtls_mpi_uint *upper_bound = NULL;
169 size_t limbs;
170 size_t n_bits;
171 mbedtls_mpi_uint *result = NULL;
172 size_t b;
173 /* If upper_bound is small, stats[b] is the number of times the value b
174 * has been generated. Otherwise stats[b] is the number of times a
175 * value with bit b set has been generated. */
176 size_t *stats = NULL;
177 size_t stats_len;
178 int full_stats;
179 size_t i;
180
181 TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &upper_bound, &limbs,
182 bound_hex ) );
183 ASSERT_ALLOC( result, limbs * ciL );
184
185 n_bits = mbedtls_mpi_core_bitlen( upper_bound, limbs );
186 /* Consider a bound "small" if it's less than 2^5. This value is chosen
187 * to be small enough that the probability of missing one value is
188 * negligible given the number of iterations. It must be less than
189 * 256 because some of the code below assumes that "small" values
190 * fit in a byte. */
191 if( n_bits <= 5 )
192 {
193 full_stats = 1;
194 stats_len = (uint8_t) upper_bound[0];
195 }
196 else
197 {
198 full_stats = 0;
199 stats_len = n_bits;
200 }
201 ASSERT_ALLOC( stats, stats_len );
202
203 for( i = 0; i < (size_t) iterations; i++ )
204 {
205 mbedtls_test_set_step( i );
206 TEST_EQUAL( 0, mbedtls_mpi_core_random( result,
207 min, upper_bound, limbs,
208 mbedtls_test_rnd_std_rand, NULL ) );
209
210 /* Temporarily use a legacy MPI for analysis, because the
211 * necessary auxiliary functions don't exist yet in core. */
212 mbedtls_mpi B = {1, limbs, upper_bound};
213 mbedtls_mpi R = {1, limbs, result};
214
215 TEST_ASSERT( mbedtls_mpi_cmp_mpi( &R, &B ) < 0 );
216 TEST_ASSERT( mbedtls_mpi_cmp_int( &R, min ) >= 0 );
217 if( full_stats )
218 {
219 uint8_t value;
220 TEST_EQUAL( 0, mbedtls_mpi_write_binary( &R, &value, 1 ) );
221 TEST_ASSERT( value < stats_len );
222 ++stats[value];
223 }
224 else
225 {
226 for( b = 0; b < n_bits; b++ )
227 stats[b] += mbedtls_mpi_get_bit( &R, b );
228 }
229 }
230
231 if( full_stats )
232 {
233 for( b = min; b < stats_len; b++ )
234 {
235 mbedtls_test_set_step( 1000000 + b );
236 /* Assert that each value has been reached at least once.
237 * This is almost guaranteed if the iteration count is large
238 * enough. This is a very crude way of checking the distribution.
239 */
240 TEST_ASSERT( stats[b] > 0 );
241 }
242 }
243 else
244 {
245 bound_bytes.len = limbs * sizeof( mbedtls_mpi_uint );
246 ASSERT_ALLOC( bound_bytes.x, bound_bytes.len );
247 mbedtls_mpi_core_write_be( upper_bound, limbs,
248 bound_bytes.x, bound_bytes.len );
249 int statistically_safe_all_the_way =
250 is_significantly_above_a_power_of_2( &bound_bytes );
251 for( b = 0; b < n_bits; b++ )
252 {
253 mbedtls_test_set_step( 1000000 + b );
254 /* Assert that each bit has been set in at least one result and
255 * clear in at least one result. Provided that iterations is not
256 * too small, it would be extremely unlikely for this not to be
257 * the case if the results are uniformly distributed.
258 *
259 * As an exception, the top bit may legitimately never be set
260 * if bound is a power of 2 or only slightly above.
261 */
262 if( statistically_safe_all_the_way || b != n_bits - 1 )
263 {
264 TEST_ASSERT( stats[b] > 0 );
265 }
266 TEST_ASSERT( stats[b] < (size_t) iterations );
267 }
268 }
269
270exit:
271 mbedtls_free( bound_bytes.x );
272 mbedtls_free( upper_bound );
273 mbedtls_free( result );
274 mbedtls_free( stats );
275}
276/* END_CASE */
277
278/* BEGIN_CASE */
279void mpi_random_sizes( int min, data_t *bound_bytes, int nlimbs, int before )
280{
281 mbedtls_mpi upper_bound;
282 mbedtls_mpi result;
283
284 mbedtls_mpi_init( &upper_bound );
285 mbedtls_mpi_init( &result );
286
287 if( before != 0 )
288 {
289 /* Set result to sign(before) * 2^(|before|-1) */
290 TEST_ASSERT( mbedtls_mpi_lset( &result, before > 0 ? 1 : -1 ) == 0 );
291 if( before < 0 )
292 before = - before;
293 TEST_ASSERT( mbedtls_mpi_shift_l( &result, before - 1 ) == 0 );
294 }
295
296 TEST_EQUAL( 0, mbedtls_mpi_grow( &result, nlimbs ) );
297 TEST_EQUAL( 0, mbedtls_mpi_read_binary( &upper_bound,
298 bound_bytes->x, bound_bytes->len ) );
299 TEST_EQUAL( 0, mbedtls_mpi_random( &result, min, &upper_bound,
300 mbedtls_test_rnd_std_rand, NULL ) );
301 TEST_ASSERT( sign_is_valid( &result ) );
302 TEST_ASSERT( mbedtls_mpi_cmp_mpi( &result, &upper_bound ) < 0 );
303 TEST_ASSERT( mbedtls_mpi_cmp_int( &result, min ) >= 0 );
304
305exit:
306 mbedtls_mpi_free( &upper_bound );
307 mbedtls_mpi_free( &result );
308}
309/* END_CASE */
310
311/* BEGIN_CASE */
312void mpi_random_fail( int min, data_t *bound_bytes, int expected_ret )
313{
314 mbedtls_mpi upper_bound;
315 mbedtls_mpi result;
316 int actual_ret;
317
318 mbedtls_mpi_init( &upper_bound );
319 mbedtls_mpi_init( &result );
320
321 TEST_EQUAL( 0, mbedtls_mpi_read_binary( &upper_bound,
322 bound_bytes->x, bound_bytes->len ) );
323 actual_ret = mbedtls_mpi_random( &result, min, &upper_bound,
324 mbedtls_test_rnd_std_rand, NULL );
325 TEST_EQUAL( expected_ret, actual_ret );
326
327exit:
328 mbedtls_mpi_free( &upper_bound );
329 mbedtls_mpi_free( &result );
330}
331/* END_CASE */