File Coverage

csprng.c
Criterion Covered Total %
statement 85 86 98.8
branch 21 22 95.4
condition n/a
subroutine n/a
pod n/a
total 106 108 98.1


line stmt bran cond sub pod time code
1              
2             /* Our API for random numbers.
3             *
4             * We can use ISAAC, ChaCha20, or something else.
5             *
6             * 3700 ns/word ChaCha20 in Perl
7             * 3100 ns/word Salsa20 in Perl
8             * 1600 ns/word ChaCha8 in Perl
9             * 760 ns/word ISAAC in Perl
10             *
11             * 11.20 ns/word ChaCha20 (openbsd)
12             * 10.31 ns/word ChaCha20 (dj)
13             * 8.66 ns/word ChaCha20 (sse2 Peters)
14             * 6.85 ns/word ChaCha12 (dj)
15             * 5.99 ns/word Tyche
16             * 5.11 ns/word ChaCha8 (dj)
17             * 4.37 ns/word MT19937 (Cokus)
18             * 4.14 ns/word Tyche-i
19             * 3.26 ns/word ISAAC
20             * 3.18 ns/word PCG64 (64-bit state, 64-bit types)
21             * 1.95 ns/word PCG64 (64-bit state, 128-bit types)
22             * 1.84 ns/word ChaCha20 (AVX2 chacha-opt)
23             * 1.48 ns/word Xoroshiro128+
24             * 1.16 ns/word SplitMix64
25             *
26             * These functions do locking, the underlying library does not.
27             */
28              
29             #include
30             #include
31             #include
32             #include "ptypes.h"
33             #include "csprng.h"
34              
35             #include "chacha.h"
36             #define SEED_BYTES (32+8)
37             #define CSEED(ctx,bytes,data,good) chacha_seed(ctx,bytes,data,good)
38             #define CRBYTES(ctx,bytes,data) chacha_rand_bytes(ctx,bytes,data)
39             #define CIRAND32(ctx) chacha_irand32(ctx)
40             #define CIRAND64(ctx) chacha_irand64(ctx)
41             #define CSELFTEST() chacha_selftest()
42              
43             /* Helper macros, similar to ChaCha, so we're consistent. */
44             #ifndef U8TO32_LE
45             #define U8TO32_LE(p) \
46             (((uint32_t)((p)[0]) ) | \
47             ((uint32_t)((p)[1]) << 8) | \
48             ((uint32_t)((p)[2]) << 16) | \
49             ((uint32_t)((p)[3]) << 24))
50             #endif
51             #define U32TO8_LE(p, v) \
52             do { \
53             uint32_t _v = v; \
54             (p)[0] = (((_v) ) & 0xFFU); \
55             (p)[1] = (((_v) >> 8) & 0xFFU); \
56             (p)[2] = (((_v) >> 16) & 0xFFU); \
57             (p)[3] = (((_v) >> 24) & 0xFFU); \
58             } while (0)
59              
60             /*****************************************************************************/
61              
62             /* We put a simple non-CS PRNG here to help fill small seeds.
63             * I'd like to use PCG64 or Xoroshiro128+ here, but to be maximally
64             * portable and reproducible, we'll use PCG (RXS M XS 32).
65             */
66             #if 0
67             /* PCG XSH RR 64/32. 32-bit output, 64-bit state and types. */
68             uint32_t prng_next(char* rng) {
69             uint32_t xorshifted, rot;
70             uint64_t *state = (uint64_t*) rng;
71             uint64_t oldstate = state[0];
72             pcg_state = oldstate * 6364136223846793005ULL + state[1];
73             xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u;
74             rot = oldstate >> 59u;
75             return (xorshifted >> rot) | (xorshifted << ((-rot) & 31));
76             }
77             char* prng_new(uint32_t a, uint32_t b, uint32_t c, uint32_t d) {
78             uint64_t *state, initstate, initseq;
79             New(0, state, 2, uint64_t);
80             initstate = (((uint64_t)a) << 32) | b;
81             initseq = (((uint64_t)c) << 32) | d;
82             state[0] = 0U;
83             state[1] = (initseq << 1u) | 1u;
84             (void) prng_next((char*)state);
85             state[0] += initstate;
86             (void) prng_next((char*)state);
87             return (char*) state;
88             }
89             #else
90             /* PCG RXS M XS 32. 32-bit output, 32-bit state and types. */
91 64           uint32_t prng_next(char* ctx) {
92 64           uint32_t *rng = (uint32_t*) ctx;
93 64           uint32_t word, oldstate = rng[0];
94 64           rng[0] = rng[0] * 747796405U + rng[1];
95 64           word = ((oldstate >> ((oldstate >> 28u) + 4u)) ^ oldstate) * 277803737u;
96 64           return (word >> 22u) ^ word;
97             }
98 5           char* prng_new(uint32_t a, uint32_t b, uint32_t c, uint32_t d) {
99             uint32_t *state;
100 5           New(0, state, 2, uint32_t);
101 5           state[0] = 0U;
102 5           state[1] = (b << 1u) | 1u;
103 5           (void) prng_next((char*)state);
104 5           state[0] += a;
105 5           (void) prng_next((char*)state);
106 5           state[0] ^= c;
107 5           (void) prng_next((char*)state);
108 5           state[0] ^= d;
109 5           (void) prng_next((char*)state);
110 5           return (char*) state;
111             }
112             #endif
113              
114             /*****************************************************************************/
115              
116 138           uint32_t csprng_context_size(void)
117             {
118 138           return sizeof(chacha_context_t);
119             }
120             static char _has_selftest_run = 0;
121              
122 80           void csprng_seed(void *ctx, uint32_t bytes, const unsigned char* data)
123             {
124             unsigned char seed[SEED_BYTES + 4];
125              
126             /* If given a short seed, minimize zeros in state */
127 80 100         if (bytes >= SEED_BYTES) {
128 75           memcpy(seed, data, SEED_BYTES);
129             } else {
130             char* rng;
131             uint32_t a, b, c, d, i;
132 5           memcpy(seed, data, bytes);
133 5           memset(seed+bytes, 0, sizeof(seed)-bytes);
134 5           a = U8TO32_LE((seed + 0));
135 5           b = U8TO32_LE((seed + 4));
136 5           c = U8TO32_LE((seed + 8));
137 5           d = U8TO32_LE((seed + 12));
138 5           rng = prng_new(a,b,c,d);
139 49 100         for (i = 4*((bytes+3)/4); i < SEED_BYTES; i += 4)
140 44           U32TO8_LE(seed + i, prng_next(rng));
141 5           Safefree(rng);
142             #if 0
143             printf("got %u bytes in expanded to %u\n", bytes, SEED_BYTES);
144             printf("from: ");for(i=0;i
145             printf("to: ");for(i=0;i
146             #endif
147             }
148              
149 80 100         if (!_has_selftest_run) {
150 69           _has_selftest_run = 1;
151 69           CSELFTEST();
152             }
153 80           CSEED(ctx, SEED_BYTES, seed, (bytes >= 16));
154 80           }
155              
156 5           extern void csprng_srand(void* ctx, UV insecure_seed)
157             {
158             #if BITS_PER_WORD == 32
159             unsigned char seed[4] = {0};
160             U32TO8_LE(seed, insecure_seed);
161             csprng_seed(ctx, 4, seed);
162             #else
163 5           unsigned char seed[8] = {0};
164 5 100         if (insecure_seed <= UVCONST(4294967295)) {
165 4           U32TO8_LE(seed, insecure_seed);
166 4           csprng_seed(ctx, 4, seed);
167             } else {
168 1           U32TO8_LE(seed, insecure_seed);
169 1           U32TO8_LE(seed + 4, (insecure_seed >> 32));
170 1           csprng_seed(ctx, 8, seed);
171             }
172             #endif
173 5           }
174              
175 45           void csprng_rand_bytes(void* ctx, uint32_t bytes, unsigned char* data)
176             {
177 45           CRBYTES(ctx, bytes, data);
178 45           }
179              
180 100875           uint32_t irand32(void* ctx)
181             {
182 100875           return CIRAND32(ctx);
183             }
184 2328           UV irand64(void* ctx)
185             {
186             #if BITS_PER_WORD < 64
187             croak("irand64 too many bits for UV");
188             #else
189 2328           return CIRAND64(ctx);
190             #endif
191             }
192              
193              
194             /*****************************************************************************/
195              
196 1           int is_csprng_well_seeded(void *ctx)
197             {
198 1           chacha_context_t *cs = ctx;
199 1           return cs->goodseed;
200             }
201              
202             /* There are many ways to get floats from integers. A few good, many bad.
203             *
204             * Vigna recommends (x64 >> 11) * (1.0 / (1ULL<<53)).
205             * http://xoroshiro.di.unimi.it
206             * Also see alternatives discussed:
207             * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/VERSIONS/C-LANG/speed-up-real.html
208             *
209             * Melissa O'Neill notes the problem is harder than it looks, doesn't address.
210             * http://www.pcg-random.org/pdf/toms-oneill-pcg-family-v1.02.pdf
211             *
212             * randomstate for numpy uses separate code for each generator.
213             * With the exception of dSFMT, they each one one of:
214             * (x64 >> 11) * (1 / 9007199254740992.0)
215             * ((x32 >> 5) * 67108864.0 + (y32 >> 6)) / 9007199254740992.0
216             * where the first one is identical to Vigna.
217             *
218             * David Jones recommends the minor 32-bit variant:
219             * ((x32 >> 6) * 134217728.0 + (y32 >> 5)) / 9007199254740992.0
220             * http://www0.cs.ucl.ac.uk/staff/d.jones/GoodPracticeRNG.pdf
221             *
222             * Taylor Campbell discusses this in:
223             * http://mumble.net/~campbell/tmp/random_real.c
224             * He points out that there are two common non-broken choices,
225             * div by 2^-53 or div by 2^-64, and each are slightly flawed in
226             * different ways. He shows a theoretically better method.
227             */
228              
229             /*
230             * We prefer the x64 / 2^-64 method. It seems to produce the best results
231             * and is easiest for ensuring we fill up all the bits.
232             * It is similar to what Geoff Kuenning does in MTwist, though he computes
233             * the constants at runtime to ensure a dodgy compiler won't munge them.
234             */
235             #define TO_NV_32 2.3283064365386962890625000000000000000E-10L
236             #define TO_NV_64 5.4210108624275221700372640043497085571E-20L
237             #define TO_NV_96 1.2621774483536188886587657044524579675E-29L
238             #define TO_NV_128 2.9387358770557187699218413430556141945E-39L
239              
240             #define DRAND_32_32 (CIRAND32(ctx) * TO_NV_32)
241             #define DRAND_64_32 (((CIRAND32(ctx)>>5) * 67108864.0 + (CIRAND32(ctx)>>6)) / 9007199254740992.0)
242             #define DRAND_64_64 (CIRAND64(ctx) * TO_NV_64)
243             #define DRAND_128_32 (CIRAND32(ctx) * TO_NV_32 + CIRAND32(ctx) * TO_NV_64 + CIRAND32(ctx) * TO_NV_96 + CIRAND32(ctx) * TO_NV_128)
244             #define DRAND_128_64 (CIRAND64(ctx) * TO_NV_64 + CIRAND64(ctx) * TO_NV_128)
245              
246 6033           NV drand64(void* ctx)
247             {
248             NV r;
249             #if NVMANTBITS <= 32
250             r = DRAND_32_32;
251             #elif NVMANTBITS <= 64
252 6033           r = (BITS_PER_WORD <= 32) ? DRAND_64_32 : DRAND_64_64;
253             #else
254             r = (BITS_PER_WORD <= 32) ? DRAND_128_32 : DRAND_128_64;
255             #endif
256 6033           return r;
257             }
258              
259             /* Return rand 32-bit integer between 0 to n-1 inclusive */
260 134384           uint32_t urandomm32(void *ctx, uint32_t n)
261             {
262             uint32_t r, rmin;
263              
264 134384 100         if (n <= 1)
265 1010           return 0;
266              
267 133374           rmin = -n % n;
268             while (1) {
269 133375           r = CIRAND32(ctx);
270 133375 100         if (r >= rmin)
271 133374           break;
272 1           }
273 133374           return r % n;
274             }
275              
276 134554           UV urandomm64(void* ctx, UV n)
277             {
278             UV r, rmin;
279              
280 134554 100         if (n <= 4294967295UL)
281 134262           return urandomm32(ctx,n);
282              
283 292           rmin = -n % n;
284             while (1) {
285 295           r = CIRAND64(ctx);
286 295 100         if (r >= rmin)
287 292           break;
288 3           }
289 292           return r % n;
290             }
291              
292 3191           UV urandomb(void* ctx, int nbits)
293             {
294 3191 100         if (nbits == 0) {
295 1           return 0;
296 3190 100         } else if (nbits <= 32) {
297 870           return irand32(ctx) >> (32-nbits);
298             #if BITS_PER_WORD == 64
299 2320 50         } else if (nbits <= 64) {
300 2320           return irand64(ctx) >> (64-nbits);
301             #endif
302             }
303 0           croak("irand64 too many bits for UV");
304             }