Crypto++ 8.6
Free C++ class library of cryptographic schemes
ppc_power8.cpp
1// ppc_power8.cpp - written and placed in the public domain by
2// Jeffrey Walton, Uri Blumenthal and Marcel Raad.
3//
4// This source file uses intrinsics and built-ins to gain access to
5// Power8 instructions. A separate source file is needed because
6// additional CXXFLAGS are required to enable the appropriate
7// instructions sets in some build configurations.
8
9#include "pch.h"
10#include "config.h"
11
12#ifdef CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY
13# include <signal.h>
14# include <setjmp.h>
15#endif
16
17#if defined(_ARCH_PWR8) || defined(__CRYPTO__)
18# include "ppc_simd.h"
19#endif
20
21// Squash MS LNK4221 and libtool warnings
22extern const char PPC_POWER8_FNAME[] = __FILE__;
23
24NAMESPACE_BEGIN(CryptoPP)
25
26// ************************* Feature Probes ************************* //
27
28#ifdef CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY
29extern "C" {
30 typedef void (*SigHandler)(int);
31
32 static jmp_buf s_jmpSIGILL;
33 static void SigIllHandler(int)
34 {
35 longjmp(s_jmpSIGILL, 1);
36 }
37}
38#endif // CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY
39
40#if (CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64)
41
42bool CPU_ProbePower8()
43{
44#if defined(CRYPTOPP_NO_CPU_FEATURE_PROBES)
45 return false;
46#elif (_ARCH_PWR8) && defined(CRYPTOPP_POWER8_AVAILABLE)
47# if defined(CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY)
48
49 // longjmp and clobber warnings. Volatile is required.
50 // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854
51 volatile int result = true;
52
53 volatile SigHandler oldHandler = signal(SIGILL, SigIllHandler);
54 if (oldHandler == SIG_ERR)
55 return false;
56
57 volatile sigset_t oldMask;
58 if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask))
59 {
60 signal(SIGILL, oldHandler);
61 return false;
62 }
63
64 if (setjmp(s_jmpSIGILL))
65 result = false;
66 else
67 {
68 // POWER8 added 64-bit SIMD operations
69 const word64 x = W64LIT(0xffffffffffffffff);
70 word64 w1[2] = {x, x}, w2[2] = {4, 6}, w3[2];
71
72 // Specifically call the VSX loads and stores with 64-bit types
73 #if defined(__ibmxl__) || (defined(_AIX) && defined(__xlC__)) || defined(__clang__)
74 const uint64x2_p v1 = vec_xl(0, (unsigned long long*)w1);
75 const uint64x2_p v2 = vec_xl(0, (unsigned long long*)w2);
76 const uint64x2_p v3 = vec_add(v1, v2); // 64-bit add
77 vec_xst(v3, 0, (unsigned long long*)w3);
78 #else
79 const uint64x2_p v1 = (uint64x2_p)vec_vsx_ld(0, (const byte*)w1);
80 const uint64x2_p v2 = (uint64x2_p)vec_vsx_ld(0, (const byte*)w2);
81 const uint64x2_p v3 = vec_add(v1, v2); // 64-bit add
82 vec_vsx_st((uint8x16_p)v3, 0, (byte*)w3);
83 #endif
84
85 // Relies on integer wrap
86 result = (w3[0] == 3 && w3[1] == 5);
87 }
88
89 sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR);
90 signal(SIGILL, oldHandler);
91 return result;
92# endif
93#else
94 return false;
95#endif // _ARCH_PWR8
96}
97
98bool CPU_ProbeAES()
99{
100#if defined(CRYPTOPP_NO_CPU_FEATURE_PROBES)
101 return false;
102#elif (__CRYPTO__) && defined(CRYPTOPP_POWER8_AES_AVAILABLE)
103# if defined(CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY)
104
105 // longjmp and clobber warnings. Volatile is required.
106 // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854
107 volatile int result = true;
108
109 volatile SigHandler oldHandler = signal(SIGILL, SigIllHandler);
110 if (oldHandler == SIG_ERR)
111 return false;
112
113 volatile sigset_t oldMask;
114 if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask))
115 {
116 signal(SIGILL, oldHandler);
117 return false;
118 }
119
120 if (setjmp(s_jmpSIGILL))
121 result = false;
122 else
123 {
124 byte key[16] = {0xA0, 0xFA, 0xFE, 0x17, 0x88, 0x54, 0x2c, 0xb1,
125 0x23, 0xa3, 0x39, 0x39, 0x2a, 0x6c, 0x76, 0x05};
126 byte state[16] = {0x19, 0x3d, 0xe3, 0xb3, 0xa0, 0xf4, 0xe2, 0x2b,
127 0x9a, 0xc6, 0x8d, 0x2a, 0xe9, 0xf8, 0x48, 0x08};
128 byte r[16] = {255}, z[16] = {};
129
130 uint8x16_p k = (uint8x16_p)VecLoad(0, key);
131 uint8x16_p s = (uint8x16_p)VecLoad(0, state);
132 s = VecEncrypt(s, k);
133 s = VecEncryptLast(s, k);
134 s = VecDecrypt(s, k);
135 s = VecDecryptLast(s, k);
136 VecStore(s, r);
137
138 result = (0 != std::memcmp(r, z, 16));
139 }
140
141 sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR);
142 signal(SIGILL, oldHandler);
143 return result;
144# endif
145#else
146 return false;
147#endif // __CRYPTO__
148}
149
150bool CPU_ProbeSHA256()
151{
152#if defined(CRYPTOPP_NO_CPU_FEATURE_PROBES)
153 return false;
154#elif (__CRYPTO__) && defined(CRYPTOPP_POWER8_SHA_AVAILABLE)
155# if defined(CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY)
156
157 // longjmp and clobber warnings. Volatile is required.
158 // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854
159 volatile int result = false;
160
161 volatile SigHandler oldHandler = signal(SIGILL, SigIllHandler);
162 if (oldHandler == SIG_ERR)
163 return false;
164
165 volatile sigset_t oldMask;
166 if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask))
167 {
168 signal(SIGILL, oldHandler);
169 return false;
170 }
171
172 if (setjmp(s_jmpSIGILL))
173 result = false;
174 else
175 {
176 byte r[16], z[16] = {0};
177 uint8x16_p x = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
178
179 x = VecSHA256<0,0>(x);
180 x = VecSHA256<0,0xf>(x);
181 x = VecSHA256<1,0>(x);
182 x = VecSHA256<1,0xf>(x);
183 VecStore(x, r);
184
185 result = (0 == std::memcmp(r, z, 16));
186 }
187
188 sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR);
189 signal(SIGILL, oldHandler);
190 return result;
191# endif
192#else
193 return false;
194#endif // CRYPTOPP_ALTIVEC_AVAILABLE
195}
196
197bool CPU_ProbeSHA512()
198{
199#if defined(CRYPTOPP_NO_CPU_FEATURE_PROBES)
200 return false;
201#elif (__CRYPTO__) && defined(CRYPTOPP_POWER8_SHA_AVAILABLE)
202# if defined(CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY)
203
204 // longjmp and clobber warnings. Volatile is required.
205 // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854
206 volatile int result = false;
207
208 volatile SigHandler oldHandler = signal(SIGILL, SigIllHandler);
209 if (oldHandler == SIG_ERR)
210 return false;
211
212 volatile sigset_t oldMask;
213 if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask))
214 {
215 signal(SIGILL, oldHandler);
216 return false;
217 }
218
219 if (setjmp(s_jmpSIGILL))
220 result = false;
221 else
222 {
223 byte r[16], z[16] = {0};
224 uint8x16_p x = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
225
226 x = VecSHA512<0,0>(x);
227 x = VecSHA512<0,0xf>(x);
228 x = VecSHA512<1,0>(x);
229 x = VecSHA512<1,0xf>(x);
230 VecStore(x, r);
231
232 result = (0 == std::memcmp(r, z, 16));
233 }
234
235 sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR);
236 signal(SIGILL, oldHandler);
237 return result;
238# endif
239#else
240 return false;
241#endif // CRYPTOPP_POWER8_AVAILABLE
242}
243
244#endif // PPC32 or PPC64
245
246NAMESPACE_END
Library configuration file.
#define W64LIT(x)
Declare an unsigned word64.
Definition: config_int.h:119
unsigned long long word64
64-bit unsigned datatype
Definition: config_int.h:91
Crypto++ library namespace.
Precompiled header file.
Support functions for PowerPC and vector operations.
__vector unsigned char uint8x16_p
Vector of 8-bit elements.
Definition: ppc_simd.h:192
__vector unsigned long long uint64x2_p
Vector of 64-bit elements.
Definition: ppc_simd.h:212
T1 VecEncryptLast(const T1 state, const T2 key)
Final round of AES encryption.
Definition: ppc_simd.h:2634
T1 VecEncrypt(const T1 state, const T2 key)
One round of AES encryption.
Definition: ppc_simd.h:2609
T1 VecDecryptLast(const T1 state, const T2 key)
Final round of AES decryption.
Definition: ppc_simd.h:2684
T1 VecDecrypt(const T1 state, const T2 key)
One round of AES decryption.
Definition: ppc_simd.h:2659
void VecStore(const T data, byte dest[16])
Stores a vector to a byte array.
Definition: ppc_simd.h:895
uint32x4_p VecLoad(const byte src[16])
Loads a vector from a byte array.
Definition: ppc_simd.h:369