Crypto++  7.0
Free C++ class library of cryptographic schemes
ppc-simd.cpp
1 // ppc-simd.cpp - written and placed in the public domain by
2 // Jeffrey Walton, Uri Blumenthal and Marcel Raad.
3 //
4 // This source file uses intrinsics to gain access to AltiVec,
5 // Power8 and in-core crypto instructions. A separate source file
6 // is needed because additional CXXFLAGS are required to enable the
7 // appropriate instructions sets in some build configurations.
8 
9 // TODO: we still need to implement Power8 SHA. Once we have Power8 SHA,
10 // we should be able to use CRYPTOPP_POWER8_AES_AVAILABLE and
11 // CRYPTOPP_POWER8_SHA_AVAILABLE instead of the broader
12 // CRYPTOPP_POWER8_AVAILABLE. The change will need to be coordinated
13 // with the defines in config.h.
14 
15 // TODO: Bob Wilkinson reported we are misdetecting CRYPTOPP_POWER8_AVAILABLE.
16 // The problem is, the updated compiler supports them but the down-level
17 // assembler and linker do not. We will probably need to fix it through
18 // the makefile, similar to the way x86 AES and SHA are handled. For the time
19 // being CRYPTOPP_DISABLE_POWER8 will have to be applied manually. Another
20 // twist is, we don't have access to a test machine and it must be fixed
21 // for two compilers (IBM XL C/C++ and GCC). Ugh...
22 
23 #include "pch.h"
24 #include "config.h"
25 #include "stdcpp.h"
26 
27 #if defined(CRYPTOPP_ALTIVEC_AVAILABLE)
28 # include "ppc-simd.h"
29 #endif
30 
31 #ifdef CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY
32 # include <signal.h>
33 # include <setjmp.h>
34 #endif
35 
36 #ifndef EXCEPTION_EXECUTE_HANDLER
37 # define EXCEPTION_EXECUTE_HANDLER 1
38 #endif
39 
40 NAMESPACE_BEGIN(CryptoPP)
41 
42 #ifdef CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY
43 extern "C" {
44  typedef void (*SigHandler)(int);
45 
46  static jmp_buf s_jmpSIGILL;
47  static void SigIllHandler(int)
48  {
49  longjmp(s_jmpSIGILL, 1);
50  }
51 }
52 #endif // Not CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY
53 
54 #if (CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64)
55 bool CPU_ProbeAltivec()
56 {
57 #if defined(CRYPTOPP_NO_CPU_FEATURE_PROBES)
58  return false;
59 #elif (CRYPTOPP_ALTIVEC_AVAILABLE)
60 # if defined(CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY)
61 
62  // longjmp and clobber warnings. Volatile is required.
63  // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854
64  volatile int result = true;
65 
66  volatile SigHandler oldHandler = signal(SIGILL, SigIllHandler);
67  if (oldHandler == SIG_ERR)
68  return false;
69 
70  volatile sigset_t oldMask;
71  if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask))
72  return false;
73 
74  if (setjmp(s_jmpSIGILL))
75  result = false;
76  else
77  {
78  const byte b1[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
79  const byte b2[16] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
80  byte b3[16];
81 
82  const uint8x16_p v1 = (uint8x16_p)VectorLoad(0, b1);
83  const uint8x16_p v2 = (uint8x16_p)VectorLoad(0, b2);
84  const uint8x16_p v3 = (uint8x16_p)VectorXor(v1, v2);
85  VectorStore(v3, b3);
86 
87  result = (0 == std::memcmp(b2, b3, 16));
88  }
89 
90  sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR);
91  signal(SIGILL, oldHandler);
92  return result;
93 # endif
94 #else
95  return false;
96 #endif // CRYPTOPP_ALTIVEC_AVAILABLE
97 }
98 
99 bool CPU_ProbePower7()
100 {
101 #if defined(CRYPTOPP_NO_CPU_FEATURE_PROBES)
102  return false;
103 #elif (CRYPTOPP_POWER7_AVAILABLE)
104 # if defined(CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY)
105 
106  // longjmp and clobber warnings. Volatile is required.
107  // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854
108  volatile int result = false;
109 
110  volatile SigHandler oldHandler = signal(SIGILL, SigIllHandler);
111  if (oldHandler == SIG_ERR)
112  return false;
113 
114  volatile sigset_t oldMask;
115  if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask))
116  return false;
117 
118  if (setjmp(s_jmpSIGILL))
119  result = false;
120  else
121  {
122  byte b1[19] = {255, 255, 255, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, b2[17];
123  const uint8x16_p v1 = (uint8x16_p)VectorLoad(0, b1+3);
124  VectorStore(v1, b2+1);
125 
126  result = (0 == std::memcmp(b1+3, b2+1, 16));
127  }
128 
129  sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR);
130  signal(SIGILL, oldHandler);
131  return result;
132 # endif
133 #else
134  return false;
135 #endif // CRYPTOPP_POWER7_AVAILABLE
136 }
137 
138 bool CPU_ProbePower8()
139 {
140 #if defined(CRYPTOPP_NO_CPU_FEATURE_PROBES)
141  return false;
142 #elif (CRYPTOPP_POWER8_AVAILABLE)
143 # if defined(CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY)
144 
145  // longjmp and clobber warnings. Volatile is required.
146  // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854
147  volatile int result = true;
148 
149  volatile SigHandler oldHandler = signal(SIGILL, SigIllHandler);
150  if (oldHandler == SIG_ERR)
151  return false;
152 
153  volatile sigset_t oldMask;
154  if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask))
155  return false;
156 
157  if (setjmp(s_jmpSIGILL))
158  result = false;
159  else
160  {
161  byte b1[19] = {255, 255, 255, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, b2[17];
162  const uint8x16_p v1 = (uint8x16_p)VectorLoad(0, b1+3);
163  VectorStore(v1, b2+1);
164 
165  result = (0 == std::memcmp(b1+3, b2+1, 16));
166  }
167 
168  sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR);
169  signal(SIGILL, oldHandler);
170  return result;
171 # endif
172 #else
173  return false;
174 #endif // CRYPTOPP_POWER8_AVAILABLE
175 }
176 
177 bool CPU_ProbeAES()
178 {
179 #if defined(CRYPTOPP_NO_CPU_FEATURE_PROBES)
180  return false;
181 #elif (CRYPTOPP_POWER8_AVAILABLE)
182 # if defined(CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY)
183 
184  // longjmp and clobber warnings. Volatile is required.
185  // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854
186  volatile int result = true;
187 
188  volatile SigHandler oldHandler = signal(SIGILL, SigIllHandler);
189  if (oldHandler == SIG_ERR)
190  return false;
191 
192  volatile sigset_t oldMask;
193  if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask))
194  return false;
195 
196  if (setjmp(s_jmpSIGILL))
197  result = false;
198  else
199  {
200  byte key[16] = {0xA0, 0xFA, 0xFE, 0x17, 0x88, 0x54, 0x2c, 0xb1,
201  0x23, 0xa3, 0x39, 0x39, 0x2a, 0x6c, 0x76, 0x05};
202  byte state[16] = {0x19, 0x3d, 0xe3, 0xb3, 0xa0, 0xf4, 0xe2, 0x2b,
203  0x9a, 0xc6, 0x8d, 0x2a, 0xe9, 0xf8, 0x48, 0x08};
204  byte r[16] = {255}, z[16] = {};
205 
206  uint8x16_p k = (uint8x16_p)VectorLoad(0, key);
207  uint8x16_p s = (uint8x16_p)VectorLoad(0, state);
208  s = VectorEncrypt(s, k);
209  s = VectorEncryptLast(s, k);
210  s = VectorDecrypt(s, k);
211  s = VectorDecryptLast(s, k);
212  VectorStore(s, r);
213 
214  result = (0 != std::memcmp(r, z, 16));
215  }
216 
217  sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR);
218  signal(SIGILL, oldHandler);
219  return result;
220 # endif
221 #else
222  return false;
223 #endif // CRYPTOPP_ALTIVEC_AVAILABLE
224 }
225 
226 bool CPU_ProbeSHA256()
227 {
228 #if defined(CRYPTOPP_NO_CPU_FEATURE_PROBES)
229  return false;
230 #elif (CRYPTOPP_POWER8_AVAILABLE)
231 # if defined(CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY)
232 
233  // longjmp and clobber warnings. Volatile is required.
234  // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854
235  volatile int result = false;
236 
237  volatile SigHandler oldHandler = signal(SIGILL, SigIllHandler);
238  if (oldHandler == SIG_ERR)
239  return false;
240 
241  volatile sigset_t oldMask;
242  if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask))
243  return false;
244 
245  if (setjmp(s_jmpSIGILL))
246  result = false;
247  else
248  {
249  byte r[16], z[16] = {0};
250  uint8x16_p x = ((uint8x16_p){0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0});
251 
252  x = VectorSHA256<0,0>(x);
253  x = VectorSHA256<0,1>(x);
254  x = VectorSHA256<1,0>(x);
255  x = VectorSHA256<1,1>(x);
256  VectorStore(x, r);
257 
258  result = (0 == std::memcmp(r, z, 16));
259  }
260 
261  sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR);
262  signal(SIGILL, oldHandler);
263  return result;
264 # endif
265 #else
266  return false;
267 #endif // CRYPTOPP_ALTIVEC_AVAILABLE
268 }
269 
270 bool CPU_ProbeSHA512()
271 {
272 #if defined(CRYPTOPP_NO_CPU_FEATURE_PROBES)
273  return false;
274 #elif (CRYPTOPP_POWER8_AVAILABLE)
275 # if defined(CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY)
276 
277  // longjmp and clobber warnings. Volatile is required.
278  // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854
279  volatile int result = false;
280 
281  volatile SigHandler oldHandler = signal(SIGILL, SigIllHandler);
282  if (oldHandler == SIG_ERR)
283  return false;
284 
285  volatile sigset_t oldMask;
286  if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask))
287  return false;
288 
289  if (setjmp(s_jmpSIGILL))
290  result = false;
291  else
292  {
293  byte r[16], z[16] = {0};
294  uint8x16_p x = ((uint8x16_p){0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0});
295 
296  x = VectorSHA512<0,0>(x);
297  x = VectorSHA512<0,1>(x);
298  x = VectorSHA512<1,0>(x);
299  x = VectorSHA512<1,1>(x);
300  VectorStore(x, r);
301 
302  result = (0 == std::memcmp(r, z, 16));
303  }
304 
305  sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR);
306  signal(SIGILL, oldHandler);
307  return result;
308 # endif
309 #else
310  return false;
311 #endif // CRYPTOPP_POWER8_AVAILABLE
312 }
313 # endif // CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64
314 NAMESPACE_END
T1 VectorEncrypt(const T1 &state, const T2 &key)
One round of AES encryption.
Definition: ppc-simd.h:438
T1 VectorEncryptLast(const T1 &state, const T2 &key)
Final round of AES encryption.
Definition: ppc-simd.h:458
Library configuration file.
T1 VectorDecryptLast(const T1 &state, const T2 &key)
Final round of AES decryption.
Definition: ppc-simd.h:498
Common C++ header files.
Support functions for PowerPC and vector operations.
uint32x4_p VectorLoad(const byte src[16])
Loads a vector from a byte array.
Definition: ppc-simd.h:188
Precompiled header file.
T1 VectorXor(const T1 &vec1, const T2 &vec2)
XOR two vectors.
Definition: ppc-simd.h:373
T1 VectorDecrypt(const T1 &state, const T2 &key)
One round of AES decryption.
Definition: ppc-simd.h:478
Crypto++ library namespace.
void VectorStore(const T &src, byte dest[16])
Stores a vector to a byte array.
Definition: ppc-simd.h:310