File: Random.pmod

package info (click to toggle)
pike8.0 8.0.1956-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 60,580 kB
  • sloc: ansic: 259,734; xml: 36,320; makefile: 3,748; sh: 1,713; cpp: 1,349; awk: 1,036; lisp: 655; javascript: 468; asm: 242; objc: 240; pascal: 157; sed: 34
file content (92 lines) | stat: -rw-r--r-- 3,187 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#pike __REAL_VERSION__
#pragma strict_types
#require constant(Nettle.Fortuna)

//! This module contains a pseudo random number generator (PRNG)
//! designed to give you the best possible random number generation.
//! The current design is based on the Fortuna PRNG, but uses the
//! system random source as input.

protected class RND
{
  inherit Nettle.Fortuna;

  protected function(int:string(8bit)) source;

  protected void create()
  {
#if constant(Nettle.NT)
    source = Nettle.NT.CryptContext(0, 0, Nettle.NT.PROV_RSA_FULL,
                                    Nettle.NT.CRYPT_VERIFYCONTEXT )->read;
#else
    source = Stdio.File("/dev/urandom")->read;
#endif

    // random_string() is either seeded with time and PID in the
    // master, or outputs data from RDRND. Both of these are
    // (partially) independent from /dev/urandom, which gives some
    // protection against a /dev/urandom exploit.
    reseed(source(32)+predef::random_string(32));
  }

  System.Timer last_seed = System.Timer();
  void reseed(string(8bit)data)
  {
    last_seed->get();
    ::reseed(data);
  }

  string(8bit) random_string(int len)
  {
    // The original Fortuna design has an entropy pool reseeding the
    // generator when enough external events have been collected, but
    // not more often than every 100 ms. Since we are pulling entropy
    // rather than having it pushed, we do it if more than 100 ms has
    // passed since last call.
    //
    // An alternative here would be to asynchronously pull data every
    // 100 ms to hide entropy consumption from an external obserer,
    // but that requires a backend, and is likely a waste of effort.
    if( last_seed->peek()>0.1 )
      reseed(source(32));
    return ::random_string(len);
  }
}

protected RND rnd_obj = RND();
protected function(int:string(8bit)) rnd_func = rnd_obj->random_string;

//! Returns a string of length @[len] with random content. The content
//! is generated by a Fortuna random generator that is updated with
//! output from /dev/urandom on UNIX and CryptGenRandom on NT.
string(8bit) random_string(int len) {
  return rnd_func(len);
}

__deprecated__ string(8bit) blocking_random_string(int len)
{
  return rnd_func(len);
}

//! Returns a @[Gmp.mpz] object with a random value between @expr{0@}
//! and @[top]. Uses @[random_string].
Gmp.mpz random(int top) {
  return [object(Gmp.mpz)]( Gmp.mpz(rnd_func( (int)ceil( log((float)top)/
                                                         log(2.0) ) ),
				    256) % top);
}

//! Inject additional entropy into the random generator. One possible
//! use is to persist random data between executions of an
//! application. The internal state is approximately 256 bits, so
//! storing 32 bytes from @[random_string()] at shutdown and injecting
//! them through @[add_entropy()] agan at startup should carry over
//! the entropy. Note that this doesn't affect the independent
//! initialization that happens in the generator at startup, so the
//! output sequence will be different than if the application had
//! continued uninterrupted.
//! @param data
//!   The random string.
void add_entropy(string(8bit) data) {
  rnd_obj->reseed(data);
}