star-sp

Random number generators and distributions
git clone git://git.meso-star.fr/star-sp.git
Log | Files | Refs | README | LICENSE

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