15#if defined(CRYPTOPP_DISABLE_GCM_ASM)
16# undef CRYPTOPP_X86_ASM_AVAILABLE
17# undef CRYPTOPP_X32_ASM_AVAILABLE
18# undef CRYPTOPP_X64_ASM_AVAILABLE
19# undef CRYPTOPP_SSE2_ASM_AVAILABLE
22#if (CRYPTOPP_SSE2_INTRIN_AVAILABLE)
23# include <emmintrin.h>
24# include <xmmintrin.h>
27#if (CRYPTOPP_CLMUL_AVAILABLE)
28# include <tmmintrin.h>
29# include <wmmintrin.h>
32#if (CRYPTOPP_ARM_NEON_HEADER)
37#if defined(CRYPTOPP_ARM_PMULL_AVAILABLE)
41#if defined(CRYPTOPP_ALTIVEC_AVAILABLE)
45#ifdef CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY
50#ifndef EXCEPTION_EXECUTE_HANDLER
51# define EXCEPTION_EXECUTE_HANDLER 1
55extern const char GCM_SIMD_FNAME[] = __FILE__;
61#ifdef CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY
63 typedef void (*SigHandler)(int);
65 static jmp_buf s_jmpSIGILL;
66 static void SigIllHandler(
int)
68 longjmp(s_jmpSIGILL, 1);
73#if (CRYPTOPP_BOOL_ARM32 || CRYPTOPP_BOOL_ARMV8)
76#if defined(CRYPTOPP_NO_CPU_FEATURE_PROBES)
78#elif (CRYPTOPP_ARM_PMULL_AVAILABLE)
79# if defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY)
80 volatile bool result =
true;
84 const uint64_t wa1[]={0,0x9090909090909090}, wb1[]={0,0xb0b0b0b0b0b0b0b0};
85 const uint64x2_t a1=vld1q_u64(wa1), b1=vld1q_u64(wb1);
87 const uint8_t wa2[]={0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
88 0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0},
89 wb2[]={0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,
90 0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0};
91 const uint8x16_t a2=vld1q_u8(wa2), b2=vld1q_u8(wb2);
93 const uint64x2_t r1 =
PMULL_00(a1, b1);
94 const uint64x2_t r2 =
PMULL_11(vreinterpretq_u64_u8(a2),
95 vreinterpretq_u64_u8(b2));
97 result = !!(vgetq_lane_u64(r1,0) == 0x5300530053005300 &&
98 vgetq_lane_u64(r1,1) == 0x5300530053005300 &&
99 vgetq_lane_u64(r2,0) == 0x6c006c006c006c00 &&
100 vgetq_lane_u64(r2,1) == 0x6c006c006c006c00);
102 __except (EXCEPTION_EXECUTE_HANDLER)
110 volatile bool result =
true;
112 volatile SigHandler oldHandler = signal(SIGILL, SigIllHandler);
113 if (oldHandler == SIG_ERR)
116 volatile sigset_t oldMask;
117 if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask))
119 signal(SIGILL, oldHandler);
123 if (setjmp(s_jmpSIGILL))
128 const uint64_t wa1[]={0,0x9090909090909090}, wb1[]={0,0xb0b0b0b0b0b0b0b0};
129 const uint64x2_t a1=vld1q_u64(wa1), b1=vld1q_u64(wb1);
131 const uint8_t wa2[]={0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
132 0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0},
133 wb2[]={0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,
134 0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0};
135 const uint8x16_t a2=vld1q_u8(wa2), b2=vld1q_u8(wb2);
137 const uint64x2_t r1 =
PMULL_00(a1, b1);
138 const uint64x2_t r2 =
PMULL_11(vreinterpretq_u64_u8(a2),
139 vreinterpretq_u64_u8(b2));
141 result = !!(vgetq_lane_u64(r1,0) == 0x5300530053005300 &&
142 vgetq_lane_u64(r1,1) == 0x5300530053005300 &&
143 vgetq_lane_u64(r2,0) == 0x6c006c006c006c00 &&
144 vgetq_lane_u64(r2,1) == 0x6c006c006c006c00);
147 sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR);
148 signal(SIGILL, oldHandler);
159#if CRYPTOPP_ARM_NEON_AVAILABLE
160void GCM_Xor16_NEON(
byte *a,
const byte *b,
const byte *c)
162 vst1q_u8(a, veorq_u8(vld1q_u8(b), vld1q_u8(c)));
166#if CRYPTOPP_ARM_PMULL_AVAILABLE
169inline uint64x2_t SwapWords(
const uint64x2_t& data)
171 return (uint64x2_t)vcombine_u64(
172 vget_high_u64(data), vget_low_u64(data));
175uint64x2_t GCM_Reduce_PMULL(uint64x2_t c0, uint64x2_t c1, uint64x2_t c2,
const uint64x2_t &r)
177 c1 = veorq_u64(c1, VEXT_U8<8>(vdupq_n_u64(0), c0));
178 c1 = veorq_u64(c1,
PMULL_01(c0, r));
179 c0 = VEXT_U8<8>(c0, vdupq_n_u64(0));
180 c0 = vshlq_n_u64(veorq_u64(c0, c1), 1);
182 c2 = veorq_u64(c2, c0);
183 c2 = veorq_u64(c2, VEXT_U8<8>(c1, vdupq_n_u64(0)));
184 c1 = vshrq_n_u64(vcombine_u64(vget_low_u64(c1), vget_low_u64(c2)), 63);
185 c2 = vshlq_n_u64(c2, 1);
187 return veorq_u64(c2, c1);
190uint64x2_t GCM_Multiply_PMULL(
const uint64x2_t &x,
const uint64x2_t &h,
const uint64x2_t &r)
192 const uint64x2_t c0 =
PMULL_00(x, h);
194 const uint64x2_t c2 =
PMULL_11(x, h);
196 return GCM_Reduce_PMULL(c0, c1, c2, r);
199void GCM_SetKeyWithoutResync_PMULL(
const byte *hashKey,
byte *mulTable,
unsigned int tableSize)
201 const uint64x2_t r = {0xe100000000000000ull, 0xc200000000000000ull};
202 const uint64x2_t t = vreinterpretq_u64_u8(vrev64q_u8(vld1q_u8(hashKey)));
203 const uint64x2_t h0 = vextq_u64(t, t, 1);
207 for (i=0; i<tableSize-32; i+=32)
209 const uint64x2_t h1 = GCM_Multiply_PMULL(h, h0, r);
210 vst1_u64(UINT64_CAST(mulTable+i), vget_low_u64(h));
211 vst1q_u64(UINT64_CAST(mulTable+i+16), h1);
212 vst1q_u64(UINT64_CAST(mulTable+i+8), h);
213 vst1_u64(UINT64_CAST(mulTable+i+8), vget_low_u64(h1));
214 h = GCM_Multiply_PMULL(h1, h0, r);
217 const uint64x2_t h1 = GCM_Multiply_PMULL(h, h0, r);
218 vst1_u64(UINT64_CAST(mulTable+i), vget_low_u64(h));
219 vst1q_u64(UINT64_CAST(mulTable+i+16), h1);
220 vst1q_u64(UINT64_CAST(mulTable+i+8), h);
221 vst1_u64(UINT64_CAST(mulTable+i+8), vget_low_u64(h1));
224size_t GCM_AuthenticateBlocks_PMULL(
const byte *data,
size_t len,
const byte *mtable,
byte *hbuffer)
226 const uint64x2_t r = {0xe100000000000000ull, 0xc200000000000000ull};
227 uint64x2_t x = vreinterpretq_u64_u8(vld1q_u8(hbuffer));
232 uint64x2_t d1, d2 = vreinterpretq_u64_u8(vrev64q_u8(vld1q_u8(data+(s-1)*16U)));
233 uint64x2_t c0 = vdupq_n_u64(0);
234 uint64x2_t c1 = vdupq_n_u64(0);
235 uint64x2_t c2 = vdupq_n_u64(0);
239 const uint64x2_t h0 = vld1q_u64(CONST_UINT64_CAST(mtable+(i+0)*16));
240 const uint64x2_t h1 = vld1q_u64(CONST_UINT64_CAST(mtable+(i+1)*16));
241 const uint64x2_t h2 = veorq_u64(h0, h1);
245 const uint64x2_t t1 = vreinterpretq_u64_u8(vrev64q_u8(vld1q_u8(data)));
246 d1 = veorq_u64(vextq_u64(t1, t1, 1), x);
247 c0 = veorq_u64(c0,
PMULL_00(d1, h0));
248 c2 = veorq_u64(c2,
PMULL_10(d1, h1));
249 d1 = veorq_u64(d1, SwapWords(d1));
250 c1 = veorq_u64(c1,
PMULL_00(d1, h2));
255 d1 = vreinterpretq_u64_u8(vrev64q_u8(vld1q_u8(data+(s-i)*16-8)));
256 c0 = veorq_u64(c0,
PMULL_10(d2, h0));
257 c2 = veorq_u64(c2,
PMULL_10(d1, h1));
258 d2 = veorq_u64(d2, d1);
259 c1 = veorq_u64(c1,
PMULL_10(d2, h2));
263 const uint64x2_t t2 = vreinterpretq_u64_u8(vrev64q_u8(vld1q_u8(data)));
264 d1 = veorq_u64(vextq_u64(t2, t2, 1), x);
265 c0 = veorq_u64(c0,
PMULL_01(d1, h0));
266 c2 = veorq_u64(c2,
PMULL_11(d1, h1));
267 d1 = veorq_u64(d1, SwapWords(d1));
268 c1 = veorq_u64(c1,
PMULL_01(d1, h2));
273 const uint64x2_t t3 = vreinterpretq_u64_u8(vrev64q_u8(vld1q_u8(data+(s-i)*16-8)));
274 d2 = vextq_u64(t3, t3, 1);
275 c0 = veorq_u64(c0,
PMULL_01(d1, h0));
276 c2 = veorq_u64(c2,
PMULL_01(d2, h1));
277 d1 = veorq_u64(d1, d2);
278 c1 = veorq_u64(c1,
PMULL_01(d1, h2));
283 c1 = veorq_u64(veorq_u64(c1, c0), c2);
284 x = GCM_Reduce_PMULL(c0, c1, c2, r);
287 vst1q_u64(UINT64_CAST(hbuffer), x);
291void GCM_ReverseHashBufferIfNeeded_PMULL(
byte *hashBuffer)
295 const uint8x16_t x = vrev64q_u8(vld1q_u8(hashBuffer));
296 vst1q_u8(hashBuffer, vextq_u8(x, x, 8));
303#if CRYPTOPP_SSE2_INTRIN_AVAILABLE || CRYPTOPP_SSE2_ASM_AVAILABLE
306void GCM_Xor16_SSE2(
byte *a,
const byte *b,
const byte *c)
308# if CRYPTOPP_SSE2_ASM_AVAILABLE && defined(__GNUC__)
309 asm (
"movdqa %1, %%xmm0; pxor %2, %%xmm0; movdqa %%xmm0, %0;"
310 :
"=m" (a[0]) :
"m"(b[0]),
"m"(c[0]));
312 _mm_store_si128(
M128_CAST(a), _mm_xor_si128(
319#if CRYPTOPP_CLMUL_AVAILABLE
323void gcm_gf_mult(
const unsigned char *a,
const unsigned char *b,
unsigned char *c)
325 word64 Z0=0, Z1=0, V0, V1;
328 Block::Get(a)(V0)(V1);
330 for (
int i=0; i<16; i++)
332 for (
int j=0x80; j!=0; j>>=1)
338 V1 = (V1>>1) | (V0<<63);
339 V0 = (V0>>1) ^ (x ?
W64LIT(0xe1) << 56 : 0);
345__m128i _mm_clmulepi64_si128(
const __m128i &a,
const __m128i &b,
int i)
355 for (
int i=0; i<16; i++)
356 ((
byte *)&output)[i] = c.GetByte(i);
362inline __m128i SwapWords(
const __m128i& val)
364 return _mm_shuffle_epi32(val, _MM_SHUFFLE(1, 0, 3, 2));
369inline __m128i GCM_Reduce_CLMUL(__m128i c0, __m128i c1, __m128i c2,
const __m128i& r)
383 c1 = _mm_xor_si128(c1, _mm_slli_si128(c0, 8));
384 c1 = _mm_xor_si128(c1, _mm_clmulepi64_si128(c0, r, 0x10));
385 c0 = _mm_xor_si128(c1, _mm_srli_si128(c0, 8));
386 c0 = _mm_slli_epi64(c0, 1);
387 c0 = _mm_clmulepi64_si128(c0, r, 0);
388 c2 = _mm_xor_si128(c2, c0);
389 c2 = _mm_xor_si128(c2, _mm_srli_si128(c1, 8));
390 c1 = _mm_unpacklo_epi64(c1, c2);
391 c1 = _mm_srli_epi64(c1, 63);
392 c2 = _mm_slli_epi64(c2, 1);
393 return _mm_xor_si128(c2, c1);
398__m128i GCM_Multiply_CLMUL(
const __m128i &x,
const __m128i &h,
const __m128i &r)
400 const __m128i c0 = _mm_clmulepi64_si128(x,h,0);
401 const __m128i c1 = _mm_xor_si128(_mm_clmulepi64_si128(x,h,1), _mm_clmulepi64_si128(x,h,0x10));
402 const __m128i c2 = _mm_clmulepi64_si128(x,h,0x11);
404 return GCM_Reduce_CLMUL(c0, c1, c2, r);
407void GCM_SetKeyWithoutResync_CLMUL(
const byte *hashKey,
byte *mulTable,
unsigned int tableSize)
409 const __m128i r = _mm_set_epi32(0xc2000000, 0x00000000, 0xe1000000, 0x00000000);
410 const __m128i m = _mm_set_epi32(0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f);
411 __m128i h0 = _mm_shuffle_epi8(_mm_load_si128(
CONST_M128_CAST(hashKey)), m), h = h0;
414 for (i=0; i<tableSize-32; i+=32)
416 const __m128i h1 = GCM_Multiply_CLMUL(h, h0, r);
417 _mm_storel_epi64(
M128_CAST(mulTable+i), h);
418 _mm_storeu_si128(
M128_CAST(mulTable+i+16), h1);
419 _mm_storeu_si128(
M128_CAST(mulTable+i+8), h);
420 _mm_storel_epi64(
M128_CAST(mulTable+i+8), h1);
421 h = GCM_Multiply_CLMUL(h1, h0, r);
424 const __m128i h1 = GCM_Multiply_CLMUL(h, h0, r);
425 _mm_storel_epi64(
M128_CAST(mulTable+i), h);
426 _mm_storeu_si128(
M128_CAST(mulTable+i+16), h1);
427 _mm_storeu_si128(
M128_CAST(mulTable+i+8), h);
428 _mm_storel_epi64(
M128_CAST(mulTable+i+8), h1);
431size_t GCM_AuthenticateBlocks_CLMUL(
const byte *data,
size_t len,
const byte *mtable,
byte *hbuffer)
433 const __m128i r = _mm_set_epi32(0xc2000000, 0x00000000, 0xe1000000, 0x00000000);
434 const __m128i m1 = _mm_set_epi32(0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f);
435 const __m128i m2 = _mm_set_epi32(0x08090a0b, 0x0c0d0e0f, 0x00010203, 0x04050607);
436 __m128i x = _mm_load_si128(
M128_CAST(hbuffer));
442 __m128i d2 = _mm_shuffle_epi8(d1, m2);
443 __m128i c0 = _mm_setzero_si128();
444 __m128i c1 = _mm_setzero_si128();
445 __m128i c2 = _mm_setzero_si128();
451 const __m128i h2 = _mm_xor_si128(h0, h1);
456 d1 = _mm_xor_si128(d1, x);
457 c0 = _mm_xor_si128(c0, _mm_clmulepi64_si128(d1, h0, 0));
458 c2 = _mm_xor_si128(c2, _mm_clmulepi64_si128(d1, h1, 1));
459 d1 = _mm_xor_si128(d1, SwapWords(d1));
460 c1 = _mm_xor_si128(c1, _mm_clmulepi64_si128(d1, h2, 0));
464 d1 = _mm_shuffle_epi8(_mm_loadu_si128(
CONST_M128_CAST(data+(s-i)*16-8)), m2);
465 c0 = _mm_xor_si128(c0, _mm_clmulepi64_si128(d2, h0, 1));
466 c2 = _mm_xor_si128(c2, _mm_clmulepi64_si128(d1, h1, 1));
467 d2 = _mm_xor_si128(d2, d1);
468 c1 = _mm_xor_si128(c1, _mm_clmulepi64_si128(d2, h2, 1));
473 d1 = _mm_xor_si128(d1, x);
474 c0 = _mm_xor_si128(c0, _mm_clmulepi64_si128(d1, h0, 0x10));
475 c2 = _mm_xor_si128(c2, _mm_clmulepi64_si128(d1, h1, 0x11));
476 d1 = _mm_xor_si128(d1, SwapWords(d1));
477 c1 = _mm_xor_si128(c1, _mm_clmulepi64_si128(d1, h2, 0x10));
481 d2 = _mm_shuffle_epi8(_mm_loadu_si128(
CONST_M128_CAST(data+(s-i)*16-8)), m1);
482 c0 = _mm_xor_si128(c0, _mm_clmulepi64_si128(d1, h0, 0x10));
483 c2 = _mm_xor_si128(c2, _mm_clmulepi64_si128(d2, h1, 0x10));
484 d1 = _mm_xor_si128(d1, d2);
485 c1 = _mm_xor_si128(c1, _mm_clmulepi64_si128(d1, h2, 0x10));
490 c1 = _mm_xor_si128(_mm_xor_si128(c1, c0), c2);
491 x = GCM_Reduce_CLMUL(c0, c1, c2, r);
498void GCM_ReverseHashBufferIfNeeded_CLMUL(
byte *hashBuffer)
501 const __m128i mask = _mm_set_epi32(0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f);
502 _mm_storeu_si128(
M128_CAST(hashBuffer), _mm_shuffle_epi8(
509#if CRYPTOPP_POWER8_AVAILABLE
510void GCM_Xor16_POWER8(
byte *a,
const byte *b,
const byte *c)
516#if CRYPTOPP_POWER8_VMULL_AVAILABLE
522 c1 =
VecXor(c1, VecShiftRightOctet<8>(c0));
524 c0 =
VecXor(c1, VecShiftLeftOctet<8>(c0));
527 c2 =
VecXor(c2, VecShiftLeftOctet<8>(c1));
528 c1 = vec_sr(vec_mergeh(c1, c2), m63);
540 return GCM_Reduce_VMULL(c0, c1, c2, r);
543inline uint64x2_p LoadHashKey(
const byte *hashKey)
545#if (CRYPTOPP_BIG_ENDIAN)
547 const uint8x16_p mask = {8,9,10,11, 12,13,14,15, 0,1,2,3, 4,5,6,7};
551 const uint8x16_p mask = {15,14,13,12, 11,10,9,8, 7,6,5,4, 3,2,1,0};
556void GCM_SetKeyWithoutResync_VMULL(
const byte *hashKey,
byte *mulTable,
unsigned int tableSize)
558 const uint64x2_p r = {0xe100000000000000ull, 0xc200000000000000ull};
564 for (i=0; i<tableSize-32; i+=32)
566 const uint64x2_p h1 = GCM_Multiply_VMULL(h, h0, r);
568 std::memcpy(mulTable+i, temp+0, 8);
572 std::memcpy(mulTable+i+8, temp+0, 8);
573 h = GCM_Multiply_VMULL(h1, h0, r);
576 const uint64x2_p h1 = GCM_Multiply_VMULL(h, h0, r);
578 std::memcpy(mulTable+i, temp+0, 8);
582 std::memcpy(mulTable+i+8, temp+0, 8);
587inline T SwapWords(
const T& data)
589 return (T)VecRotateLeftOctet<8>(data);
592inline uint64x2_p LoadBuffer1(
const byte *dataBuffer)
594#if (CRYPTOPP_BIG_ENDIAN)
598 const uint8x16_p mask = {7,6,5,4, 3,2,1,0, 15,14,13,12, 11,10,9,8};
603inline uint64x2_p LoadBuffer2(
const byte *dataBuffer)
605#if (CRYPTOPP_BIG_ENDIAN)
612size_t GCM_AuthenticateBlocks_VMULL(
const byte *data,
size_t len,
const byte *mtable,
byte *hbuffer)
614 const uint64x2_p r = {0xe100000000000000ull, 0xc200000000000000ull};
620 uint64x2_p d1, d2 = LoadBuffer1(data+(s-1)*16);
631 d1 = LoadBuffer2(data);
635 d1 =
VecXor(d1, SwapWords(d1));
640 d1 = LoadBuffer1(data+(s-i)*16-8);
648 d1 = LoadBuffer2(data);
652 d1 =
VecXor(d1, SwapWords(d1));
657 d2 = LoadBuffer2(data+(s-i)*16-8);
667 x = GCM_Reduce_VMULL(c0, c1, c2, r);
674void GCM_ReverseHashBufferIfNeeded_VMULL(
byte *hashBuffer)
676 const uint64x2_p mask = {0x08090a0b0c0d0e0full, 0x0001020304050607ull};
#define M128_CAST(x)
Clang workaround.
#define CONST_M128_CAST(x)
Clang workaround.
Support functions for ARM and vector operations.
uint64x2_t PMULL_00(const uint64x2_t a, const uint64x2_t b)
Polynomial multiplication.
uint64x2_t PMULL_11(const uint64x2_t a, const uint64x2_t b)
Polynomial multiplication.
uint64x2_t PMULL_01(const uint64x2_t a, const uint64x2_t b)
Polynomial multiplication.
uint64x2_t PMULL_10(const uint64x2_t a, const uint64x2_t b)
Polynomial multiplication.
Polynomial with Coefficients in GF(2)
Access a block of memory.
Library configuration file.
#define W64LIT(x)
Declare an unsigned word64.
unsigned long long word64
64-bit unsigned datatype
@ BIG_ENDIAN_ORDER
byte order is big-endian
Utility functions for the Crypto++ library.
byte ByteReverse(byte value)
Reverses bytes in a 8-bit value.
const T1 UnsignedMin(const T1 &a, const T2 &b)
Safe comparison of values that could be negative and incorrectly promoted.
ByteOrder GetNativeByteOrder()
Returns NativeByteOrder as an enumerated ByteOrder value.
Crypto++ library namespace.
Support functions for PowerPC and vector operations.
uint32x4_p VecLoadBE(const byte src[16])
Loads a vector from a byte array.
T1 VecPermute(const T1 vec, const T2 mask)
Permutes a vector.
uint64x2_p VecIntelMultiply00(const uint64x2_p &a, const uint64x2_p &b)
Polynomial multiplication.
__vector unsigned char uint8x16_p
Vector of 8-bit elements.
T1 VecXor(const T1 vec1, const T2 vec2)
XOR two vectors.
__vector unsigned long long uint64x2_p
Vector of 64-bit elements.
uint64x2_p VecIntelMultiply11(const uint64x2_p &a, const uint64x2_p &b)
Polynomial multiplication.
void VecStore(const T data, byte dest[16])
Stores a vector to a byte array.
uint64x2_p VecIntelMultiply01(const uint64x2_p &a, const uint64x2_p &b)
Polynomial multiplication.
uint32x4_p VecLoad(const byte src[16])
Loads a vector from a byte array.
uint64x2_p VecIntelMultiply10(const uint64x2_p &a, const uint64x2_p &b)
Polynomial multiplication.
Access a block of memory.