blob: 6db2820ec707cc2ffa33e63588fda6390f72d379 [file] [log] [blame]
Austin Schuh36244a12019-09-21 17:52:38 -07001// 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
35namespace {
36
37using testing::Each;
38using testing::ElementsAre;
39using testing::Eq;
40using testing::Ne;
41using testing::Pointwise;
42
43TEST(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
54TEST(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
67TEST(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
76TEST(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
90TEST(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
105TEST(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
115TEST(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
131TEST(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
152TEST(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
177TEST(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