|
| 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 | + | license@php.net so we can mail you a copy immediately. | |
| 12 | + +----------------------------------------------------------------------+ |
| 13 | + | Authors: Rasmus Lerdorf <rasmus@php.net> | |
| 14 | + | Zeev Suraski <zeev@php.net> | |
| 15 | + | Sascha Schumann <sascha@schumann.cx> | |
| 16 | + | Pedro Melo <melo@ip.pt> | |
| 17 | + | Sterling Hughes <sterling@php.net> | |
| 18 | + | Sammy Kaye Powers <me@sammyk.me> | |
| 19 | + | Go Kudo <g-kudo@colopl.co.jp> | |
| 20 | + | | |
| 21 | + | Based on code from: Richard J. Wagner <rjwagner@writeme.com> | |
| 22 | + | Makoto Matsumoto <matumoto@math.keio.ac.jp> | |
| 23 | + | Takuji Nishimura | |
| 24 | + | Shawn Cokus <Cokus@math.washington.edu> | |
| 25 | + +----------------------------------------------------------------------+ |
| 26 | +*/ |
| 27 | +#ifndef PHP_RANDOM_H |
| 28 | +# define PHP_RANDOM_H |
| 29 | + |
| 30 | +/* System Rand functions */ |
| 31 | +# ifndef RAND_MAX |
| 32 | +# define RAND_MAX PHP_MT_RAND_MAX |
| 33 | +# endif |
| 34 | + |
| 35 | +# define PHP_RAND_MAX PHP_MT_RAND_MAX |
| 36 | + |
| 37 | +/* |
| 38 | + * A bit of tricky math here. We want to avoid using a modulus because |
| 39 | + * that simply tosses the high-order bits and might skew the distribution |
| 40 | + * of random values over the range. Instead we map the range directly. |
| 41 | + * |
| 42 | + * We need to map the range from 0...M evenly to the range a...b |
| 43 | + * Let n = the random number and n' = the mapped random number |
| 44 | + * |
| 45 | + * Then we have: n' = a + n(b-a)/M |
| 46 | + * |
| 47 | + * We have a problem here in that only n==M will get mapped to b which |
| 48 | + * means the chances of getting b is much much less than getting any of |
| 49 | + * the other values in the range. We can fix this by increasing our range |
| 50 | + * artificially and using: |
| 51 | + * |
| 52 | + * n' = a + n(b-a+1)/M |
| 53 | + * |
| 54 | + * Now we only have a problem if n==M which would cause us to produce a |
| 55 | + * number of b+1 which would be bad. So we bump M up by one to make sure |
| 56 | + * this will never happen, and the final algorithm looks like this: |
| 57 | + * |
| 58 | + * n' = a + n(b-a+1)/(M+1) |
| 59 | + * |
| 60 | + * -RL |
| 61 | + */ |
| 62 | +# define RAND_RANGE_BADSCALING(__n, __min, __max, __tmax) \ |
| 63 | + (__n) = (__min) + (zend_long) ((double) ( (double) (__max) - (__min) + 1.0) * ((__n) / ((__tmax) + 1.0))) |
| 64 | + |
| 65 | +# ifdef PHP_WIN32 |
| 66 | +# define GENERATE_SEED() (((zend_long) (time(0) * GetCurrentProcessId())) ^ ((zend_long) (1000000.0 * php_combined_lcg()))) |
| 67 | +# else |
| 68 | +# define GENERATE_SEED() (((zend_long) (time(0) * getpid())) ^ ((zend_long) (1000000.0 * php_combined_lcg()))) |
| 69 | +# endif |
| 70 | + |
| 71 | +# define PHP_MT_RAND_MAX ((zend_long) (0x7FFFFFFF)) /* (1<<31) - 1 */ |
| 72 | + |
| 73 | +# define MT_RAND_MT19937 0 |
| 74 | +# define MT_RAND_PHP 1 |
| 75 | + |
| 76 | +# define MT_N (624) |
| 77 | + |
| 78 | +# define php_random_bytes_throw(b, s) php_random_bytes((b), (s), 1) |
| 79 | +# define php_random_bytes_silent(b, s) php_random_bytes((b), (s), 0) |
| 80 | + |
| 81 | +# define php_random_int_throw(min, max, result) \ |
| 82 | + php_random_int((min), (max), (result), 1) |
| 83 | +# define php_random_int_silent(min, max, result) \ |
| 84 | + php_random_int((min), (max), (result), 0) |
| 85 | + |
| 86 | +PHPAPI double php_combined_lcg(void); |
| 87 | + |
| 88 | +PHPAPI void php_srand(zend_long seed); |
| 89 | +PHPAPI zend_long php_rand(void); |
| 90 | + |
| 91 | +PHPAPI void php_mt_srand(uint32_t seed); |
| 92 | +PHPAPI uint32_t php_mt_rand(void); |
| 93 | +PHPAPI zend_long php_mt_rand_range(zend_long min, zend_long max); |
| 94 | +PHPAPI zend_long php_mt_rand_common(zend_long min, zend_long max); |
| 95 | + |
| 96 | +PHPAPI int php_random_bytes(void *bytes, size_t size, bool should_throw); |
| 97 | +PHPAPI int php_random_int(zend_long min, zend_long max, zend_long *result, bool should_throw); |
| 98 | + |
| 99 | +typedef struct _php_random_numbergenerator_algo { |
| 100 | + const size_t generate_size; |
| 101 | + const size_t state_size; |
| 102 | + uint64_t (*generate)(void *state); |
| 103 | + void (*seed)(void *state, const uint64_t seed); /* nullable */ |
| 104 | + int (*serialize)(void *state, HashTable *data); /* nullable */ |
| 105 | + int (*unserialize)(void *state, HashTable *data); /* nullable */ |
| 106 | +} php_random_numbergenerator_algo; |
| 107 | + |
| 108 | +PHPAPI const php_random_numbergenerator_algo *php_random_numbergenerator_get_default_algo(void); |
| 109 | +PHPAPI void *php_random_numbergenerater_get_default_state(void); |
| 110 | + |
| 111 | +PHPAPI zend_long php_random_numbergenerator_range(const php_random_numbergenerator_algo *algo, void *state, zend_long min, zend_long max); |
| 112 | + |
| 113 | +extern zend_module_entry random_module_entry; |
| 114 | +# define phpext_random_ptr &random_module_entry |
| 115 | + |
| 116 | +extern PHPAPI zend_class_entry *random_ce_Random_NumberGenerator; |
| 117 | +extern PHPAPI zend_class_entry *random_ce_Random_NumberGenerator_XorShift128Plus; |
| 118 | +extern PHPAPI zend_class_entry *random_ce_Random_NumberGenerator_MersenneTwister; |
| 119 | +extern PHPAPI zend_class_entry *random_ce_Random_NumberGenerator_CombinedLCG; |
| 120 | +extern PHPAPI zend_class_entry *random_ce_Random_NumberGenerator_Secure; |
| 121 | +extern PHPAPI zend_class_entry *random_ce_Random_Randomizer; |
| 122 | + |
| 123 | +extern const php_random_numbergenerator_algo php_random_numbergenerator_algo_xorshift128plus; |
| 124 | +extern const php_random_numbergenerator_algo php_random_numbergenerator_algo_mersennetwister; |
| 125 | +extern const php_random_numbergenerator_algo php_random_numbergenerator_algo_combinedlcg; |
| 126 | +extern const php_random_numbergenerator_algo php_random_numbergenerator_algo_secure; |
| 127 | +extern const php_random_numbergenerator_algo php_random_numbergenerator_algo_user; |
| 128 | + |
| 129 | +typedef struct _php_random_numbergenerator { |
| 130 | + const php_random_numbergenerator_algo *algo; |
| 131 | + void *state; |
| 132 | + zend_object std; |
| 133 | +} php_random_numbergenerator; |
| 134 | + |
| 135 | +typedef struct _php_random_randomizer { |
| 136 | + const php_random_numbergenerator_algo *algo; |
| 137 | + void *state; |
| 138 | + bool self_allocate; |
| 139 | + zend_object std; |
| 140 | +} php_random_randomizer; |
| 141 | + |
| 142 | +typedef struct _php_random_numbergenerator_state_xorshift128plus { |
| 143 | + uint64_t s[2]; |
| 144 | +} php_random_numbergenerator_state_xorshift128plus; |
| 145 | + |
| 146 | +typedef struct _php_random_numbergenerator_state_mersennetwister { |
| 147 | + uint32_t s[MT_N]; |
| 148 | + int cnt; |
| 149 | + zend_long mode; |
| 150 | + bool seeded; |
| 151 | +} php_random_numbergenerator_state_mersennetwister; |
| 152 | + |
| 153 | +typedef struct _php_random_numbergenerator_state_combinedlcg { |
| 154 | + int32_t s[2]; |
| 155 | + bool seeded; |
| 156 | +} php_random_numbergenerator_state_combinedlcg; |
| 157 | + |
| 158 | +typedef struct _php_random_numbergenerator_state_user { |
| 159 | + zend_object *object; |
| 160 | + zend_function *method; |
| 161 | +} php_random_numbergenerator_state_user; |
| 162 | + |
| 163 | +static inline php_random_numbergenerator *php_random_numbergenerator_from_obj(zend_object *obj) { |
| 164 | + return (php_random_numbergenerator *)((char *)(obj) - XtOffsetOf(php_random_numbergenerator, std)); |
| 165 | +} |
| 166 | + |
| 167 | +static inline php_random_randomizer *php_random_randomizer_from_obj(zend_object *obj) { |
| 168 | + return (php_random_randomizer *)((char *)(obj) - XtOffsetOf(php_random_randomizer, std)); |
| 169 | +} |
| 170 | + |
| 171 | +# define Z_RANDOM_NUMBERGENERATOR_P(zval) php_random_numbergenerator_from_obj(Z_OBJ_P(zval)) |
| 172 | + |
| 173 | +# define Z_RANDOM_RANDOMIZER_P(zval) php_random_randomizer_from_obj(Z_OBJ_P(zval)) |
| 174 | + |
| 175 | +PHP_MINIT_FUNCTION(random); |
| 176 | +PHP_MSHUTDOWN_FUNCTION(random); |
| 177 | +PHP_RINIT_FUNCTION(random); |
| 178 | + |
| 179 | +ZEND_BEGIN_MODULE_GLOBALS(random) |
| 180 | + php_random_numbergenerator_state_combinedlcg clcg; /* Combined LCG global state */ |
| 181 | + php_random_numbergenerator_state_mersennetwister mt; /* MT global state */ |
| 182 | + int random_fd; /* random file discriptor */ |
| 183 | +ZEND_END_MODULE_GLOBALS(random) |
| 184 | + |
| 185 | +# define RANDOM_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(random, v) |
| 186 | + |
| 187 | +#endif /* PHP_RANDOM_H */ |
0 commit comments