• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // HERMETIC NOTE: The randen_hwaes target must not introduce duplicate
16 // symbols from arbitrary system and other headers, since it may be built
17 // with different flags from other targets, using different levels of
18 // optimization, potentially introducing ODR violations.
19 
20 #include "absl/random/internal/randen_hwaes.h"
21 
22 #include <cstdint>
23 #include <cstring>
24 
25 #include "absl/base/attributes.h"
26 #include "absl/random/internal/platform.h"
27 
28 // ABSL_RANDEN_HWAES_IMPL indicates whether this file will contain
29 // a hardware accelerated implementation of randen, or whether it
30 // will contain stubs that exit the process.
31 #if defined(ABSL_ARCH_X86_64) || defined(ABSL_ARCH_X86_32)
32 // The platform.h directives are sufficient to indicate whether
33 // we should build accelerated implementations for x86.
34 #if (ABSL_HAVE_ACCELERATED_AES || ABSL_RANDOM_INTERNAL_AES_DISPATCH)
35 #define ABSL_RANDEN_HWAES_IMPL 1
36 #endif
37 #elif defined(ABSL_ARCH_PPC)
38 // The platform.h directives are sufficient to indicate whether
39 // we should build accelerated implementations for PPC.
40 //
41 // NOTE: This has mostly been tested on 64-bit Power variants,
42 // and not embedded cpus such as powerpc32-8540
43 #if ABSL_HAVE_ACCELERATED_AES
44 #define ABSL_RANDEN_HWAES_IMPL 1
45 #endif
46 #elif defined(ABSL_ARCH_ARM) || defined(ABSL_ARCH_AARCH64)
47 // ARM is somewhat more complicated. We might support crypto natively...
48 #if ABSL_HAVE_ACCELERATED_AES || \
49     (defined(__ARM_NEON) && defined(__ARM_FEATURE_CRYPTO))
50 #define ABSL_RANDEN_HWAES_IMPL 1
51 
52 #elif ABSL_RANDOM_INTERNAL_AES_DISPATCH && !defined(__APPLE__) && \
53     (defined(__GNUC__) && __GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ > 9)
54 // ...or, on GCC, we can use an ASM directive to
55 // instruct the assember to allow crypto instructions.
56 #define ABSL_RANDEN_HWAES_IMPL 1
57 #define ABSL_RANDEN_HWAES_IMPL_CRYPTO_DIRECTIVE 1
58 #endif
59 #else
60 // HWAES is unsupported by these architectures / platforms:
61 //   __myriad2__
62 //   __mips__
63 //
64 // Other architectures / platforms are unknown.
65 //
66 // See the Abseil documentation on supported macros at:
67 // https://abseil.io/docs/cpp/platforms/macros
68 #endif
69 
70 #if !defined(ABSL_RANDEN_HWAES_IMPL)
71 // No accelerated implementation is supported.
72 // The RandenHwAes functions are stubs that print an error and exit.
73 
74 #include <cstdio>
75 #include <cstdlib>
76 
77 namespace absl {
78 ABSL_NAMESPACE_BEGIN
79 namespace random_internal {
80 
81 // No accelerated implementation.
HasRandenHwAesImplementation()82 bool HasRandenHwAesImplementation() { return false; }
83 
84 // NOLINTNEXTLINE
GetKeys()85 const void* RandenHwAes::GetKeys() {
86   // Attempted to dispatch to an unsupported dispatch target.
87   const int d = ABSL_RANDOM_INTERNAL_AES_DISPATCH;
88   fprintf(stderr, "AES Hardware detection failed (%d).\n", d);
89   exit(1);
90   return nullptr;
91 }
92 
93 // NOLINTNEXTLINE
Absorb(const void *,void *)94 void RandenHwAes::Absorb(const void*, void*) {
95   // Attempted to dispatch to an unsupported dispatch target.
96   const int d = ABSL_RANDOM_INTERNAL_AES_DISPATCH;
97   fprintf(stderr, "AES Hardware detection failed (%d).\n", d);
98   exit(1);
99 }
100 
101 // NOLINTNEXTLINE
Generate(const void *,void *)102 void RandenHwAes::Generate(const void*, void*) {
103   // Attempted to dispatch to an unsupported dispatch target.
104   const int d = ABSL_RANDOM_INTERNAL_AES_DISPATCH;
105   fprintf(stderr, "AES Hardware detection failed (%d).\n", d);
106   exit(1);
107 }
108 
109 }  // namespace random_internal
110 ABSL_NAMESPACE_END
111 }  // namespace absl
112 
113 #else  // defined(ABSL_RANDEN_HWAES_IMPL)
114 //
115 // Accelerated implementations are supported.
116 // We need the per-architecture includes and defines.
117 //
118 
119 #include "absl/random/internal/randen_traits.h"
120 
121 // TARGET_CRYPTO defines a crypto attribute for each architecture.
122 //
123 // NOTE: Evaluate whether we should eliminate ABSL_TARGET_CRYPTO.
124 #if (defined(__clang__) || defined(__GNUC__))
125 #if defined(ABSL_ARCH_X86_64) || defined(ABSL_ARCH_X86_32)
126 #define ABSL_TARGET_CRYPTO __attribute__((target("aes")))
127 #elif defined(ABSL_ARCH_PPC)
128 #define ABSL_TARGET_CRYPTO __attribute__((target("crypto")))
129 #else
130 #define ABSL_TARGET_CRYPTO
131 #endif
132 #else
133 #define ABSL_TARGET_CRYPTO
134 #endif
135 
136 #if defined(ABSL_ARCH_PPC)
137 // NOTE: Keep in mind that PPC can operate in little-endian or big-endian mode,
138 // however the PPC altivec vector registers (and thus the AES instructions)
139 // always operate in big-endian mode.
140 
141 #include <altivec.h>
142 // <altivec.h> #defines vector __vector; in C++, this is bad form.
143 #undef vector
144 
145 // Rely on the PowerPC AltiVec vector operations for accelerated AES
146 // instructions. GCC support of the PPC vector types is described in:
147 // https://gcc.gnu.org/onlinedocs/gcc-4.9.0/gcc/PowerPC-AltiVec_002fVSX-Built-in-Functions.html
148 //
149 // Already provides operator^=.
150 using Vector128 = __vector unsigned long long;  // NOLINT(runtime/int)
151 
152 namespace {
153 
ReverseBytes(const Vector128 & v)154 inline ABSL_TARGET_CRYPTO Vector128 ReverseBytes(const Vector128& v) {
155   // Reverses the bytes of the vector.
156   const __vector unsigned char perm = {15, 14, 13, 12, 11, 10, 9, 8,
157                                        7,  6,  5,  4,  3,  2,  1, 0};
158   return vec_perm(v, v, perm);
159 }
160 
161 // WARNING: these load/store in native byte order. It is OK to load and then
162 // store an unchanged vector, but interpreting the bits as a number or input
163 // to AES will have undefined results.
Vector128Load(const void * from)164 inline ABSL_TARGET_CRYPTO Vector128 Vector128Load(const void* from) {
165   return vec_vsx_ld(0, reinterpret_cast<const Vector128*>(from));
166 }
167 
Vector128Store(const Vector128 & v,void * to)168 inline ABSL_TARGET_CRYPTO void Vector128Store(const Vector128& v, void* to) {
169   vec_vsx_st(v, 0, reinterpret_cast<Vector128*>(to));
170 }
171 
172 // One round of AES. "round_key" is a public constant for breaking the
173 // symmetry of AES (ensures previously equal columns differ afterwards).
AesRound(const Vector128 & state,const Vector128 & round_key)174 inline ABSL_TARGET_CRYPTO Vector128 AesRound(const Vector128& state,
175                                              const Vector128& round_key) {
176   return Vector128(__builtin_crypto_vcipher(state, round_key));
177 }
178 
179 // Enables native loads in the round loop by pre-swapping.
SwapEndian(uint64_t * state)180 inline ABSL_TARGET_CRYPTO void SwapEndian(uint64_t* state) {
181   using absl::random_internal::RandenTraits;
182   constexpr size_t kLanes = 2;
183   constexpr size_t kFeistelBlocks = RandenTraits::kFeistelBlocks;
184 
185   for (uint32_t branch = 0; branch < kFeistelBlocks; ++branch) {
186     const Vector128 v = ReverseBytes(Vector128Load(state + kLanes * branch));
187     Vector128Store(v, state + kLanes * branch);
188   }
189 }
190 
191 }  // namespace
192 
193 #elif defined(ABSL_ARCH_ARM) || defined(ABSL_ARCH_AARCH64)
194 
195 // This asm directive will cause the file to be compiled with crypto extensions
196 // whether or not the cpu-architecture supports it.
197 #if ABSL_RANDEN_HWAES_IMPL_CRYPTO_DIRECTIVE
198 asm(".arch_extension  crypto\n");
199 
200 // Override missing defines.
201 #if !defined(__ARM_NEON)
202 #define __ARM_NEON 1
203 #endif
204 
205 #if !defined(__ARM_FEATURE_CRYPTO)
206 #define __ARM_FEATURE_CRYPTO 1
207 #endif
208 
209 #endif
210 
211 // Rely on the ARM NEON+Crypto advanced simd types, defined in <arm_neon.h>.
212 // uint8x16_t is the user alias for underlying __simd128_uint8_t type.
213 // http://infocenter.arm.com/help/topic/com.arm.doc.ihi0073a/IHI0073A_arm_neon_intrinsics_ref.pdf
214 //
215 // <arm_neon> defines the following
216 //
217 // typedef __attribute__((neon_vector_type(16))) uint8_t uint8x16_t;
218 // typedef __attribute__((neon_vector_type(16))) int8_t int8x16_t;
219 // typedef __attribute__((neon_polyvector_type(16))) int8_t poly8x16_t;
220 //
221 // vld1q_v
222 // vst1q_v
223 // vaeseq_v
224 // vaesmcq_v
225 #include <arm_neon.h>
226 
227 // Already provides operator^=.
228 using Vector128 = uint8x16_t;
229 
230 namespace {
231 
Vector128Load(const void * from)232 inline ABSL_TARGET_CRYPTO Vector128 Vector128Load(const void* from) {
233   return vld1q_u8(reinterpret_cast<const uint8_t*>(from));
234 }
235 
Vector128Store(const Vector128 & v,void * to)236 inline ABSL_TARGET_CRYPTO void Vector128Store(const Vector128& v, void* to) {
237   vst1q_u8(reinterpret_cast<uint8_t*>(to), v);
238 }
239 
240 // One round of AES. "round_key" is a public constant for breaking the
241 // symmetry of AES (ensures previously equal columns differ afterwards).
AesRound(const Vector128 & state,const Vector128 & round_key)242 inline ABSL_TARGET_CRYPTO Vector128 AesRound(const Vector128& state,
243                                              const Vector128& round_key) {
244   // It is important to always use the full round function - omitting the
245   // final MixColumns reduces security [https://eprint.iacr.org/2010/041.pdf]
246   // and does not help because we never decrypt.
247   //
248   // Note that ARM divides AES instructions differently than x86 / PPC,
249   // And we need to skip the first AddRoundKey step and add an extra
250   // AddRoundKey step to the end. Lucky for us this is just XOR.
251   return vaesmcq_u8(vaeseq_u8(state, uint8x16_t{})) ^ round_key;
252 }
253 
SwapEndian(uint64_t *)254 inline ABSL_TARGET_CRYPTO void SwapEndian(uint64_t*) {}
255 
256 }  // namespace
257 
258 #elif defined(ABSL_ARCH_X86_64) || defined(ABSL_ARCH_X86_32)
259 // On x86 we rely on the aesni instructions
260 #include <wmmintrin.h>
261 
262 namespace {
263 
264 // Vector128 class is only wrapper for __m128i, benchmark indicates that it's
265 // faster than using __m128i directly.
266 class Vector128 {
267  public:
268   // Convert from/to intrinsics.
Vector128(const __m128i & Vector128)269   inline explicit Vector128(const __m128i& Vector128) : data_(Vector128) {}
270 
data() const271   inline __m128i data() const { return data_; }
272 
operator ^=(const Vector128 & other)273   inline Vector128& operator^=(const Vector128& other) {
274     data_ = _mm_xor_si128(data_, other.data());
275     return *this;
276   }
277 
278  private:
279   __m128i data_;
280 };
281 
Vector128Load(const void * from)282 inline ABSL_TARGET_CRYPTO Vector128 Vector128Load(const void* from) {
283   return Vector128(_mm_load_si128(reinterpret_cast<const __m128i*>(from)));
284 }
285 
Vector128Store(const Vector128 & v,void * to)286 inline ABSL_TARGET_CRYPTO void Vector128Store(const Vector128& v, void* to) {
287   _mm_store_si128(reinterpret_cast<__m128i*>(to), v.data());
288 }
289 
290 // One round of AES. "round_key" is a public constant for breaking the
291 // symmetry of AES (ensures previously equal columns differ afterwards).
AesRound(const Vector128 & state,const Vector128 & round_key)292 inline ABSL_TARGET_CRYPTO Vector128 AesRound(const Vector128& state,
293                                              const Vector128& round_key) {
294   // It is important to always use the full round function - omitting the
295   // final MixColumns reduces security [https://eprint.iacr.org/2010/041.pdf]
296   // and does not help because we never decrypt.
297   return Vector128(_mm_aesenc_si128(state.data(), round_key.data()));
298 }
299 
SwapEndian(uint64_t *)300 inline ABSL_TARGET_CRYPTO void SwapEndian(uint64_t*) {}
301 
302 }  // namespace
303 
304 #endif
305 
306 namespace {
307 
308 // u64x2 is a 128-bit, (2 x uint64_t lanes) struct used to store
309 // the randen_keys.
310 struct alignas(16) u64x2 {
u64x2__anon571fe8980411::u64x2311   constexpr u64x2(uint64_t hi, uint64_t lo)
312 #if defined(ABSL_ARCH_PPC)
313       // This has been tested with PPC running in little-endian mode;
314       // We byte-swap the u64x2 structure from little-endian to big-endian
315       // because altivec always runs in big-endian mode.
316       : v{__builtin_bswap64(hi), __builtin_bswap64(lo)} {
317 #else
318       : v{lo, hi} {
319 #endif
320   }
321 
operator ==__anon571fe8980411::u64x2322   constexpr bool operator==(const u64x2& other) const {
323     return v[0] == other.v[0] && v[1] == other.v[1];
324   }
325 
operator !=__anon571fe8980411::u64x2326   constexpr bool operator!=(const u64x2& other) const {
327     return !(*this == other);
328   }
329 
330   uint64_t v[2];
331 };  // namespace
332 
333 #ifdef __clang__
334 #pragma clang diagnostic push
335 #pragma clang diagnostic ignored "-Wunknown-pragmas"
336 #endif
337 
338 // At this point, all of the platform-specific features have been defined /
339 // implemented.
340 //
341 // REQUIRES: using u64x2 = ...
342 // REQUIRES: using Vector128 = ...
343 // REQUIRES: Vector128 Vector128Load(void*) {...}
344 // REQUIRES: void Vector128Store(Vector128, void*) {...}
345 // REQUIRES: Vector128 AesRound(Vector128, Vector128) {...}
346 // REQUIRES: void SwapEndian(uint64_t*) {...}
347 //
348 // PROVIDES: absl::random_internal::RandenHwAes::Absorb
349 // PROVIDES: absl::random_internal::RandenHwAes::Generate
350 
351 // RANDen = RANDom generator or beetroots in Swiss German.
352 // 'Strong' (well-distributed, unpredictable, backtracking-resistant) random
353 // generator, faster in some benchmarks than std::mt19937_64 and pcg64_c32.
354 //
355 // High-level summary:
356 // 1) Reverie (see "A Robust and Sponge-Like PRNG with Improved Efficiency") is
357 //    a sponge-like random generator that requires a cryptographic permutation.
358 //    It improves upon "Provably Robust Sponge-Based PRNGs and KDFs" by
359 //    achieving backtracking resistance with only one Permute() per buffer.
360 //
361 // 2) "Simpira v2: A Family of Efficient Permutations Using the AES Round
362 //    Function" constructs up to 1024-bit permutations using an improved
363 //    Generalized Feistel network with 2-round AES-128 functions. This Feistel
364 //    block shuffle achieves diffusion faster and is less vulnerable to
365 //    sliced-biclique attacks than the Type-2 cyclic shuffle.
366 //
367 // 3) "Improving the Generalized Feistel" and "New criterion for diffusion
368 //    property" extends the same kind of improved Feistel block shuffle to 16
369 //    branches, which enables a 2048-bit permutation.
370 //
371 // We combine these three ideas and also change Simpira's subround keys from
372 // structured/low-entropy counters to digits of Pi.
373 
374 // Randen constants.
375 using absl::random_internal::RandenTraits;
376 constexpr size_t kStateBytes = RandenTraits::kStateBytes;
377 constexpr size_t kCapacityBytes = RandenTraits::kCapacityBytes;
378 constexpr size_t kFeistelBlocks = RandenTraits::kFeistelBlocks;
379 constexpr size_t kFeistelRounds = RandenTraits::kFeistelRounds;
380 constexpr size_t kFeistelFunctions = RandenTraits::kFeistelFunctions;
381 
382 // Independent keys (272 = 2.1 KiB) for the first AES subround of each function.
383 constexpr size_t kKeys = kFeistelRounds * kFeistelFunctions;
384 
385 // INCLUDE keys.
386 #include "absl/random/internal/randen-keys.inc"
387 
388 static_assert(kKeys == kRoundKeys, "kKeys and kRoundKeys must be equal");
389 static_assert(round_keys[kKeys - 1] != u64x2(0, 0),
390               "Too few round_keys initializers");
391 
392 // Number of uint64_t lanes per 128-bit vector;
393 constexpr size_t kLanes = 2;
394 
395 // Block shuffles applies a shuffle to the entire state between AES rounds.
396 // Improved odd-even shuffle from "New criterion for diffusion property".
BlockShuffle(uint64_t * state)397 inline ABSL_TARGET_CRYPTO void BlockShuffle(uint64_t* state) {
398   static_assert(kFeistelBlocks == 16, "Expecting 16 FeistelBlocks.");
399 
400   constexpr size_t shuffle[kFeistelBlocks] = {7,  2, 13, 4,  11, 8,  3, 6,
401                                               15, 0, 9,  10, 1,  14, 5, 12};
402 
403   // The fully unrolled loop without the memcpy improves the speed by about
404   // 30% over the equivalent loop.
405   const Vector128 v0 = Vector128Load(state + kLanes * shuffle[0]);
406   const Vector128 v1 = Vector128Load(state + kLanes * shuffle[1]);
407   const Vector128 v2 = Vector128Load(state + kLanes * shuffle[2]);
408   const Vector128 v3 = Vector128Load(state + kLanes * shuffle[3]);
409   const Vector128 v4 = Vector128Load(state + kLanes * shuffle[4]);
410   const Vector128 v5 = Vector128Load(state + kLanes * shuffle[5]);
411   const Vector128 v6 = Vector128Load(state + kLanes * shuffle[6]);
412   const Vector128 v7 = Vector128Load(state + kLanes * shuffle[7]);
413   const Vector128 w0 = Vector128Load(state + kLanes * shuffle[8]);
414   const Vector128 w1 = Vector128Load(state + kLanes * shuffle[9]);
415   const Vector128 w2 = Vector128Load(state + kLanes * shuffle[10]);
416   const Vector128 w3 = Vector128Load(state + kLanes * shuffle[11]);
417   const Vector128 w4 = Vector128Load(state + kLanes * shuffle[12]);
418   const Vector128 w5 = Vector128Load(state + kLanes * shuffle[13]);
419   const Vector128 w6 = Vector128Load(state + kLanes * shuffle[14]);
420   const Vector128 w7 = Vector128Load(state + kLanes * shuffle[15]);
421 
422   Vector128Store(v0, state + kLanes * 0);
423   Vector128Store(v1, state + kLanes * 1);
424   Vector128Store(v2, state + kLanes * 2);
425   Vector128Store(v3, state + kLanes * 3);
426   Vector128Store(v4, state + kLanes * 4);
427   Vector128Store(v5, state + kLanes * 5);
428   Vector128Store(v6, state + kLanes * 6);
429   Vector128Store(v7, state + kLanes * 7);
430   Vector128Store(w0, state + kLanes * 8);
431   Vector128Store(w1, state + kLanes * 9);
432   Vector128Store(w2, state + kLanes * 10);
433   Vector128Store(w3, state + kLanes * 11);
434   Vector128Store(w4, state + kLanes * 12);
435   Vector128Store(w5, state + kLanes * 13);
436   Vector128Store(w6, state + kLanes * 14);
437   Vector128Store(w7, state + kLanes * 15);
438 }
439 
440 // Feistel round function using two AES subrounds. Very similar to F()
441 // from Simpira v2, but with independent subround keys. Uses 17 AES rounds
442 // per 16 bytes (vs. 10 for AES-CTR). Computing eight round functions in
443 // parallel hides the 7-cycle AESNI latency on HSW. Note that the Feistel
444 // XORs are 'free' (included in the second AES instruction).
FeistelRound(uint64_t * state,const u64x2 * ABSL_RANDOM_INTERNAL_RESTRICT keys)445 inline ABSL_TARGET_CRYPTO const u64x2* FeistelRound(
446     uint64_t* state, const u64x2* ABSL_RANDOM_INTERNAL_RESTRICT keys) {
447   static_assert(kFeistelBlocks == 16, "Expecting 16 FeistelBlocks.");
448 
449   // MSVC does a horrible job at unrolling loops.
450   // So we unroll the loop by hand to improve the performance.
451   const Vector128 s0 = Vector128Load(state + kLanes * 0);
452   const Vector128 s1 = Vector128Load(state + kLanes * 1);
453   const Vector128 s2 = Vector128Load(state + kLanes * 2);
454   const Vector128 s3 = Vector128Load(state + kLanes * 3);
455   const Vector128 s4 = Vector128Load(state + kLanes * 4);
456   const Vector128 s5 = Vector128Load(state + kLanes * 5);
457   const Vector128 s6 = Vector128Load(state + kLanes * 6);
458   const Vector128 s7 = Vector128Load(state + kLanes * 7);
459   const Vector128 s8 = Vector128Load(state + kLanes * 8);
460   const Vector128 s9 = Vector128Load(state + kLanes * 9);
461   const Vector128 s10 = Vector128Load(state + kLanes * 10);
462   const Vector128 s11 = Vector128Load(state + kLanes * 11);
463   const Vector128 s12 = Vector128Load(state + kLanes * 12);
464   const Vector128 s13 = Vector128Load(state + kLanes * 13);
465   const Vector128 s14 = Vector128Load(state + kLanes * 14);
466   const Vector128 s15 = Vector128Load(state + kLanes * 15);
467 
468   // Encode even blocks with keys.
469   const Vector128 e0 = AesRound(s0, Vector128Load(keys + 0));
470   const Vector128 e2 = AesRound(s2, Vector128Load(keys + 1));
471   const Vector128 e4 = AesRound(s4, Vector128Load(keys + 2));
472   const Vector128 e6 = AesRound(s6, Vector128Load(keys + 3));
473   const Vector128 e8 = AesRound(s8, Vector128Load(keys + 4));
474   const Vector128 e10 = AesRound(s10, Vector128Load(keys + 5));
475   const Vector128 e12 = AesRound(s12, Vector128Load(keys + 6));
476   const Vector128 e14 = AesRound(s14, Vector128Load(keys + 7));
477 
478   // Encode odd blocks with even output from above.
479   const Vector128 o1 = AesRound(e0, s1);
480   const Vector128 o3 = AesRound(e2, s3);
481   const Vector128 o5 = AesRound(e4, s5);
482   const Vector128 o7 = AesRound(e6, s7);
483   const Vector128 o9 = AesRound(e8, s9);
484   const Vector128 o11 = AesRound(e10, s11);
485   const Vector128 o13 = AesRound(e12, s13);
486   const Vector128 o15 = AesRound(e14, s15);
487 
488   // Store odd blocks. (These will be shuffled later).
489   Vector128Store(o1, state + kLanes * 1);
490   Vector128Store(o3, state + kLanes * 3);
491   Vector128Store(o5, state + kLanes * 5);
492   Vector128Store(o7, state + kLanes * 7);
493   Vector128Store(o9, state + kLanes * 9);
494   Vector128Store(o11, state + kLanes * 11);
495   Vector128Store(o13, state + kLanes * 13);
496   Vector128Store(o15, state + kLanes * 15);
497 
498   return keys + 8;
499 }
500 
501 // Cryptographic permutation based via type-2 Generalized Feistel Network.
502 // Indistinguishable from ideal by chosen-ciphertext adversaries using less than
503 // 2^64 queries if the round function is a PRF. This is similar to the b=8 case
504 // of Simpira v2, but more efficient than its generic construction for b=16.
Permute(const void * ABSL_RANDOM_INTERNAL_RESTRICT keys,uint64_t * state)505 inline ABSL_TARGET_CRYPTO void Permute(
506     const void* ABSL_RANDOM_INTERNAL_RESTRICT keys, uint64_t* state) {
507   const u64x2* ABSL_RANDOM_INTERNAL_RESTRICT keys128 =
508       static_cast<const u64x2*>(keys);
509 
510   // (Successfully unrolled; the first iteration jumps into the second half)
511 #ifdef __clang__
512 #pragma clang loop unroll_count(2)
513 #endif
514   for (size_t round = 0; round < kFeistelRounds; ++round) {
515     keys128 = FeistelRound(state, keys128);
516     BlockShuffle(state);
517   }
518 }
519 
520 }  // namespace
521 
522 namespace absl {
523 ABSL_NAMESPACE_BEGIN
524 namespace random_internal {
525 
HasRandenHwAesImplementation()526 bool HasRandenHwAesImplementation() { return true; }
527 
GetKeys()528 const void* ABSL_TARGET_CRYPTO RandenHwAes::GetKeys() {
529   // Round keys for one AES per Feistel round and branch.
530   // The canonical implementation uses first digits of Pi.
531   return round_keys;
532 }
533 
534 // NOLINTNEXTLINE
Absorb(const void * seed_void,void * state_void)535 void ABSL_TARGET_CRYPTO RandenHwAes::Absorb(const void* seed_void,
536                                             void* state_void) {
537   auto* state = static_cast<uint64_t*>(state_void);
538   const auto* seed = static_cast<const uint64_t*>(seed_void);
539 
540   constexpr size_t kCapacityBlocks = kCapacityBytes / sizeof(Vector128);
541   constexpr size_t kStateBlocks = kStateBytes / sizeof(Vector128);
542 
543   static_assert(kCapacityBlocks * sizeof(Vector128) == kCapacityBytes,
544                 "Not i*V");
545   static_assert(kCapacityBlocks == 1, "Unexpected Randen kCapacityBlocks");
546   static_assert(kStateBlocks == 16, "Unexpected Randen kStateBlocks");
547 
548   Vector128 b1 = Vector128Load(state + kLanes * 1);
549   b1 ^= Vector128Load(seed + kLanes * 0);
550   Vector128Store(b1, state + kLanes * 1);
551 
552   Vector128 b2 = Vector128Load(state + kLanes * 2);
553   b2 ^= Vector128Load(seed + kLanes * 1);
554   Vector128Store(b2, state + kLanes * 2);
555 
556   Vector128 b3 = Vector128Load(state + kLanes * 3);
557   b3 ^= Vector128Load(seed + kLanes * 2);
558   Vector128Store(b3, state + kLanes * 3);
559 
560   Vector128 b4 = Vector128Load(state + kLanes * 4);
561   b4 ^= Vector128Load(seed + kLanes * 3);
562   Vector128Store(b4, state + kLanes * 4);
563 
564   Vector128 b5 = Vector128Load(state + kLanes * 5);
565   b5 ^= Vector128Load(seed + kLanes * 4);
566   Vector128Store(b5, state + kLanes * 5);
567 
568   Vector128 b6 = Vector128Load(state + kLanes * 6);
569   b6 ^= Vector128Load(seed + kLanes * 5);
570   Vector128Store(b6, state + kLanes * 6);
571 
572   Vector128 b7 = Vector128Load(state + kLanes * 7);
573   b7 ^= Vector128Load(seed + kLanes * 6);
574   Vector128Store(b7, state + kLanes * 7);
575 
576   Vector128 b8 = Vector128Load(state + kLanes * 8);
577   b8 ^= Vector128Load(seed + kLanes * 7);
578   Vector128Store(b8, state + kLanes * 8);
579 
580   Vector128 b9 = Vector128Load(state + kLanes * 9);
581   b9 ^= Vector128Load(seed + kLanes * 8);
582   Vector128Store(b9, state + kLanes * 9);
583 
584   Vector128 b10 = Vector128Load(state + kLanes * 10);
585   b10 ^= Vector128Load(seed + kLanes * 9);
586   Vector128Store(b10, state + kLanes * 10);
587 
588   Vector128 b11 = Vector128Load(state + kLanes * 11);
589   b11 ^= Vector128Load(seed + kLanes * 10);
590   Vector128Store(b11, state + kLanes * 11);
591 
592   Vector128 b12 = Vector128Load(state + kLanes * 12);
593   b12 ^= Vector128Load(seed + kLanes * 11);
594   Vector128Store(b12, state + kLanes * 12);
595 
596   Vector128 b13 = Vector128Load(state + kLanes * 13);
597   b13 ^= Vector128Load(seed + kLanes * 12);
598   Vector128Store(b13, state + kLanes * 13);
599 
600   Vector128 b14 = Vector128Load(state + kLanes * 14);
601   b14 ^= Vector128Load(seed + kLanes * 13);
602   Vector128Store(b14, state + kLanes * 14);
603 
604   Vector128 b15 = Vector128Load(state + kLanes * 15);
605   b15 ^= Vector128Load(seed + kLanes * 14);
606   Vector128Store(b15, state + kLanes * 15);
607 }
608 
609 // NOLINTNEXTLINE
Generate(const void * keys,void * state_void)610 void ABSL_TARGET_CRYPTO RandenHwAes::Generate(const void* keys,
611                                               void* state_void) {
612   static_assert(kCapacityBytes == sizeof(Vector128), "Capacity mismatch");
613 
614   auto* state = static_cast<uint64_t*>(state_void);
615 
616   const Vector128 prev_inner = Vector128Load(state);
617 
618   SwapEndian(state);
619 
620   Permute(keys, state);
621 
622   SwapEndian(state);
623 
624   // Ensure backtracking resistance.
625   Vector128 inner = Vector128Load(state);
626   inner ^= prev_inner;
627   Vector128Store(inner, state);
628 }
629 
630 #ifdef __clang__
631 #pragma clang diagnostic pop
632 #endif
633 
634 }  // namespace random_internal
635 ABSL_NAMESPACE_END
636 }  // namespace absl
637 
638 #endif  // (ABSL_RANDEN_HWAES_IMPL)
639