Commit 022527c5 by Milad Fa Committed by GitHub

Fix Randen and PCG on Big Endian platforms (#1031)

parent cc413f8b
...@@ -74,7 +74,7 @@ class ExplicitSeedSeq { ...@@ -74,7 +74,7 @@ class ExplicitSeedSeq {
template <typename OutIterator> template <typename OutIterator>
void generate(OutIterator begin, OutIterator end) { void generate(OutIterator begin, OutIterator end) {
for (size_t index = 0; begin != end; begin++) { for (size_t index = 0; begin != end; begin++) {
*begin = state_.empty() ? 0 : little_endian::FromHost32(state_[index++]); *begin = state_.empty() ? 0 : state_[index++];
if (index >= state_.size()) { if (index >= state_.size()) {
index = 0; index = 0;
} }
......
...@@ -121,6 +121,13 @@ class alignas(16) randen_engine { ...@@ -121,6 +121,13 @@ class alignas(16) randen_engine {
const size_t requested_entropy = (entropy_size == 0) ? 8u : entropy_size; const size_t requested_entropy = (entropy_size == 0) ? 8u : entropy_size;
std::fill(std::begin(buffer) + requested_entropy, std::end(buffer), 0); std::fill(std::begin(buffer) + requested_entropy, std::end(buffer), 0);
seq.generate(std::begin(buffer), std::begin(buffer) + requested_entropy); seq.generate(std::begin(buffer), std::begin(buffer) + requested_entropy);
#ifdef ABSL_IS_BIG_ENDIAN
// Randen expects the seed buffer to be in Little Endian; reverse it on
// Big Endian platforms.
for (sequence_result_type& e : buffer) {
e = absl::little_endian::FromHost(e);
}
#endif
// The Randen paper suggests preferentially initializing even-numbered // The Randen paper suggests preferentially initializing even-numbered
// 128-bit vectors of the randen state (there are 16 such vectors). // 128-bit vectors of the randen state (there are 16 such vectors).
// The seed data is merged into the state offset by 128-bits, which // The seed data is merged into the state offset by 128-bits, which
......
...@@ -395,6 +395,23 @@ inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE void Permute( ...@@ -395,6 +395,23 @@ inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE void Permute(
} }
} }
// Enables native loads in the round loop by pre-swapping.
inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE void SwapEndian(
absl::uint128* state) {
#ifdef ABSL_IS_BIG_ENDIAN
for (uint32_t block = 0; block < RandenTraits::kFeistelBlocks; ++block) {
uint64_t new_lo = absl::little_endian::ToHost64(
static_cast<uint64_t>(state[block] >> 64));
uint64_t new_hi = absl::little_endian::ToHost64(
static_cast<uint64_t>((state[block] << 64) >> 64));
state[block] = (static_cast<absl::uint128>(new_hi) << 64) | new_lo;
}
#else
// Avoid warning about unused variable.
(void)state;
#endif
}
} // namespace } // namespace
namespace absl { namespace absl {
...@@ -439,8 +456,12 @@ void RandenSlow::Generate(const void* keys_void, void* state_void) { ...@@ -439,8 +456,12 @@ void RandenSlow::Generate(const void* keys_void, void* state_void) {
const absl::uint128 prev_inner = state[0]; const absl::uint128 prev_inner = state[0];
SwapEndian(state);
Permute(state, keys); Permute(state, keys);
SwapEndian(state);
// Ensure backtracking resistance. // Ensure backtracking resistance.
*state ^= prev_inner; *state ^= prev_inner;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment