// Copyright 2017 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef ABSL_RANDOM_INTERNAL_SALTED_SEED_SEQ_H_ #define ABSL_RANDOM_INTERNAL_SALTED_SEED_SEQ_H_ #include #include #include #include #include #include #include #include "absl/container/inlined_vector.h" #include "absl/meta/type_traits.h" #include "absl/random/internal/seed_material.h" #include "absl/types/optional.h" #include "absl/types/span.h" namespace absl { namespace random_internal { // This class conforms to the C++ Standard "Seed Sequence" concept // [rand.req.seedseq]. // // A `SaltedSeedSeq` is meant to wrap an existing seed sequence and modify // generated sequence by mixing with extra entropy. This entropy may be // build-dependent or process-dependent. The implementation may change to be // have either or both kinds of entropy. If salt is not available sequence is // not modified. template class SaltedSeedSeq { public: using inner_sequence_type = SSeq; using result_type = typename SSeq::result_type; SaltedSeedSeq() : seq_(absl::make_unique()) {} template SaltedSeedSeq(Iterator begin, Iterator end) : seq_(absl::make_unique(begin, end)) {} template SaltedSeedSeq(std::initializer_list il) : SaltedSeedSeq(il.begin(), il.end()) {} SaltedSeedSeq(const SaltedSeedSeq&) = delete; SaltedSeedSeq& operator=(const SaltedSeedSeq&) = delete; SaltedSeedSeq(SaltedSeedSeq&&) = default; SaltedSeedSeq& operator=(SaltedSeedSeq&&) = default; template void generate(RandomAccessIterator begin, RandomAccessIterator end) { // The common case is that generate is called with ContiguousIterators // to uint arrays. Such contiguous memory regions may be optimized, // which we detect here. using tag = absl::conditional_t< (std::is_pointer::value && std::is_same, uint32_t>::value), ContiguousAndUint32Tag, DefaultTag>; if (begin != end) { generate_impl(begin, end, tag{}); } } template void param(OutIterator out) const { seq_->param(out); } size_t size() const { return seq_->size(); } private: struct ContiguousAndUint32Tag {}; struct DefaultTag {}; // Generate which requires the iterators are contiguous pointers to uint32_t. void generate_impl(uint32_t* begin, uint32_t* end, ContiguousAndUint32Tag) { generate_contiguous(absl::MakeSpan(begin, end)); } // The uncommon case for generate is that it is called with iterators over // some other buffer type which is assignable from a 32-bit value. In this // case we allocate a temporary 32-bit buffer and then copy-assign back // to the initial inputs. template void generate_impl(RandomAccessIterator begin, RandomAccessIterator end, DefaultTag) { return generate_and_copy(std::distance(begin, end), begin); } // Fills the initial seed buffer the underlying SSeq::generate() call, // mixing in the salt material. void generate_contiguous(absl::Span buffer) { seq_->generate(buffer.begin(), buffer.end()); const uint32_t salt = absl::random_internal::GetSaltMaterial().value_or(0); MixIntoSeedMaterial(absl::MakeConstSpan(&salt, 1), buffer); } // Allocates a seed buffer of `n` elements, generates the seed, then // copies the result into the `out` iterator. template void generate_and_copy(size_t n, Iterator out) { // Allocate a temporary buffer, generate, and then copy. absl::InlinedVector data(n, 0); generate_contiguous(absl::MakeSpan(data.data(), data.size())); std::copy(data.begin(), data.end(), out); } // Because [rand.req.seedseq] is not required to be copy-constructible, // copy-assignable nor movable, we wrap it with unique pointer to be able // to move SaltedSeedSeq. std::unique_ptr seq_; }; // is_salted_seed_seq indicates whether the type is a SaltedSeedSeq. template struct is_salted_seed_seq : public std::false_type {}; template struct is_salted_seed_seq< T, typename std::enable_if>::value>::type> : public std::true_type {}; // MakeSaltedSeedSeq returns a salted variant of the seed sequence. // When provided with an existing SaltedSeedSeq, returns the input parameter, // otherwise constructs a new SaltedSeedSeq which embodies the original // non-salted seed parameters. template < typename SSeq, // typename EnableIf = absl::enable_if_t::value>> SSeq MakeSaltedSeedSeq(SSeq&& seq) { return SSeq(std::forward(seq)); } template < typename SSeq, // typename EnableIf = absl::enable_if_t::value>> SaltedSeedSeq::type> MakeSaltedSeedSeq(SSeq&& seq) { using sseq_type = typename std::decay::type; using result_type = typename sseq_type::result_type; absl::InlinedVector data; seq.param(std::back_inserter(data)); return SaltedSeedSeq(data.begin(), data.end()); } } // namespace random_internal } // namespace absl #endif // ABSL_RANDOM_INTERNAL_SALTED_SEED_SEQ_H_