tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

explicit_seed_seq_test.cc (7727B)


      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/explicit_seed_seq.h"
     16 
     17 #include <iterator>
     18 #include <random>
     19 #include <utility>
     20 
     21 #include "gmock/gmock.h"
     22 #include "gtest/gtest.h"
     23 #include "absl/random/seed_sequences.h"
     24 
     25 namespace {
     26 
     27 using ::absl::random_internal::ExplicitSeedSeq;
     28 
     29 template <typename Sseq>
     30 bool ConformsToInterface() {
     31  // Check that the SeedSequence can be default-constructed.
     32  {
     33    Sseq default_constructed_seq;
     34  }
     35  // Check that the SeedSequence can be constructed with two iterators.
     36  {
     37    uint32_t init_array[] = {1, 3, 5, 7, 9};
     38    Sseq iterator_constructed_seq(init_array, &init_array[5]);
     39  }
     40  // Check that the SeedSequence can be std::initializer_list-constructed.
     41  {
     42    Sseq list_constructed_seq = {1, 3, 5, 7, 9, 11, 13};
     43  }
     44  // Check that param() and size() return state provided to constructor.
     45  {
     46    uint32_t init_array[] = {1, 2, 3, 4, 5};
     47    Sseq seq(init_array, &init_array[ABSL_ARRAYSIZE(init_array)]);
     48    EXPECT_EQ(seq.size(), ABSL_ARRAYSIZE(init_array));
     49 
     50    uint32_t state_array[ABSL_ARRAYSIZE(init_array)];
     51    seq.param(state_array);
     52 
     53    for (int i = 0; i < ABSL_ARRAYSIZE(state_array); i++) {
     54      EXPECT_EQ(state_array[i], i + 1);
     55    }
     56  }
     57  // Check for presence of generate() method.
     58  {
     59    Sseq seq;
     60    uint32_t seeds[5];
     61 
     62    seq.generate(seeds, &seeds[ABSL_ARRAYSIZE(seeds)]);
     63  }
     64  return true;
     65 }
     66 }  // namespace
     67 
     68 TEST(SeedSequences, CheckInterfaces) {
     69  // Control case
     70  EXPECT_TRUE(ConformsToInterface<std::seed_seq>());
     71 
     72  // Abseil classes
     73  EXPECT_TRUE(ConformsToInterface<ExplicitSeedSeq>());
     74 }
     75 
     76 TEST(ExplicitSeedSeq, DefaultConstructorGeneratesZeros) {
     77  const size_t kNumBlocks = 128;
     78 
     79  uint32_t outputs[kNumBlocks];
     80  ExplicitSeedSeq seq;
     81  seq.generate(outputs, &outputs[kNumBlocks]);
     82 
     83  for (uint32_t& seed : outputs) {
     84    EXPECT_EQ(seed, 0);
     85  }
     86 }
     87 
     88 TEST(ExplicitSeeqSeq, SeedMaterialIsForwardedIdentically) {
     89  const size_t kNumBlocks = 128;
     90 
     91  uint32_t seed_material[kNumBlocks];
     92  std::random_device urandom{"/dev/urandom"};
     93  for (uint32_t& seed : seed_material) {
     94    seed = urandom();
     95  }
     96  ExplicitSeedSeq seq(seed_material, &seed_material[kNumBlocks]);
     97 
     98  // Check that output is same as seed-material provided to constructor.
     99  {
    100    const size_t kNumGenerated = kNumBlocks / 2;
    101    uint32_t outputs[kNumGenerated];
    102    seq.generate(outputs, &outputs[kNumGenerated]);
    103    for (size_t i = 0; i < kNumGenerated; i++) {
    104      EXPECT_EQ(outputs[i], seed_material[i]);
    105    }
    106  }
    107  // Check that SeedSequence is stateless between invocations: Despite the last
    108  // invocation of generate() only consuming half of the input-entropy, the same
    109  // entropy will be recycled for the next invocation.
    110  {
    111    const size_t kNumGenerated = kNumBlocks;
    112    uint32_t outputs[kNumGenerated];
    113    seq.generate(outputs, &outputs[kNumGenerated]);
    114    for (size_t i = 0; i < kNumGenerated; i++) {
    115      EXPECT_EQ(outputs[i], seed_material[i]);
    116    }
    117  }
    118  // Check that when more seed-material is asked for than is provided, nonzero
    119  // values are still written.
    120  {
    121    const size_t kNumGenerated = kNumBlocks * 2;
    122    uint32_t outputs[kNumGenerated];
    123    seq.generate(outputs, &outputs[kNumGenerated]);
    124    for (size_t i = 0; i < kNumGenerated; i++) {
    125      EXPECT_EQ(outputs[i], seed_material[i % kNumBlocks]);
    126    }
    127  }
    128 }
    129 
    130 TEST(ExplicitSeedSeq, CopyAndMoveConstructors) {
    131  using testing::Each;
    132  using testing::Eq;
    133  using testing::Not;
    134  using testing::Pointwise;
    135 
    136  uint32_t entropy[4];
    137  std::random_device urandom("/dev/urandom");
    138  for (uint32_t& entry : entropy) {
    139    entry = urandom();
    140  }
    141  ExplicitSeedSeq seq_from_entropy(std::begin(entropy), std::end(entropy));
    142  // Copy constructor.
    143  {
    144    ExplicitSeedSeq seq_copy(seq_from_entropy);
    145    EXPECT_EQ(seq_copy.size(), seq_from_entropy.size());
    146 
    147    std::vector<uint32_t> seeds_1(1000, 0);
    148    std::vector<uint32_t> seeds_2(1000, 1);
    149 
    150    seq_from_entropy.generate(seeds_1.begin(), seeds_1.end());
    151    seq_copy.generate(seeds_2.begin(), seeds_2.end());
    152 
    153    EXPECT_THAT(seeds_1, Pointwise(Eq(), seeds_2));
    154  }
    155  // Assignment operator.
    156  {
    157    for (uint32_t& entry : entropy) {
    158      entry = urandom();
    159    }
    160    ExplicitSeedSeq another_seq(std::begin(entropy), std::end(entropy));
    161 
    162    std::vector<uint32_t> seeds_1(1000, 0);
    163    std::vector<uint32_t> seeds_2(1000, 0);
    164 
    165    seq_from_entropy.generate(seeds_1.begin(), seeds_1.end());
    166    another_seq.generate(seeds_2.begin(), seeds_2.end());
    167 
    168    // Assert precondition: Sequences generated by seed-sequences are not equal.
    169    EXPECT_THAT(seeds_1, Not(Pointwise(Eq(), seeds_2)));
    170 
    171    // Apply the assignment-operator.
    172    // GCC 12 has a false-positive -Wstringop-overflow warning here.
    173 #if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(12, 0)
    174 #pragma GCC diagnostic push
    175 #pragma GCC diagnostic ignored "-Wstringop-overflow"
    176 #endif
    177    another_seq = seq_from_entropy;
    178 #if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(12, 0)
    179 #pragma GCC diagnostic pop
    180 #endif
    181 
    182    // Re-generate seeds.
    183    seq_from_entropy.generate(seeds_1.begin(), seeds_1.end());
    184    another_seq.generate(seeds_2.begin(), seeds_2.end());
    185 
    186    // Seeds generated by seed-sequences should now be equal.
    187    EXPECT_THAT(seeds_1, Pointwise(Eq(), seeds_2));
    188  }
    189  // Move constructor.
    190  {
    191    // Get seeds from seed-sequence constructed from entropy.
    192    std::vector<uint32_t> seeds_1(1000, 0);
    193    seq_from_entropy.generate(seeds_1.begin(), seeds_1.end());
    194 
    195    // Apply move-constructor move the sequence to another instance.
    196    absl::random_internal::ExplicitSeedSeq moved_seq(
    197        std::move(seq_from_entropy));
    198    std::vector<uint32_t> seeds_2(1000, 1);
    199    moved_seq.generate(seeds_2.begin(), seeds_2.end());
    200    // Verify that seeds produced by moved-instance are the same as original.
    201    EXPECT_THAT(seeds_1, Pointwise(Eq(), seeds_2));
    202 
    203    // Verify that the moved-from instance now behaves like a
    204    // default-constructed instance.
    205    EXPECT_EQ(seq_from_entropy.size(), 0);
    206    seq_from_entropy.generate(seeds_1.begin(), seeds_1.end());
    207    EXPECT_THAT(seeds_1, Each(Eq(0)));
    208  }
    209 }
    210 
    211 TEST(ExplicitSeedSeq, StdURBGGoldenTests) {
    212  // Verify that for std::- URBG instances the results are stable across
    213  // platforms (these should have deterministic output).
    214  {
    215    ExplicitSeedSeq seed_sequence{12, 34, 56};
    216    std::minstd_rand rng(seed_sequence);
    217 
    218    std::minstd_rand::result_type values[4] = {rng(), rng(), rng(), rng()};
    219    EXPECT_THAT(values,
    220                testing::ElementsAre(579252, 43785881, 464353103, 1501811174));
    221  }
    222 
    223  {
    224    ExplicitSeedSeq seed_sequence{12, 34, 56};
    225    std::mt19937 rng(seed_sequence);
    226 
    227    std::mt19937::result_type values[4] = {rng(), rng(), rng(), rng()};
    228    EXPECT_THAT(values, testing::ElementsAre(138416803, 151130212, 33817739,
    229                                             138416803));
    230  }
    231 
    232  {
    233    ExplicitSeedSeq seed_sequence{12, 34, 56};
    234    std::mt19937_64 rng(seed_sequence);
    235 
    236    std::mt19937_64::result_type values[4] = {rng(), rng(), rng(), rng()};
    237    EXPECT_THAT(values,
    238                testing::ElementsAre(19738651785169348, 1464811352364190456,
    239                                     18054685302720800, 19738651785169348));
    240  }
    241 }