OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/common/metrics/entropy_provider.h" | |
6 | |
7 #include <algorithm> | |
8 #include <limits> | |
9 #include <vector> | |
10 | |
11 #include "base/logging.h" | |
12 #include "base/rand_util.h" | |
13 #include "base/sha1.h" | |
14 #include "base/sys_byteorder.h" | |
15 | |
16 namespace internal { | |
17 | |
18 SeededRandGenerator::SeededRandGenerator(uint32 seed) { | |
19 mersenne_twister_.init_genrand(seed); | |
20 } | |
21 | |
22 SeededRandGenerator::~SeededRandGenerator() { | |
23 } | |
24 | |
25 uint32 SeededRandGenerator::operator()(uint32 range) { | |
26 // Based on base::RandGenerator(). | |
27 DCHECK_GT(range, 0u); | |
28 | |
29 // We must discard random results above this number, as they would | |
30 // make the random generator non-uniform (consider e.g. if | |
31 // MAX_UINT64 was 7 and |range| was 5, then a result of 1 would be twice | |
32 // as likely as a result of 3 or 4). | |
SteveT
2012/08/16 20:55:42
nit: Looks like you can make better use of the 80
Alexei Svitkine (slow)
2012/08/16 21:27:11
This comment (and code) is copied out of base::Ran
| |
33 uint32 max_acceptable_value = | |
34 (std::numeric_limits<uint32>::max() / range) * range - 1; | |
35 | |
36 uint32 value; | |
37 do { | |
38 value = mersenne_twister_.genrand_int32(); | |
39 } while (value > max_acceptable_value); | |
40 | |
41 return value % range; | |
42 } | |
43 | |
44 uint32 HashName(const std::string& name) { | |
45 // SHA-1 is designed to produce a uniformly random spread in its output space, | |
46 // even for nearly-identical inputs. | |
47 unsigned char sha1_hash[base::kSHA1Length]; | |
48 base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(name.c_str()), | |
49 name.size(), | |
50 sha1_hash); | |
51 | |
52 uint32 bits; | |
53 COMPILE_ASSERT(sizeof(bits) < sizeof(sha1_hash), need_more_data); | |
54 memcpy(&bits, sha1_hash, sizeof(bits)); | |
55 | |
56 return base::ByteSwapToLE32(bits); | |
57 } | |
58 | |
59 } // namespace internal | |
60 | |
61 SHA1EntropyProvider::SHA1EntropyProvider(const std::string& entropy_source) | |
62 : entropy_source_(entropy_source) { | |
63 } | |
64 | |
65 SHA1EntropyProvider::~SHA1EntropyProvider() { | |
66 } | |
67 | |
68 double SHA1EntropyProvider::GetEntropyForTrial(const std::string& trial_name) { | |
69 // SHA-1 is designed to produce a uniformly random spread in its output space, | |
70 // even for nearly-identical inputs, so it helps massage whatever client_id | |
71 // and trial_name we get into something with a uniform distribution, which | |
72 // is desirable so that we don't skew any part of the 0-100% spectrum. | |
73 std::string input(entropy_source_ + trial_name); | |
74 unsigned char sha1_hash[base::kSHA1Length]; | |
75 base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(input.c_str()), | |
76 input.size(), | |
77 sha1_hash); | |
78 | |
79 uint64 bits; | |
80 COMPILE_ASSERT(sizeof(bits) < sizeof(sha1_hash), need_more_data); | |
81 memcpy(&bits, sha1_hash, sizeof(bits)); | |
82 bits = base::ByteSwapToLE64(bits); | |
83 | |
84 return base::BitsToOpenEndedUnitInterval(bits); | |
85 } | |
86 | |
87 PermutedEntropyProvider::PermutedEntropyProvider( | |
88 uint16 low_entropy_source, | |
89 size_t low_entropy_source_max) | |
90 : low_entropy_source_(low_entropy_source), | |
91 low_entropy_source_max_(low_entropy_source_max) { | |
92 } | |
93 | |
94 PermutedEntropyProvider::~PermutedEntropyProvider() { | |
95 } | |
96 | |
97 double PermutedEntropyProvider::GetEntropyForTrial( | |
98 const std::string& trial_name) { | |
99 std::vector<uint16> mapping(low_entropy_source_max_); | |
100 for (size_t i = 0; i < mapping.size(); ++i) | |
101 mapping[i] = static_cast<uint16>(i); | |
102 | |
103 internal::SeededRandGenerator generator(internal::HashName(trial_name)); | |
104 std::random_shuffle(mapping.begin(), mapping.end(), generator); | |
105 | |
106 return mapping[low_entropy_source_] / | |
107 static_cast<double>(low_entropy_source_max_); | |
108 } | |
OLD | NEW |