Hi all,
Following code is problematic and needs proper reseeding to work.
// We need the same random numbers here
mt_srand(1234);
for ($i=0; $i < 10; $i++) {
$my_rand[] = mt_rand()
;
}
Somewhere later in code
// We need somewhat random numbers for non CS purpose
for ($i=0; $i < 10; $i++) {
$my_other_rand[] = mt_rand()
;
}
$my_other_rand array is not random at all for the app. This applies to
rand()
/srand() as well as all functions that use rand and rand/MT rand
internally. e.g. shuffle()
. rand()
is alias of mt_rand()
in PHP 7.1, it can
cause serious problem. i.e. srand(1234) forces mt_rand()
to generate non
random numbers.
In addition, this behavior persists across requests because once
BG(mt_rand_is_seeded)/BG(rand_is_seeded) are set to 1, they are kept for
the process. Therefore, subsequent mt_rand()
/rand(), including any
functions use rand/MT rand internally such as shuffle()
, call in other
requests are not random.
In order to get random numbers, we need to reseed RNG.
Currently, it is possible to reseed like (int overflow is ignored)
$seed = unpack("l", file_get_contents("/dev/urandom", false, NULL, 0, 4));
mt_srand($seed[1]);
for ($i=0; $i < 10; $i++) {
$my_other_rand[] = mt_rand()
;
}
OR for PHP 7
mt_srand(random_int(PHP_INT_MIN, PHP_INT_MAX));
for ($i=0; $i < 10; $i++) {
$my_other_rand[] = mt_rand()
;
}
Requiring these reseeding code for most mt_rand()
/rand() calls is not
preferred behavior.
Proposal:
- Add BG(mt_rand_is_user_seeded) and BG(rand_is_user_seeded). If they are
1, set BG(mt_rand_is_seeded)=0 and BG(rand_is_seeded)=0. - Make srand(0) and mt_srand(0) to force RNG reseeding by PHP.
Outcome:
- resolves "across requests" non random numbers.
- simplifies reseeding.
Problem:
- Added new BG values are BC for released versions. Simply reseeding by
current GENERATE_SEED() macro is weak and too easy to be guessed even with
MT rand. i.e. Setting BG(mt_rand_is_seeded)=0 and BG(rand_is_seeded)=0 at
RINIT is not exactly a good idea. (There is improvement discussion in
"Improvingmt_rand()
seed" thread) - Manual reseeding API, srand(0)/mt_srand(0), is not compatible with older
versions.
Open Issue:
- and 2), apply these to released versions or not.
This idea is acceptable, but I don't like this idea myself.
It seems we should do something for this, documentation for released
versions at least.
Any better ideas are appreciated.
Regards,
--
Yasuo Ohgaki
yohgaki@ohgaki.net
Hi all,
Following code is problematic and needs proper reseeding to work.
// We need the same random numbers here
mt_srand(1234);
for ($i=0; $i < 10; $i++) {
$my_rand[] =mt_rand()
;
}Somewhere later in code
// We need somewhat random numbers for non CS purpose
for ($i=0; $i < 10; $i++) {
$my_other_rand[] =mt_rand()
;
}$my_other_rand array is not random at all for the app. This applies to
rand()
/srand() as well as all functions that use rand and rand/MT rand
internally. e.g.shuffle()
.rand()
is alias ofmt_rand()
in PHP 7.1, it can
cause serious problem. i.e. srand(1234) forcesmt_rand()
to generate non
random numbers.In addition, this behavior persists across requests because once
BG(mt_rand_is_seeded)/BG(rand_is_seeded) are set to 1, they are kept for
the process. Therefore, subsequentmt_rand()
/rand(), including any
functions use rand/MT rand internally such asshuffle()
, call in other
requests are not random.In order to get random numbers, we need to reseed RNG.
Currently, it is possible to reseed like (int overflow is ignored)
$seed = unpack("l", file_get_contents("/dev/urandom", false, NULL, 0, 4));
mt_srand($seed[1]);
for ($i=0; $i < 10; $i++) {
$my_other_rand[] =mt_rand()
;
}OR for PHP 7
mt_srand(random_int(PHP_INT_MIN, PHP_INT_MAX));
for ($i=0; $i < 10; $i++) {
$my_other_rand[] =mt_rand()
;
}Requiring these reseeding code for most
mt_rand()
/rand() calls is not
preferred behavior.Proposal:
- Add BG(mt_rand_is_user_seeded) and BG(rand_is_user_seeded). If they are
1, set BG(mt_rand_is_seeded)=0 and BG(rand_is_seeded)=0.- Make srand(0) and mt_srand(0) to force RNG reseeding by PHP.
Outcome:
- resolves "across requests" non random numbers.
- simplifies reseeding.
Problem:
- Added new BG values are BC for released versions. Simply reseeding by
current GENERATE_SEED() macro is weak and too easy to be guessed even with
MT rand. i.e. Setting BG(mt_rand_is_seeded)=0 and BG(rand_is_seeded)=0 at
RINIT is not exactly a good idea. (There is improvement discussion in
"Improvingmt_rand()
seed" thread)- Manual reseeding API, srand(0)/mt_srand(0), is not compatible with older
versions.Open Issue:
- and 2), apply these to released versions or not.
This idea is acceptable, but I don't like this idea myself.
It seems we should do something for this, documentation for released
versions at least.
Any better ideas are appreciated.
Just a quick idea:
<?php
class PNRG {
public function __construct($seed = null) {…}
public function get() {…}
}
--
Christoph M. Becker
Hi Christoph,
Christoph M. Becker wrote:
Just a quick idea:
<?php
class PNRG {
public function __construct($seed = null) {…}
public function get() {…}
}
I've long favoured an API along these lines. One size does not fit all,
you need two APIs for (non-crytographic) random numbers:
- automatically-seeded, non-reproducible numbers (a global function like
rand()
) - manually-seeded, reproducible number sequences (objects)
Currently we mix these two, and it's a mess. The easy solution would be
a random number-generating object like you propose, to cover the second
use-case. We could also introduce a non-manually-seedable global PRNG
also, if desired. Perhaps as a static method of that class.
One thought: it'd be nice if you had two different methods, one that
mutates in places, and one that doesn't, i.e.:
$prng1 = new PRNG(SEED);
[$randomNumber, $prng2] = $prng2->getWithNewPRNG();
v.s.:
$prng = new PRNG(SEED);
$randomNumber = $prng->get();
$randomNumber2 = $prng->get();
Thanks!
--
Andrea Faulds
https://ajf.me/
Hi Andrea,
Christoph M. Becker wrote:
Just a quick idea:
<?php
class PNRG {
public function __construct($seed = null) {…}
public function get() {…}
}I've long favoured an API along these lines. One size does not fit all,
you need two APIs for (non-crytographic) random numbers:
- automatically-seeded, non-reproducible numbers (a global function like
rand()
)- manually-seeded, reproducible number sequences (objects)
I agree. We should have PRNG object.
Currently we mix these two, and it's a mess. The easy solution would be a
random number-generating object like you propose, to cover the second
use-case. We could also introduce a non-manually-seedable global PRNG also,
if desired. Perhaps as a static method of that class.
Mixing system and user seeded PRNG is mess. I totally agree.
Let's divide them into separated states.
One thought: it'd be nice if you had two different methods, one that
mutates in places, and one that doesn't, i.e.:$prng1 = new PRNG(SEED);
[$randomNumber, $prng2] = $prng2->getWithNewPRNG();v.s.:
$prng = new PRNG(SEED);
$randomNumber = $prng->get();
$randomNumber2 = $prng->get();
My current objective is to make existing API to work, so resource may be
used
to set/get PRNG state.
*** Initialize and Create new PRNG state resource ***
resource mt_srand([int|string $seed])
resource: MT rand state resource.
$seed: I would like to allow large seed like Python and Ruby.
When seed is string, use all bits for MT rand state
initialization.
Example usage: mt_srand(random_bytes(2000));
*** Get random number from state resource ***
int mt_rand()
// System state
int mt_rand(resource $state) // Specified user state
int mt_rand(int $min , int $max [,resource $state]) // Specified user state
if $state is passed
I suppose most codes do not use mt_srand()
/srand(). With new API, users may
write
code like
===============
// We need the same random numbers here
$my_state = mt_srand(1234);
// NOTE: mt_srand()
, w/o seed, creates new PRNG state.
for ($i=0; $i < 10; $i++) {
// Use my PRNG state
$my_rand[] = mt_rand($my_state);
}
Somewhere later in code
// We need somewhat random numbers for non CS purpose
for ($i=0; $i < 10; $i++) {
// System PRNG state is affected by mt_srand()
/srand()
// and $my_other_rand will have proper random values
$my_other_rand[] = mt_rand()
;
}
This requires code modifications, but it isn't too bad.
Problem is this change would be master only and
other functions, e.g. shuffle()
, have optional state resource
parameter or not.
Thoughts? Comments?
Regards,
--
Yasuo Ohgaki
yohgaki@ohgaki.net
Hi,
Yasuo Ohgaki wrote:
My current objective is to make existing API to work, so resource may be
used
to set/get PRNG state.
I would prefer it if we not introduce a new usage of resources. An
object would suffice.
*** Initialize and Create new PRNG state resource ***
resource mt_srand([int|string $seed])resource: MT rand state resource.
$seed: I would like to allow large seed like Python and Ruby.
When seed is string, use all bits for MT rand state
initialization.
Example usage: mt_srand(random_bytes(2000));*** Get random number from state resource ***
intmt_rand()
// System state
int mt_rand(resource $state) // Specified user state
int mt_rand(int $min , int $max [,resource $state]) // Specified user state
if $state is passed
While we could retrofit this into the existing API, it would be cleaner
and friendlier to provide a new one based on objects.
--
Andrea Faulds
https://ajf.me/
Hi all,
Yasuo Ohgaki wrote:
My current objective is to make existing API to work, so resource may be
used
to set/get PRNG state.I would prefer it if we not introduce a new usage of resources. An object
would suffice.*** Initialize and Create new PRNG state resource ***
resource mt_srand([int|string $seed])
resource: MT rand state resource.
$seed: I would like to allow large seed like Python and Ruby.
When seed is string, use all bits for MT rand state
initialization.
Example usage: mt_srand(random_bytes(2000));*** Get random number from state resource ***
intmt_rand()
// System state
int mt_rand(resource $state) // Specified user state
int mt_rand(int $min , int $max [,resource $state]) // Specified user
state
if $state is passedWhile we could retrofit this into the existing API, it would be cleaner
and friendlier to provide a new one based on objects.
Object based implementation is nicer. I agree.
I like multi paradigm programming also. We should provide API that users
can adopt with
minimal cost. IMHO. Therefore, I would like to provide working PRNG for
both procedural
and object based. I wrote new RFC that fixes issues discussed here.
https://wiki.php.net/rfc/improve_predictable_prng_random
I used RandomState object so that OO based Random API can use it seamlessly
in the future.
Comments are appreciated!
Regards,
--
Yasuo Ohgaki
yohgaki@ohgaki.net
Christoph M. Becker wrote:
Just a quick idea:
<?php
class PNRG {
public function __construct($seed = null) {…}
public function get() {…}
}I've long favoured an API along these lines. One size does not fit all,
you need two APIs for (non-crytographic) random numbers:
- automatically-seeded, non-reproducible numbers (a global function like
rand()
)- manually-seeded, reproducible number sequences (objects)
Currently we mix these two, and it's a mess. The easy solution would be
a random number-generating object like you propose, to cover the second
use-case. We could also introduce a non-manually-seedable global PRNG
also, if desired. Perhaps as a static method of that class.One thought: it'd be nice if you had two different methods, one that
mutates in places, and one that doesn't, i.e.:$prng1 = new PRNG(SEED);
[$randomNumber, $prng2] = $prng2->getWithNewPRNG();v.s.:
$prng = new PRNG(SEED);
$randomNumber = $prng->get();
$randomNumber2 = $prng->get();
Thanks, Andrea! I like all your suggestions, and I'd be happy to see a
respective RFC – unfortunately, I won't have time to do this myself in
the near future.
--
Christoph M. Becker
Hi Christoph,
On Mon, Jan 30, 2017 at 10:20 PM, Christoph M. Becker cmbecker69@gmx.de
wrote:
Just a quick idea:
<?php
class PNRG {
public function __construct($seed = null) {…}
public function get() {…}
}
Object based implementation is a lot cleaner. I'm willing to write one
but not now... I would like to make current API work better first.
If anyone could write OO based predictable PRNG, I appreciate a lot!
Regards,
--
Yasuo Ohgaki
yohgaki@ohgaki.net