1c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org// Copyright 2013 the V8 project authors. All rights reserved.
23484964a86451e86dcf04be9bd8c0d76ee04f081rossberg@chromium.org// Use of this source code is governed by a BSD-style license that can be
33484964a86451e86dcf04be9bd8c0d76ee04f081rossberg@chromium.org// found in the LICENSE file.
4c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org
55de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org#include "src/base/utils/random-number-generator.h"
6c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org
7e31286d471eb2e656a1809383fa16b76053dd673machenbach@chromium.org#include <stdio.h>
8e31286d471eb2e656a1809383fa16b76053dd673machenbach@chromium.org#include <stdlib.h>
9c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org
103ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org#include <new>
113ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
123ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org#include "src/base/macros.h"
135de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org#include "src/base/platform/mutex.h"
145de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org#include "src/base/platform/time.h"
15c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org
16c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.orgnamespace v8 {
175de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.orgnamespace base {
18c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org
19c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.orgstatic LazyMutex entropy_mutex = LAZY_MUTEX_INITIALIZER;
20c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.orgstatic RandomNumberGenerator::EntropySource entropy_source = NULL;
21c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org
22c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org
23c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org// static
24c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.orgvoid RandomNumberGenerator::SetEntropySource(EntropySource source) {
25c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org  LockGuard<Mutex> lock_guard(entropy_mutex.Pointer());
26c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org  entropy_source = source;
27c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org}
28c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org
29c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org
30c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.orgRandomNumberGenerator::RandomNumberGenerator() {
31c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org  // Check if embedder supplied an entropy source.
32c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org  { LockGuard<Mutex> lock_guard(entropy_mutex.Pointer());
33c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org    if (entropy_source != NULL) {
34c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org      int64_t seed;
35c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org      if (entropy_source(reinterpret_cast<unsigned char*>(&seed),
36c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org                         sizeof(seed))) {
37c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org        SetSeed(seed);
38c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org        return;
39c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org      }
40c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org    }
41c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org  }
42c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org
433d079fe881245e49c7ba803b54b4fe6d4b46113cmachenbach@chromium.org#if V8_OS_CYGWIN || V8_OS_WIN
443d079fe881245e49c7ba803b54b4fe6d4b46113cmachenbach@chromium.org  // Use rand_s() to gather entropy on Windows. See:
453d079fe881245e49c7ba803b54b4fe6d4b46113cmachenbach@chromium.org  // https://code.google.com/p/v8/issues/detail?id=2905
463d079fe881245e49c7ba803b54b4fe6d4b46113cmachenbach@chromium.org  unsigned first_half, second_half;
473d079fe881245e49c7ba803b54b4fe6d4b46113cmachenbach@chromium.org  errno_t result = rand_s(&first_half);
48e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org  DCHECK_EQ(0, result);
493d079fe881245e49c7ba803b54b4fe6d4b46113cmachenbach@chromium.org  result = rand_s(&second_half);
50e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org  DCHECK_EQ(0, result);
513d079fe881245e49c7ba803b54b4fe6d4b46113cmachenbach@chromium.org  SetSeed((static_cast<int64_t>(first_half) << 32) + second_half);
523d079fe881245e49c7ba803b54b4fe6d4b46113cmachenbach@chromium.org#else
53c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org  // Gather entropy from /dev/urandom if available.
54c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org  FILE* fp = fopen("/dev/urandom", "rb");
55c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org  if (fp != NULL) {
56c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org    int64_t seed;
57c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org    size_t n = fread(&seed, sizeof(seed), 1, fp);
58c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org    fclose(fp);
59c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org    if (n == 1) {
60c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org      SetSeed(seed);
61c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org      return;
62c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org    }
63c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org  }
64c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org
65c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org  // We cannot assume that random() or rand() were seeded
66c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org  // properly, so instead of relying on random() or rand(),
67c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org  // we just seed our PRNG using timing data as fallback.
683d079fe881245e49c7ba803b54b4fe6d4b46113cmachenbach@chromium.org  // This is weak entropy, but it's sufficient, because
693d079fe881245e49c7ba803b54b4fe6d4b46113cmachenbach@chromium.org  // it is the responsibility of the embedder to install
703d079fe881245e49c7ba803b54b4fe6d4b46113cmachenbach@chromium.org  // an entropy source using v8::V8::SetEntropySource(),
713d079fe881245e49c7ba803b54b4fe6d4b46113cmachenbach@chromium.org  // which provides reasonable entropy, see:
723d079fe881245e49c7ba803b54b4fe6d4b46113cmachenbach@chromium.org  // https://code.google.com/p/v8/issues/detail?id=2905
73c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org  int64_t seed = Time::NowFromSystemTime().ToInternalValue() << 24;
74d8a3a149cb9dac7437e264a2fe50f680418c3a45jkummerow@chromium.org  seed ^= TimeTicks::HighResolutionNow().ToInternalValue() << 16;
75c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org  seed ^= TimeTicks::Now().ToInternalValue() << 8;
76c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org  SetSeed(seed);
773d079fe881245e49c7ba803b54b4fe6d4b46113cmachenbach@chromium.org#endif  // V8_OS_CYGWIN || V8_OS_WIN
78c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org}
79c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org
80c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org
81c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.orgint RandomNumberGenerator::NextInt(int max) {
82e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org  DCHECK_LE(0, max);
83c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org
84c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org  // Fast path if max is a power of 2.
853ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  if (IS_POWER_OF_TWO(max)) {
86c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org    return static_cast<int>((max * static_cast<int64_t>(Next(31))) >> 31);
87c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org  }
88c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org
89c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org  while (true) {
90c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org    int rnd = Next(31);
91c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org    int val = rnd % max;
92c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org    if (rnd - val + (max - 1) >= 0) {
93c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org      return val;
94c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org    }
95c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org  }
96c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org}
97c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org
98c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org
99c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.orgdouble RandomNumberGenerator::NextDouble() {
100c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org  return ((static_cast<int64_t>(Next(26)) << 27) + Next(27)) /
101c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org      static_cast<double>(static_cast<int64_t>(1) << 53);
102c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org}
103c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org
104c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org
105c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.orgvoid RandomNumberGenerator::NextBytes(void* buffer, size_t buflen) {
106c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org  for (size_t n = 0; n < buflen; ++n) {
107c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org    static_cast<uint8_t*>(buffer)[n] = static_cast<uint8_t>(Next(8));
108c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org  }
109c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org}
110c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org
111c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org
112c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.orgint RandomNumberGenerator::Next(int bits) {
113e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org  DCHECK_LT(0, bits);
114e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org  DCHECK_GE(32, bits);
11570d11c79c7833b9ab1ee185625fcf707b9480a40machenbach@chromium.org  // Do unsigned multiplication, which has the intended modulo semantics, while
11670d11c79c7833b9ab1ee185625fcf707b9480a40machenbach@chromium.org  // signed multiplication would expose undefined behavior.
11770d11c79c7833b9ab1ee185625fcf707b9480a40machenbach@chromium.org  uint64_t product = static_cast<uint64_t>(seed_) * kMultiplier;
11870d11c79c7833b9ab1ee185625fcf707b9480a40machenbach@chromium.org  // Assigning a uint64_t to an int64_t is implementation defined, but this
11970d11c79c7833b9ab1ee185625fcf707b9480a40machenbach@chromium.org  // should be OK. Use a static_cast to explicitly state that we know what we're
12070d11c79c7833b9ab1ee185625fcf707b9480a40machenbach@chromium.org  // doing. (Famous last words...)
12170d11c79c7833b9ab1ee185625fcf707b9480a40machenbach@chromium.org  int64_t seed = static_cast<int64_t>((product + kAddend) & kMask);
122c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org  seed_ = seed;
123c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org  return static_cast<int>(seed >> (48 - bits));
124c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org}
125c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org
126c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org
127c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.orgvoid RandomNumberGenerator::SetSeed(int64_t seed) {
128a2c0c1516848536a514b3178d2c040b7df0ceb5bmachenbach@chromium.org  initial_seed_ = seed;
129c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org  seed_ = (seed ^ kMultiplier) & kMask;
130c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org}
131c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org
1325de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org} }  // namespace v8::base
133