1 // Copyright 2017 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "absl/random/internal/seed_material.h"
16
17 #include <bitset>
18 #include <cstdlib>
19 #include <cstring>
20 #include <random>
21
22 #include "gmock/gmock.h"
23 #include "gtest/gtest.h"
24
25 #ifdef __ANDROID__
26 // Android assert messages only go to system log, so death tests cannot inspect
27 // the message for matching.
28 #define ABSL_EXPECT_DEATH_IF_SUPPORTED(statement, regex) \
29 EXPECT_DEATH_IF_SUPPORTED(statement, ".*")
30 #else
31 #define ABSL_EXPECT_DEATH_IF_SUPPORTED(statement, regex) \
32 EXPECT_DEATH_IF_SUPPORTED(statement, regex)
33 #endif
34
35 namespace {
36
37 using testing::Each;
38 using testing::ElementsAre;
39 using testing::Eq;
40 using testing::Ne;
41 using testing::Pointwise;
42
TEST(SeedBitsToBlocks,VerifyCases)43 TEST(SeedBitsToBlocks, VerifyCases) {
44 EXPECT_EQ(0, absl::random_internal::SeedBitsToBlocks(0));
45 EXPECT_EQ(1, absl::random_internal::SeedBitsToBlocks(1));
46 EXPECT_EQ(1, absl::random_internal::SeedBitsToBlocks(31));
47 EXPECT_EQ(1, absl::random_internal::SeedBitsToBlocks(32));
48 EXPECT_EQ(2, absl::random_internal::SeedBitsToBlocks(33));
49 EXPECT_EQ(4, absl::random_internal::SeedBitsToBlocks(127));
50 EXPECT_EQ(4, absl::random_internal::SeedBitsToBlocks(128));
51 EXPECT_EQ(5, absl::random_internal::SeedBitsToBlocks(129));
52 }
53
TEST(ReadSeedMaterialFromOSEntropy,SuccessiveReadsAreDistinct)54 TEST(ReadSeedMaterialFromOSEntropy, SuccessiveReadsAreDistinct) {
55 constexpr size_t kSeedMaterialSize = 64;
56 uint32_t seed_material_1[kSeedMaterialSize] = {};
57 uint32_t seed_material_2[kSeedMaterialSize] = {};
58
59 EXPECT_TRUE(absl::random_internal::ReadSeedMaterialFromOSEntropy(
60 absl::Span<uint32_t>(seed_material_1, kSeedMaterialSize)));
61 EXPECT_TRUE(absl::random_internal::ReadSeedMaterialFromOSEntropy(
62 absl::Span<uint32_t>(seed_material_2, kSeedMaterialSize)));
63
64 EXPECT_THAT(seed_material_1, Pointwise(Ne(), seed_material_2));
65 }
66
TEST(ReadSeedMaterialFromOSEntropy,ReadZeroBytesIsNoOp)67 TEST(ReadSeedMaterialFromOSEntropy, ReadZeroBytesIsNoOp) {
68 uint32_t seed_material[32] = {};
69 std::memset(seed_material, 0xAA, sizeof(seed_material));
70 EXPECT_TRUE(absl::random_internal::ReadSeedMaterialFromOSEntropy(
71 absl::Span<uint32_t>(seed_material, 0)));
72
73 EXPECT_THAT(seed_material, Each(Eq(0xAAAAAAAA)));
74 }
75
TEST(ReadSeedMaterialFromOSEntropy,NullPtrVectorArgument)76 TEST(ReadSeedMaterialFromOSEntropy, NullPtrVectorArgument) {
77 #ifdef NDEBUG
78 EXPECT_FALSE(absl::random_internal::ReadSeedMaterialFromOSEntropy(
79 absl::Span<uint32_t>(nullptr, 32)));
80 #else
81 bool result;
82 ABSL_EXPECT_DEATH_IF_SUPPORTED(
83 result = absl::random_internal::ReadSeedMaterialFromOSEntropy(
84 absl::Span<uint32_t>(nullptr, 32)),
85 "!= nullptr");
86 (void)result; // suppress unused-variable warning
87 #endif
88 }
89
TEST(ReadSeedMaterialFromURBG,SeedMaterialEqualsVariateSequence)90 TEST(ReadSeedMaterialFromURBG, SeedMaterialEqualsVariateSequence) {
91 // Two default-constructed instances of std::mt19937_64 are guaranteed to
92 // produce equal variate-sequences.
93 std::mt19937 urbg_1;
94 std::mt19937 urbg_2;
95 constexpr size_t kSeedMaterialSize = 1024;
96 uint32_t seed_material[kSeedMaterialSize] = {};
97
98 EXPECT_TRUE(absl::random_internal::ReadSeedMaterialFromURBG(
99 &urbg_1, absl::Span<uint32_t>(seed_material, kSeedMaterialSize)));
100 for (uint32_t seed : seed_material) {
101 EXPECT_EQ(seed, urbg_2());
102 }
103 }
104
TEST(ReadSeedMaterialFromURBG,ReadZeroBytesIsNoOp)105 TEST(ReadSeedMaterialFromURBG, ReadZeroBytesIsNoOp) {
106 std::mt19937_64 urbg;
107 uint32_t seed_material[32];
108 std::memset(seed_material, 0xAA, sizeof(seed_material));
109 EXPECT_TRUE(absl::random_internal::ReadSeedMaterialFromURBG(
110 &urbg, absl::Span<uint32_t>(seed_material, 0)));
111
112 EXPECT_THAT(seed_material, Each(Eq(0xAAAAAAAA)));
113 }
114
TEST(ReadSeedMaterialFromURBG,NullUrbgArgument)115 TEST(ReadSeedMaterialFromURBG, NullUrbgArgument) {
116 constexpr size_t kSeedMaterialSize = 32;
117 uint32_t seed_material[kSeedMaterialSize];
118 #ifdef NDEBUG
119 EXPECT_FALSE(absl::random_internal::ReadSeedMaterialFromURBG<std::mt19937_64>(
120 nullptr, absl::Span<uint32_t>(seed_material, kSeedMaterialSize)));
121 #else
122 bool result;
123 ABSL_EXPECT_DEATH_IF_SUPPORTED(
124 result = absl::random_internal::ReadSeedMaterialFromURBG<std::mt19937_64>(
125 nullptr, absl::Span<uint32_t>(seed_material, kSeedMaterialSize)),
126 "!= nullptr");
127 (void)result; // suppress unused-variable warning
128 #endif
129 }
130
TEST(ReadSeedMaterialFromURBG,NullPtrVectorArgument)131 TEST(ReadSeedMaterialFromURBG, NullPtrVectorArgument) {
132 std::mt19937_64 urbg;
133 #ifdef NDEBUG
134 EXPECT_FALSE(absl::random_internal::ReadSeedMaterialFromURBG(
135 &urbg, absl::Span<uint32_t>(nullptr, 32)));
136 #else
137 bool result;
138 ABSL_EXPECT_DEATH_IF_SUPPORTED(
139 result = absl::random_internal::ReadSeedMaterialFromURBG(
140 &urbg, absl::Span<uint32_t>(nullptr, 32)),
141 "!= nullptr");
142 (void)result; // suppress unused-variable warning
143 #endif
144 }
145
146 // The avalanche effect is a desirable cryptographic property of hashes in which
147 // changing a single bit in the input causes each bit of the output to be
148 // changed with probability near 50%.
149 //
150 // https://en.wikipedia.org/wiki/Avalanche_effect
151
TEST(MixSequenceIntoSeedMaterial,AvalancheEffectTestOneBitLong)152 TEST(MixSequenceIntoSeedMaterial, AvalancheEffectTestOneBitLong) {
153 std::vector<uint32_t> seed_material = {1, 2, 3, 4, 5, 6, 7, 8};
154
155 // For every 32-bit number with exactly one bit set, verify the avalanche
156 // effect holds. In order to reduce flakiness of tests, accept values
157 // anywhere in the range of 30%-70%.
158 for (uint32_t v = 1; v != 0; v <<= 1) {
159 std::vector<uint32_t> seed_material_copy = seed_material;
160 absl::random_internal::MixIntoSeedMaterial(
161 absl::Span<uint32_t>(&v, 1),
162 absl::Span<uint32_t>(seed_material_copy.data(),
163 seed_material_copy.size()));
164
165 uint32_t changed_bits = 0;
166 for (size_t i = 0; i < seed_material.size(); i++) {
167 std::bitset<sizeof(uint32_t) * 8> bitset(seed_material[i] ^
168 seed_material_copy[i]);
169 changed_bits += bitset.count();
170 }
171
172 EXPECT_LE(changed_bits, 0.7 * sizeof(uint32_t) * 8 * seed_material.size());
173 EXPECT_GE(changed_bits, 0.3 * sizeof(uint32_t) * 8 * seed_material.size());
174 }
175 }
176
TEST(MixSequenceIntoSeedMaterial,AvalancheEffectTestOneBitShort)177 TEST(MixSequenceIntoSeedMaterial, AvalancheEffectTestOneBitShort) {
178 std::vector<uint32_t> seed_material = {1};
179
180 // For every 32-bit number with exactly one bit set, verify the avalanche
181 // effect holds. In order to reduce flakiness of tests, accept values
182 // anywhere in the range of 30%-70%.
183 for (uint32_t v = 1; v != 0; v <<= 1) {
184 std::vector<uint32_t> seed_material_copy = seed_material;
185 absl::random_internal::MixIntoSeedMaterial(
186 absl::Span<uint32_t>(&v, 1),
187 absl::Span<uint32_t>(seed_material_copy.data(),
188 seed_material_copy.size()));
189
190 uint32_t changed_bits = 0;
191 for (size_t i = 0; i < seed_material.size(); i++) {
192 std::bitset<sizeof(uint32_t) * 8> bitset(seed_material[i] ^
193 seed_material_copy[i]);
194 changed_bits += bitset.count();
195 }
196
197 EXPECT_LE(changed_bits, 0.7 * sizeof(uint32_t) * 8 * seed_material.size());
198 EXPECT_GE(changed_bits, 0.3 * sizeof(uint32_t) * 8 * seed_material.size());
199 }
200 }
201
202 } // namespace
203