in reply to Legacy code uses "srand()" .. how to avoid losing entropy?

Could you override the built in srand and rand functions with one of your own that checks who the caller is, and chooses which source of randomness to use based on the caller.

For example, you could arrange things so that the parts of your code that need secure cryptographic randomness get bytes from Crypt::Random, while the rest of your code gets standard rand data, that has been tainted by all the calls to srand.

Alternatively if the legacy code that is calling srand far to often has little actual need for randomness, then you could consider writing a crude random number generator for its use, as returning standard rand data to all other callers.

Your crude random number generator could be as simple as a few thousand pre-generated random numbers in a file or database table, where repeated calls just increment through the list, and the value passed in to srand is the fraction through the file to start from.

  • Comment on Re: Legacy code uses "srand()" .. how to avoid losing entropy?

Replies are listed 'Best First'.
Re^2: Legacy code uses "srand()" .. how to avoid losing entropy?
by moritz (Cardinal) on May 03, 2011 at 13:15 UTC
    Could you override the built in srand and rand functions with one of your own that checks who the caller is, and chooses which source of randomness to use based on the caller.

    This sounds like a guide "how to make my code highly interconnected, and harder to reuse".

    The point of encapsulation is that code should not care where it's called from.

    Changing the code that reads non-deterministic pseudo random numbers to use Math::Random::MT or something similar would be much saner.

      Since I can’t rely upon “that version of Perl,” my present train(-wreck) of thought is to either bring in a separate random-number object for this purpose, or to do the “re-seed with a random number picked just before re-seeding” strategy described earlier.   (It is good to know that Perl is getting this “return the previous seed value” capability, as many other languages do have it, but it’s too late for this (cr)app.)

      Thanks for your inputs, one and all.   Now, back to the coal-mines.

        It sounds like you're getting wrapped up in a few problems:

        1. You've got code that depends on a stable list of pseudo-random numbers.
        2. The pseudo-random numbers aren't random enough and the results are skewed.
        3. There are calls to srand($n) throughout the program.
        4. You want to capture the "state" of the RNG at various points.

        So tackle these problems separately. As a kludge, you should be able to make the program run as-is, but with better results.

        1. Follow JavaFan's (and others') suggestion and pre-generate a list of better random numbers. There are more elegant ways to do this, but for the sake of the concept, store a list of a million pre-generated random numbers in the __DATA__ section of the code, pull them up from <DATA> and put them in a global array @RAND, accessed with a global $COUNTER. External sources might complicate matters at this stage, which is why I suggest throwing it in the code.
        2. Then borrow Tye's suggestion to override srand and rand for your purposes:
          BEGIN { our @RAND = (); our $COUNTER = 0; for (<DATA>) { $_ += 0; push @RAND, $_; } *CORE::GLOBAL::srand = sub(;$){ $COUNTER = 0 }; *CORE::GLOBAL::rand = sub(){ return $RAND[$COUNTER++] }; }
        3. Now srand($n) will ignore $n, but will reset $COUNTER so the sequence can start again. And rand will act as expected, but will return the number from @RAND rather than generate it on the fly. From the perspective of the rest of the code, this should be transparent, obviating the need for global changes (as in search/replace) to the code.
        4. To capture the state of the "RNG" (now a list), simply capture $COUNTER to pick up where you left off later.

        --marmot