3

If I generate a number using: $num=rand(0, 1000);, is it possible to guess what the next number will be?

Would I need to record a certain number of previously generated numbers? And how would I go about working out the next number?

Additional Information:

From random.org -

PHP Rand() imagePHP Rand() image

True random imageTrue random image

Thanks to Derobert's answer:

I used the method posted in his answer to generate the following image

openssl image OpenSSL image

I used the following code to do this:

// Requires the GD Library
header("Content-type: image/png");
$im = imagecreatetruecolor(512, 512)
    or die("Cannot Initialize new GD image stream");
$white = imagecolorallocate($im, 255, 255, 255);
for ($y=0; $y<512; $y++) {
    for ($x=0; $x<512; $x++) {
        if (random() === 1) {
            imagesetpixel($im, $x, $y, $white);
        }
    }
}       
imagepng($im);
imagedestroy($im);

function random(){
    $num = unpack('L', openssl_random_pseudo_bytes(4, $is_strong));


    if (!$is_strong) {
        echo 'error';
    }
    else{
        $lastDigit=substr($num[1], strlen($num[1])-1, 1);
        if($lastDigit<=4) return 0;
        return 1;
    }
}

Credits to Bo

Drahcir
  • 11,772
  • 24
  • 86
  • 128
  • 0_0 You do know that `rand` is an abbreviation for `random`, right? –  Jan 12 '12 at 16:20
  • 3
    yes, by calling rand(0, 1000) again – goto-bus-stop Jan 12 '12 at 16:21
  • It's not possible in practice, only in theory. – N.B. Jan 12 '12 at 16:23
  • @JackManey: See the images I posted and read some on random.org, rand() is not truely random – Drahcir Jan 12 '12 at 16:27
  • 1
    So is your question actually a disguised complaint about the randomness? Or do you want a reversal function for an actual algorithm? (Then tell which.) – mario Jan 12 '12 at 16:31
  • @mario: No, not complaining, I've been aware of this for a long time and it stands to reason. But I'd like to learn more about it and yes I'd like a reversal function. – Drahcir Jan 12 '12 at 16:39
  • @N.B.: You're greatly mistaken. The commonly used fast PRNGs (as opposed to the much slower cryptographic ones) are very simple linear math. Finding their state from their output is fairly easy. Many of their periods are even short enough that you can just brute force it! – derobert Jan 12 '12 at 16:40
  • Again, it depends on the algorithm used. The picture is probably `rand(0,1)` where it's not difficult to work out, but also for Windows' libc, which we don't have the source for. So need to find a specific implementation and post that, as PHPs `rand()` function chains to no less than four different variants. – mario Jan 12 '12 at 16:43
  • @derobert - that's why I said it's impossible in practice. Better phrase would be "not applicable". It also makes no sense to do it, you can obtain the next number by calling the function again. The actual problem should be phrased in such a way that you need to know what number would a remote computer give at a given time interval. Then you have enough input to try and create a function that'd calculate another computer's next in line number for a given time in space. Then again, we come to the question which is "What's the point" :) – N.B. Jan 12 '12 at 16:58
  • @N.B. I guess we agree then...? I thought it was obvious that the OP means can someone without access to the seed guess what the next number is (e.g., OP is implementing a game of chance, and wants to know if its possible to cheat by guessing `rand` output). But possibly I'm not understanding what you're saying, as I can't fathom how my pointing out that its fairly easy to do with a few outputs is at all "impossible in practice". One or both of us is talking past the other. – derobert Jan 12 '12 at 17:07
  • @N.B.: Yes Derobert is correct - It's obvious that I meant without knowing the seed and no point doing it from the same computer. – Drahcir Jan 12 '12 at 17:16
  • @derobert - I agree with what you said entirely. Reason I said it's not applicable is because it'll require some effort to do so. Have you ever tried to do such a thing when you need to guess what rand number the other machine would output? It's easy if you take some normal time intervals, but to create it for a system for which you don't know the actual time when `rand` would be invoked - not so easy. Not impossible, but it's not something you'll enjoy cracking (well, at least I wouldn't). Therefore, cheating in a game based on guessing output of `rand` = not applicable :) – N.B. Jan 12 '12 at 17:21

3 Answers3

5

Yes, it's possible, php's rand is apparently just using the underlying C library's rand, which is a pseudo-random number generator.

How much output you'd need to observe depends on the exact algorithm used by the C library, which varies from platform to platform (and sometimes even version to version). The number of outputs you need to observer is probably fewer than ten.

If your C library is particularly bad, you could try mt_rand which uses the Mersenne Twister algorithm. Note that this is still predictable.

If you need unpredictable random numbers, then use openssl_random_pseudo_bytes and make sure crypto_strong is true afterwards. Note that it returns a binary string; to get a number you'll have to use something like unpack:

$num = unpack('L', openssl_random_bytes(4, $is_strong));
if (!$is_strong) {
    ... // handle error
}

Also note that will return a number between 0 and 2³²=4294967296, not 0–1000, so you'll need to deal with that.

derobert
  • 49,731
  • 15
  • 94
  • 124
  • +1, Thanks for the function. I have edited my question and included an image generated with your function. – Drahcir Jan 12 '12 at 17:12
  • @RichardLivingston: Your random function is biased; see [Random number in range 0 to n](http://stackoverflow.com/q/1972252/27727) for how to do it (though, in this case, you can just check one bit, which it is evenly partitioned into, so you don't need the loop and all). Also, asking it for 4 bytes when you only want 1 bit is rather inefficient. But for quick and dirty code, it produces a nice image :-P – derobert Jan 12 '12 at 17:24
0

PHP will generate the same sequence of numbers for the same seed. So you would have to find out the seed and then log the numbers:

php > srand(1);
php > echo rand(1,100);
85
php > echo rand(1,100);
40
php > srand(1);
php > echo rand(1,100);
85
php > echo rand(1,100);
40

Or you have a look at the PHP source!

TimWolla
  • 31,849
  • 8
  • 63
  • 96
0

rand() generates a pseudo-random sequence. If you would like a predictable (read reproducable) sequence, you need to seed the random generator using srand().

Try running the below script twice in a row:

<?php
$seed = 2;
srand($seed);
foreach(range(1, 100) as $i) var_dump(rand(0, 100));
Jakub
  • 20,418
  • 8
  • 65
  • 92
Kenaniah
  • 5,171
  • 24
  • 27