Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Thu, 23 Jun 2011 15:25:17 +0200
From: Szabolcs Nagy <nsz@...t70.net>
To: musl@...ts.openwall.com
Subject: Re: Completeness status of musl

* Rich Felker <dalias@...ifal.cx> [2011-06-23 02:54:52 -0400]:

> On Tue, Jun 21, 2011 at 03:46:40AM +0200, Szabolcs Nagy wrote:
> > * Rich Felker <dalias@...ifal.cx> [2011-06-08 19:58:10 -0400]:
> > > 
> > > Importing external code, with major cleanups or rewrite:
> > > - PRNG (random)
> > 
> > i looked into this one
> > these functions are rather useless
> > imho the posix api definition is insane
> > http://pubs.opengroup.org/onlinepubs/9699919799/functions/random.html
> > 
> > i wrote something anyway
> > see comments in the code:
> > http://port70.net/~nsz/musl/prng
> 
> I like this. A couple questions/requests:
> 
> 1. Is this simple code really equivalent (aside from the missing
> non-default-size code) to the ugly BSD code that's 100x bigger and
> full of undefined behavior? :)
> 

the historical bsd implementation used another lcg
for both the <32byte statebuffer and seeding

"modern" implementations seems to use the
 x = (7^5 * x) mod (2^31 - 1)
park-miller generator for seeding
(it makes the generator less predictable,
with the lcg everything is mod 2^k so
the numbers 'linearly depend' on the seed)
(glibc freebsd openbsd.. all use the same code here)
(they use overflowing signed ints and signed >>1 for whatever reason)
(they discard the first 10*n rands which i forgot to do)

(freebsd seems to use the park-miller generator even for
random() in case of small state buffer, which is bad as it
will produce uniform random in [0,2^31-2] not in [0,2^31-1])

i used lcg seeding for simplicity
the lcg seeding is bad, but the generator
does not have good statistical properties
and the seeding method won't change that..

now i made all the compatibility changes (attached)
the following produces identical output with glibc vs my code:
#include <stdio.h>
#include <stdlib.h>
int main() {
        char s[256];
        int i,j;
        for (j = 8; j <= 256; j*=2) {
                initstate(1, s, j);
                for (i = 0; i < 10; i++)
                        printf("%d %d %ld\n", j, i, random());
        }
        return 0;
}

(if compatibility does not matter then a 64bit lcg
could do the same job without much fuss:
 static unsigned long long init[] = {1};
 unsigned long long *x = init;
 long random(void){
    *x = (6364136223846793005* *x + 1442695040888963407);
    return *x >> 33;
 }
etc)

> 2. If you'd like me to include this in musl, can you please license it
> (either LGPL v2.1+ or any LGPL-compatible/less-restrictive license
> such as BSD).
> 

ok
license is
"permission to use, copy, modify, and/or distribute this code
for any purpose with or without fee is hereby granted.
there is no warranty."

so feel free to alter the code
eg the parkmiller code might be better to do with uint64 multiplication
instead of the div/mod hack to avoid overflow:
 return (unsigned long long)16807*x % 0x7fffffff;

> 3. For future code contributions, please attach the code/patches to
> the email rather than just including a link. That way the code being
> referred to/discussed is visible even if the version on the website
> changes or the website it taken down.
> 

ok

View attachment "random.c" of type "text/x-csrc" (1919 bytes)

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.