Skip Menu |

This queue is for tickets about the Math-Random CPAN distribution.

Report information
The Basics
Id: 48080
Status: open
Priority: 0/
Queue: Math-Random

People
Owner: Nobody in particular
Requestors: frequency [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: Wishlist
Broken in: 0.71
Fixed in: (no value)



Subject: Better Default Seeding
Hi: By default, you seed the module using localtime. In the modules I've written (currently on CPAN) dealing with random stuff, that's what I've done too. I just learned today that there is a Perl_seed variable we can use, which gets the seed of the currently executing thread, which is used internally (I guess) for seeding hashes and stuff. Ultimately it should prove to be a better default seed. I'm working on preparing a patch for Debian. There is a bug report on this, http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=537952 -- but I think the patch could be better, so I'll send the updated one after I'm done. Notably, the patch submitted by Don Armstrong does not ensure that we're running on Perl 5.8+, which is when these seeds were introduced.
Hi: I've written the following patch which seems to resolve the issue. Please consider applying it in your module: Description: Update seeding algorithm By default, this algorithm uses localtime to seed the random number generator, which provides poor randomness when Perl is executed many times sequentially. This patch replaces that with Don Armstrong's proposed solution, Perl_seed. See BTS#537952 for details. Origin: vendor Author: Jonathan Yu <frequency@cpan.org> Bug: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=537952 Bug-CPAN: https://rt.cpan.org/Ticket/Display.html?id=48080 Forwarded: yes --- a/Random.pm +++ b/Random.pm @@ -73,7 +73,7 @@ ### set seeds by default -salfph(scalar(localtime())); +salfph(get_seed() || scalar(localtime)); ##################################################################### # RANDOM DEVIATE GENERATORS # --- a/Random.xs +++ b/Random.xs @@ -11,6 +11,28 @@ #include "randlib.h" #include "helper.h" +#define PERL_VERSION_ATLEAST(a,b,c) \ + (PERL_REVISION > (a) \ + || (PERL_REVISION == (a) \ + && (PERL_VERSION > (b) \ + || (PERL_VERSION == (b) && PERL_SUBVERSION >= (c))))) + +#if PERL_VERSION_ATLEAST (5,8,1) +/* For whatever reason, the random seeds need to be in 1..2^30; the below will + * be uniformly distributed assuming the seed value is uniformly distributed. + * + * This approach isn't cryptographically secure. Consider using /dev/random + * or Math::TrulyRandom to get some real entropy. + */ +#define Perl_get_seed (long)(Perl_seed(aTHX) % 1073741824L) +#else +/* If we don't support seeds, return 0 so we can fall back to localtime for + * default seeding. There's a chance Perl_seed will return 0 and mask this, + * but in that case the data should still be "random enough" anyway. + */ +#define Perl_get_seed 0L +#endif /* Perl_seed */ + static int not_here(s) char *s; @@ -38,6 +60,12 @@ MODULE = Math::Random PACKAGE = Math::Random +long +get_seed() + CODE: + RETVAL = Perl_get_seed; + OUTPUT: + RETVAL double genbet (aa,bb) On Wed Jul 22 10:36:58 2009, FREQUENCY wrote: Show quoted text
> Hi: > > By default, you seed the module using localtime. In the modules I've > written (currently on CPAN) dealing with random stuff, that's what I've > done too. > > I just learned today that there is a Perl_seed variable we can use, > which gets the seed of the currently executing thread, which is used > internally (I guess) for seeding hashes and stuff. Ultimately it should > prove to be a better default seed. > > I'm working on preparing a patch for Debian. There is a bug report on > this, http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=537952 -- but I > think the patch could be better, so I'll send the updated one after I'm > done. > > Notably, the patch submitted by Don Armstrong does not ensure that we're > running on Perl 5.8+, which is when these seeds were introduced.
An alternate approach would be to use one of the good Perl random modules to get a seed in Random.pm and pass it to salfph() or setall(). That would mean no changes in Random.xs, and small changes in Random.pm. The downside is that you have to choose a module and that adds a dependency (and its chain). I would strongly recommend not mentioning or using Math::TrulyRandom. I'm biased, but I think Crypt::Random::Seed would work well, and I've tested it in the module using: use Crypt::Random::Seed; my $source = Crypt::Random::Seed->new(NonBlocking => 1); setall( map { $_ % 0x3FFFFFFF } $source->random_values(2) ); The entire point of the module is to provide a lightweight and flexible solution to this exact problem. It will use Win32, /dev/random, EDG, /dev/urandom as available, as well as a userspace fallback similar in concept to Math::TrulyRandom but without its critical errors. Total of 2 non-core modules (including itself). Since Math::Random isn't targeting strong crypto, Crypt::URandom is another good choice. It's very lightweight -- just the one module with no chain, and it supports Win32. Shouldn't be too hard to use calling setall(). Not as flexible as Crypt::Random::Seed, but you may not need the flexibility. Going up a layer, Bytes::Random::Secure would also work well. It offers some methods for generating nice null-terminated strings that would play well with salfph(): use Bytes::Random::Secure qw/random_bytes_base64/; salfph(random_bytes_base64(32)); or via setall like: use Bytes::Random::Secure; my $rnd = Bytes::Random::Secure->new(NonBlocking=>1); setall( $rnd->irand() % 0x3FFFFFFF, $rnd->irand() % 0x3FFFFFFF); Fairly light dependency chain -- total of 4 non-core modules. Math::Random::Secure and Crypt::Random::Secure are nice, but they have huge dependency chains (over 20 modules plus Moose). I made Crypt::Random::Seed just because I couldn't stand the dependency and runtime overheads. Some people like Data::Entropy, but I'm not a big fan. It does require some setup or it'll just use rand() by default. About 6 dependencies. I'm not seeing anything that uses the Win32 interfaces. You could also give thought to indicating non-blocking is acceptable, which would help on servers. I'll leave the /dev/random vs. /dev/urandom battle aside for now, but many of the modules support some mechanism for this: e.g. my $source = Crypt::Random::Seed->new(NonBlocking => 1); I suspect this is preferable for this module which is not targeted to strong crypto anyway.