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