|
| 1 | +/* |
| 2 | + +----------------------------------------------------------------------+ |
| 3 | + | Copyright (c) The PHP Group | |
| 4 | + +----------------------------------------------------------------------+ |
| 5 | + | This source file is subject to version 3.01 of the PHP license, | |
| 6 | + | that is bundled with this package in the file LICENSE, and is | |
| 7 | + | available through the world-wide-web at the following url: | |
| 8 | + | https://www.php.net/license/3_01.txt | |
| 9 | + | If you did not receive a copy of the PHP license and are unable to | |
| 10 | + | obtain it through the world-wide-web, please send a note to | |
| 11 | + | [email protected] so we can mail you a copy immediately. | |
| 12 | + +----------------------------------------------------------------------+ |
| 13 | + | Authors: Sascha Schumann <[email protected]> | |
| 14 | + |
| 15 | + +----------------------------------------------------------------------+ |
| 16 | +*/ |
| 17 | + |
| 18 | +#ifdef HAVE_CONFIG_H |
| 19 | +# include "config.h" |
| 20 | +#endif |
| 21 | + |
| 22 | +#include "php.h" |
| 23 | +#include "php_random.h" |
| 24 | + |
| 25 | +#include "ext/spl/spl_exceptions.h" |
| 26 | +#include "Zend/zend_exceptions.h" |
| 27 | + |
| 28 | +/* |
| 29 | + * combinedLCG() returns a pseudo random number in the range of (0, 1). |
| 30 | + * The function combines two CGs with periods of |
| 31 | + * 2^31 - 85 and 2^31 - 249. The period of this function |
| 32 | + * is equal to the product of both primes. |
| 33 | + */ |
| 34 | +#define MODMULT(a, b, c, m, s) q = s / a; s = b * (s - a * q) - c * q; if (s < 0) s += m |
| 35 | + |
| 36 | +static void seed(php_random_status *status, uint64_t seed) |
| 37 | +{ |
| 38 | + php_random_status_state_combinedlcg *s = status->state; |
| 39 | + |
| 40 | + s->state[0] = seed & 0xffffffffU; |
| 41 | + s->state[1] = seed >> 32; |
| 42 | +} |
| 43 | + |
| 44 | +static uint64_t generate(php_random_status *status) |
| 45 | +{ |
| 46 | + php_random_status_state_combinedlcg *s = status->state; |
| 47 | + int32_t q, z; |
| 48 | + |
| 49 | + MODMULT(53668, 40014, 12211, 2147483563L, s->state[0]); |
| 50 | + MODMULT(52774, 40692, 3791, 2147483399L, s->state[1]); |
| 51 | + |
| 52 | + z = s->state[0] - s->state[1]; |
| 53 | + if (z < 1) { |
| 54 | + z += 2147483562; |
| 55 | + } |
| 56 | + |
| 57 | + return (uint64_t) z; |
| 58 | +} |
| 59 | + |
| 60 | +static zend_long range(php_random_status *status, zend_long min, zend_long max) |
| 61 | +{ |
| 62 | + return php_random_range(&php_random_algo_combinedlcg, status, min, max); |
| 63 | +} |
| 64 | + |
| 65 | +static bool serialize(php_random_status *status, HashTable *data) |
| 66 | +{ |
| 67 | + php_random_status_state_combinedlcg *s = status->state; |
| 68 | + zval t; |
| 69 | + |
| 70 | + for (uint32_t i = 0; i < 2; i++) { |
| 71 | + ZVAL_STR(&t, php_random_bin2hex_le(&s->state[i], sizeof(uint32_t))); |
| 72 | + zend_hash_next_index_insert(data, &t); |
| 73 | + } |
| 74 | + |
| 75 | + return true; |
| 76 | +} |
| 77 | + |
| 78 | +static bool unserialize(php_random_status *status, HashTable *data) |
| 79 | +{ |
| 80 | + php_random_status_state_combinedlcg *s = status->state; |
| 81 | + zval *t; |
| 82 | + |
| 83 | + for (uint32_t i = 0; i < 2; i++) { |
| 84 | + t = zend_hash_index_find(data, i); |
| 85 | + if (!t || Z_TYPE_P(t) != IS_STRING || Z_STRLEN_P(t) != (2 * sizeof(uint32_t))) { |
| 86 | + return false; |
| 87 | + } |
| 88 | + if (!php_random_hex2bin_le(Z_STR_P(t), &s->state[i])) { |
| 89 | + return false; |
| 90 | + } |
| 91 | + } |
| 92 | + |
| 93 | + return true; |
| 94 | +} |
| 95 | + |
| 96 | +const php_random_algo php_random_algo_combinedlcg = { |
| 97 | + sizeof(uint32_t), |
| 98 | + sizeof(php_random_status_state_combinedlcg), |
| 99 | + seed, |
| 100 | + generate, |
| 101 | + range, |
| 102 | + serialize, |
| 103 | + unserialize |
| 104 | +}; |
| 105 | + |
| 106 | +/* {{{ php_random_combinedlcg_seed_default */ |
| 107 | +PHPAPI void php_random_combinedlcg_seed_default(php_random_status_state_combinedlcg *state) |
| 108 | +{ |
| 109 | + struct timeval tv; |
| 110 | + |
| 111 | + if (gettimeofday(&tv, NULL) == 0) { |
| 112 | + state->state[0] = tv.tv_usec ^ (tv.tv_usec << 11); |
| 113 | + } else { |
| 114 | + state->state[0] = 1; |
| 115 | + } |
| 116 | + |
| 117 | +#ifdef ZTS |
| 118 | + state->state[1] = (zend_long) tsrm_thread_id(); |
| 119 | +#else |
| 120 | + state->state[1] = (zend_long) getpid(); |
| 121 | +#endif |
| 122 | + |
| 123 | + /* Add entropy to s2 by calling gettimeofday() again */ |
| 124 | + if (gettimeofday(&tv, NULL) == 0) { |
| 125 | + state->state[1] ^= (tv.tv_usec << 11); |
| 126 | + } |
| 127 | +} |
| 128 | +/* }}} */ |
0 commit comments