// 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. #include "absl/random/internal/randen_slow.h" #include <cstddef> #include <cstdint> #include <cstring> #include "absl/base/attributes.h" #include "absl/base/internal/endian.h" #include "absl/numeric/int128.h" #include "absl/random/internal/platform.h" #include "absl/random/internal/randen_traits.h" #if ABSL_HAVE_ATTRIBUTE(always_inline) || \ (defined(__GNUC__) && !defined(__clang__)) #define ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE … #elif defined(_MSC_VER) // We can achieve something similar to attribute((always_inline)) with MSVC by // using the __forceinline keyword, however this is not perfect. MSVC is // much less aggressive about inlining, and even with the __forceinline keyword. #define ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE … #else #define ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE #endif namespace { // AES portions based on rijndael-alg-fst.c, // https://fastcrypto.org/front/misc/rijndael-alg-fst.c, and modified for // platform-endianness. // // Implementation of // http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf constexpr uint32_t te0[256] = …; constexpr uint32_t te1[256] = …; constexpr uint32_t te2[256] = …; constexpr uint32_t te3[256] = …; // Software implementation of the Vector128 class, using uint32_t // as an underlying vector register. struct alignas(16) Vector128 { … }; inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE Vector128 Vector128Load(const void* from) { … } inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE void Vector128Store( const Vector128& v, void* to) { … } // One round of AES. "round_key" is a public constant for breaking the // symmetry of AES (ensures previously equal columns differ afterwards). inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE Vector128 AesRound(const Vector128& state, const Vector128& round_key) { … } RandenTraits; // The improved Feistel block shuffle function for 16 blocks. inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE void BlockShuffle( absl::uint128* state) { … } // Feistel round function using two AES subrounds. Very similar to F() // from Simpira v2, but with independent subround keys. Uses 17 AES rounds // per 16 bytes (vs. 10 for AES-CTR). Computing eight round functions in // parallel hides the 7-cycle AESNI latency on HSW. Note that the Feistel // XORs are 'free' (included in the second AES instruction). inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE const absl::uint128* FeistelRound(absl::uint128* ABSL_RANDOM_INTERNAL_RESTRICT state, const absl::uint128* ABSL_RANDOM_INTERNAL_RESTRICT keys) { … } // Cryptographic permutation based via type-2 Generalized Feistel Network. // Indistinguishable from ideal by chosen-ciphertext adversaries using less than // 2^64 queries if the round function is a PRF. This is similar to the b=8 case // of Simpira v2, but more efficient than its generic construction for b=16. inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE void Permute( absl::uint128* state, const absl::uint128* ABSL_RANDOM_INTERNAL_RESTRICT keys) { … } // Enables native loads in the round loop by pre-swapping. inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE void SwapEndian( absl::uint128* state) { … } } // namespace namespace absl { ABSL_NAMESPACE_BEGIN namespace random_internal { const void* RandenSlow::GetKeys() { … } void RandenSlow::Absorb(const void* seed_void, void* state_void) { … } void RandenSlow::Generate(const void* keys_void, void* state_void) { … } } // namespace random_internal ABSL_NAMESPACE_END } // namespace absl