test_ssp_rng.c (8071B)
1 /* Copyright (C) 2015-2025 |Méso|Star> (contact@meso-star.com) 2 * 3 * This program is free software: you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License as published by 5 * the Free Software Foundation, either version 3 of the License, or 6 * (at your option) any later version. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. */ 15 16 #include "ssp.h" 17 #include "test_ssp_utils.h" 18 19 #include <rsys/clock_time.h> 20 21 #include <string.h> 22 23 #define NRAND 1024 24 25 static void /* Really basic test */ 26 test_rng(const enum ssp_rng_type type) 27 { 28 FILE* stream; 29 enum ssp_rng_type type2; 30 struct ssp_rng* rng = NULL; 31 struct ssp_rng* rng1 = NULL; 32 struct ssp_rng* rng2 = NULL; 33 struct mem_allocator allocator; 34 struct time t0, t1; 35 uint64_t datai0[NRAND]; 36 uint64_t datai1[NRAND]; 37 double datad[NRAND]; 38 float dataf[NRAND]; 39 size_t len = 0; 40 char buf[512]; 41 char* cstr = NULL; 42 int i, j; 43 res_T r; 44 const char can_set = (type != SSP_RNG_RANDOM_DEVICE); 45 const char can_rw = (type != SSP_RNG_RANDOM_DEVICE); 46 const char can_have_entropy = (type == SSP_RNG_RANDOM_DEVICE); 47 const char can_discard = (type != SSP_RNG_RANDOM_DEVICE); 48 49 mem_init_proxy_allocator(&allocator, &mem_default_allocator); 50 51 CHK(ssp_rng_create(NULL, -1, NULL) == RES_BAD_ARG); 52 CHK(ssp_rng_create(&allocator, -1, NULL) == RES_BAD_ARG); 53 CHK(ssp_rng_create(NULL, type, NULL) == RES_BAD_ARG); 54 CHK(ssp_rng_create(&allocator, type, NULL) == RES_BAD_ARG); 55 CHK(ssp_rng_create(NULL, -1, &rng) == RES_BAD_ARG); 56 CHK(ssp_rng_create(&allocator, -1, &rng) == RES_BAD_ARG); 57 r = ssp_rng_create(NULL, type, &rng); 58 if(type == SSP_RNG_AES) { 59 switch(r) { 60 case RES_BAD_ARG: 61 fprintf(stderr, "AES not supported\n"); 62 break; 63 case RES_OK: /* Do nohting */ break; 64 case RES_BAD_OP: 65 fprintf(stderr, "AES-NI instructions not available.\n"); 66 break; 67 default: FATAL("Unreachable code\n"); break; 68 } 69 } 70 CHK(r == RES_OK); 71 72 CHK(ssp_rng_get_type(NULL, NULL) == RES_BAD_ARG); 73 CHK(ssp_rng_get_type(rng, NULL) == RES_BAD_ARG); 74 CHK(ssp_rng_get_type(NULL, &type2) == RES_BAD_ARG); 75 CHK(ssp_rng_get_type(rng, &type2) == RES_OK); 76 CHK(type == type2); 77 78 CHK(ssp_rng_ref_get(NULL) == RES_BAD_ARG); 79 CHK(ssp_rng_ref_get(rng) == RES_OK); 80 CHK(ssp_rng_ref_put(NULL) == RES_BAD_ARG); 81 CHK(ssp_rng_ref_put(rng) == RES_OK); 82 CHK(ssp_rng_ref_put(rng) == RES_OK); 83 84 CHK(ssp_rng_create(&allocator, type, &rng) == RES_OK); 85 CHK(ssp_rng_set(NULL, 0) == RES_BAD_ARG); 86 CHK(ssp_rng_set(rng, 0) == (can_set ? RES_OK : RES_BAD_OP)); 87 88 CHK(ssp_rng_create(NULL, type, &rng1) == RES_OK); 89 CHK(ssp_rng_create(NULL, type, &rng2) == RES_OK); 90 CHK(ssp_rng_discard(rng1, 10) == (can_discard ? RES_OK : RES_BAD_OP)); 91 if(type != SSP_RNG_RANDOM_DEVICE) { 92 FOR_EACH(i, 0, 10) ssp_rng_get(rng2); 93 CHK(ssp_rng_get(rng1) == ssp_rng_get(rng2)); 94 } 95 96 FOR_EACH(i, 0, NRAND) { 97 datai0[i] = ssp_rng_get(rng); 98 CHK(datai0[i] >= ssp_rng_min(rng)); 99 CHK(datai0[i] <= ssp_rng_max(rng)); 100 FOR_EACH(j, 0, i) { 101 CHK(datai0[i] != datai0[j]); 102 } 103 } 104 105 CHK(ssp_rng_set(rng, 0xDECAFBAD) == (can_set ? RES_OK : RES_BAD_OP)); 106 FOR_EACH(i, 0, NRAND) { 107 datai1[i] = ssp_rng_get(rng); 108 CHK(datai1[i] != datai0[i]); 109 CHK(datai1[i] >= ssp_rng_min(rng)); 110 CHK(datai1[i] <= ssp_rng_max(rng)); 111 FOR_EACH(j, 0, i) { 112 CHK(datai1[i] != datai1[j]); 113 } 114 } 115 116 FOR_EACH(i, 0, NRAND) { 117 datai0[i] = ssp_rng_uniform_uint64(rng, 1, 79); 118 CHK(datai0[i] >= 1); 119 CHK(datai0[i] <= 79); 120 } 121 FOR_EACH(i, 0, NRAND) { 122 FOR_EACH(j, 0, NRAND) if(datai0[i] != datai0[j]) break; 123 CHK(j != NRAND); 124 } 125 126 FOR_EACH(i, 0, NRAND) { 127 datad[i] = ssp_rng_uniform_double(rng, -5.0, 11.3); 128 CHK(datad[i] >= -5.0); 129 CHK(datad[i] <= 11.3); 130 } 131 FOR_EACH(i, 0, NRAND) { 132 FOR_EACH(j, 0, NRAND) if(datad[i] != datad[j]) break; 133 CHK(j != NRAND); 134 } 135 136 FOR_EACH(i, 0, NRAND) { 137 dataf[i] = ssp_rng_uniform_float(rng, -1.0, 12.5); 138 CHK(dataf[i] >= -1.0); 139 CHK(dataf[i] <= 12.5); 140 } 141 FOR_EACH(i, 0, NRAND) { 142 FOR_EACH(j, 0, NRAND) if(dataf[i] != dataf[j]) break; 143 CHK(j != NRAND); 144 } 145 146 FOR_EACH(i, 0, NRAND) { 147 datad[i] = ssp_rng_canonical(rng); 148 CHK(datad[i] >= 0.0); 149 CHK(datad[i] < 1.0 ); 150 FOR_EACH(j, 0, i) { 151 CHK(datad[i] != datad[j]); 152 } 153 } 154 155 FOR_EACH(i, 0, NRAND) { 156 dataf[i] = ssp_rng_canonical_float(rng); 157 CHK(dataf[i] >= 0.0); 158 CHK(dataf[i] < 1.0); 159 FOR_EACH(j, 0, i) { 160 CHK(dataf[i] != dataf[j]); 161 } 162 } 163 164 time_current(&t0); 165 FOR_EACH(i, 0, 1000000) { 166 ssp_rng_get(rng); 167 } 168 time_current(&t1); 169 time_sub(&t0, &t1, &t0); 170 time_dump(&t0, TIME_SEC|TIME_MSEC|TIME_USEC, NULL, buf, sizeof(buf)); 171 printf("1,000,000 random numbers in %s\n", buf); 172 173 if(can_have_entropy) { 174 printf("Entropy for this implementation and system: %f\n", 175 ssp_rng_entropy(rng)); 176 } 177 178 stream = tmpfile(); 179 CHK(stream != NULL); 180 CHK(ssp_rng_write(NULL, NULL) == RES_BAD_ARG); 181 CHK(ssp_rng_write(rng, NULL) == RES_BAD_ARG); 182 CHK(ssp_rng_write(NULL, stream) == RES_BAD_ARG); 183 CHK(ssp_rng_write(rng, stream) == (can_rw ? RES_OK : RES_BAD_OP)); 184 185 CHK(ssp_rng_write_cstr(NULL, NULL, 0, &len) == RES_BAD_ARG); 186 CHK(ssp_rng_write_cstr(rng, NULL, 0, NULL) == (can_rw ? RES_OK : RES_BAD_OP)); 187 CHK(ssp_rng_write_cstr(rng, NULL, 0, &len) == (can_rw ? RES_OK : RES_BAD_OP)); 188 cstr = mem_calloc(len+1, 1); 189 CHK(cstr != NULL); 190 CHK(ssp_rng_write_cstr(rng, cstr, len+1, NULL) == (can_rw ? RES_OK : RES_BAD_OP)); 191 192 /* Reserialize the RNG state */ 193 CHK(ssp_rng_write(rng, stream) == (can_rw ? RES_OK : RES_BAD_OP)); 194 195 FOR_EACH(i, 0, NRAND) 196 datai0[i] = ssp_rng_get(rng); 197 198 fflush(stream); 199 200 CHK(ssp_rng_read(NULL, NULL) == RES_BAD_ARG); 201 CHK(ssp_rng_read(rng, NULL) == RES_BAD_ARG); 202 CHK(ssp_rng_read(NULL, stream) == RES_BAD_ARG); 203 CHK(ssp_rng_read(rng, stream) == (can_rw ? RES_IO_ERR : RES_BAD_OP)); 204 rewind(stream); 205 206 /* Read the first state of the stream */ 207 CHK(ssp_rng_read(rng, stream) == (can_rw ? RES_OK : RES_BAD_OP)); 208 if(can_rw) { 209 FOR_EACH(i, 0, NRAND) { 210 uint64_t rn = ssp_rng_get(rng); 211 CHK(rn == datai0[i]); 212 } 213 } 214 215 /* Read the second state of the stream */ 216 CHK(ssp_rng_read(rng, stream) == (can_rw ? RES_OK : RES_BAD_OP)); 217 if(can_rw) { 218 FOR_EACH(i, 0, NRAND) { 219 uint64_t rn = ssp_rng_get(rng); 220 CHK(rn == datai0[i]); 221 } 222 } 223 224 /* Read the RNG state from an in memory buffer */ 225 CHK(ssp_rng_read_cstr(NULL, cstr) == RES_BAD_ARG); 226 CHK(ssp_rng_read_cstr(rng, NULL) == RES_BAD_ARG); 227 CHK(ssp_rng_read_cstr(rng, cstr) == (can_rw ? RES_OK : RES_BAD_OP)); 228 if(can_rw) { 229 FOR_EACH(i, 0, NRAND) { 230 uint64_t rn = ssp_rng_get(rng); 231 CHK(rn == datai0[i]); 232 } 233 } 234 235 mem_rm(cstr); 236 fclose(stream); 237 238 CHK(ssp_rng_ref_put(rng) == RES_OK); 239 ssp_rng_ref_put(rng1); 240 ssp_rng_ref_put(rng2); 241 242 check_memory_allocator(&allocator); 243 mem_shutdown_proxy_allocator(&allocator); 244 } 245 246 int 247 main(int argc, char** argv) 248 { 249 if (argc <= 1) { 250 fprintf(stderr, 251 "Usage: %s <kiss|mt19937_64|ranlux48|random_device|threefry|aes>\n", 252 argv[0]); 253 exit(0); 254 } 255 if(!strcmp(argv[1], "kiss")) { 256 test_rng(SSP_RNG_KISS); 257 } else if(!strcmp(argv[1], "mt19937_64")) { 258 test_rng(SSP_RNG_MT19937_64); 259 } else if(!strcmp(argv[1], "ranlux48")) { 260 test_rng(SSP_RNG_RANLUX48); 261 } else if(!strcmp(argv[1], "random_device")) { 262 test_rng(SSP_RNG_RANDOM_DEVICE); 263 } else if(!strcmp(argv[1], "threefry")) { 264 test_rng(SSP_RNG_THREEFRY); 265 } else if(!strcmp(argv[1], "aes")) { 266 test_rng(SSP_RNG_AES); 267 } else { 268 fprintf(stderr, "Unknown RNG `%s'\n", argv[1]); 269 ASSERT(0); 270 } 271 272 CHK(mem_allocated_size() == 0); 273 return 0; 274 } 275