Add Power8 SHA256 and SHA512 support (GH #513)

This commit is contained in:
Jeffrey Walton 2017-09-22 08:58:50 -04:00
parent 375d5e18b3
commit 3bd01f73ba
No known key found for this signature in database
GPG Key ID: B36AB348921B1838
6 changed files with 101 additions and 84 deletions

14
cpu.cpp
View File

@ -625,14 +625,14 @@ void DetectArmFeatures()
bool CRYPTOPP_SECTION_INIT g_PowerpcDetectionDone = false;
bool CRYPTOPP_SECTION_INIT g_hasAltivec = false, CRYPTOPP_SECTION_INIT g_hasPower8 = false;
bool CRYPTOPP_SECTION_INIT g_hasAES = false, CRYPTOPP_SECTION_INIT g_hasSHA1 = false, CRYPTOPP_SECTION_INIT g_hasSHA2 = false;
bool CRYPTOPP_SECTION_INIT g_hasAES = false, CRYPTOPP_SECTION_INIT g_hasSHA256 = false, CRYPTOPP_SECTION_INIT g_hasSHA512 = false;
word32 CRYPTOPP_SECTION_INIT g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE;
extern bool CPU_ProbeAltivec();
extern bool CPU_ProbePower8();
extern bool CPU_ProbeAES();
extern bool CPU_ProbeSHA1();
extern bool CPU_ProbeSHA2();
extern bool CPU_ProbeSHA256();
extern bool CPU_ProbeSHA512();
#ifndef PPC_FEATURE_HAS_ALTIVEC
# define PPC_FEATURE_HAS_ALTIVEC 0x10000000
@ -691,7 +691,7 @@ inline bool CPU_QueryAES()
return false;
}
inline bool CPU_QuerySHA1()
inline bool CPU_QuerySHA256()
{
// Power8 and ISA 2.07 provide in-core crypto. Glibc
// 2.24 or higher is required for PPC_FEATURE2_VEC_CRYPTO.
@ -703,7 +703,7 @@ inline bool CPU_QuerySHA1()
#endif
return false;
}
inline bool CPU_QuerySHA2()
inline bool CPU_QuerySHA512()
{
// Power8 and ISA 2.07 provide in-core crypto. Glibc
// 2.24 or higher is required for PPC_FEATURE2_VEC_CRYPTO.
@ -724,8 +724,8 @@ void DetectPowerpcFeatures()
g_hasPower8 = CPU_QueryPower8() || CPU_ProbePower8();
//g_hasPMULL = CPU_QueryPMULL() || CPU_ProbePMULL();
g_hasAES = CPU_QueryAES() || CPU_ProbeAES();
g_hasSHA1 = CPU_QuerySHA1() || CPU_ProbeSHA1();
g_hasSHA2 = CPU_QuerySHA2() || CPU_ProbeSHA2();
g_hasSHA256 = CPU_QuerySHA256() || CPU_ProbeSHA256();
g_hasSHA512 = CPU_QuerySHA512() || CPU_ProbeSHA512();
#if defined(_AIX)
// /usr/include/sys/systemcfg.h

18
cpu.h
View File

@ -398,7 +398,7 @@ inline bool HasSHA2()
// Hide from Doxygen
#ifndef CRYPTOPP_DOXYGEN_PROCESSING
extern bool g_PowerpcDetectionDone;
extern bool g_hasAltivec, g_hasPower7, g_hasPower8, g_hasAES, g_hasSHA1, g_hasSHA2;
extern bool g_hasAltivec, g_hasPower7, g_hasPower8, g_hasAES, g_hasSHA256, g_hasSHA512;
extern word32 g_cacheLineSize;
void CRYPTOPP_API DetectPowerpcFeatures();
#endif // CRYPTOPP_DOXYGEN_PROCESSING
@ -445,32 +445,32 @@ inline bool HasAES()
return g_hasAES;
}
//! \brief Determine if a PowerPC processor has SHA1 available
//! \returns true if the hardware is capable of SHA1 at runtime, false otherwise.
//! \brief Determine if a PowerPC processor has SHA256 available
//! \returns true if the hardware is capable of SHA256 at runtime, false otherwise.
//! \details SHA is part of the in-crypto extensions on Power8 and Power9.
//! \details Runtime support requires compile time support. When compiling with GCC, you may
//! need to compile with <tt>-mcpu=power8</tt>; while IBM XL C/C++ compilers require
//! <tt>-qarch=pwr8 -qaltivec</tt>. Also see PowerPC's <tt>__CRYPTO</tt> preprocessor macro.
//! \note This function is only available on PowerPC and PowerPC-64 platforms
inline bool HasSHA1()
inline bool HasSHA256()
{
if (!g_PowerpcDetectionDone)
DetectPowerpcFeatures();
return g_hasSHA1;
return g_hasSHA256;
}
//! \brief Determine if a PowerPC processor has SHA2 available
//! \returns true if the hardware is capable of SHA2 at runtime, false otherwise.
//! \brief Determine if a PowerPC processor has SHA512 available
//! \returns true if the hardware is capable of SHA512 at runtime, false otherwise.
//! \details SHA is part of the in-crypto extensions on Power8 and Power9.
//! \details Runtime support requires compile time support. When compiling with GCC, you may
//! need to compile with <tt>-mcpu=power8</tt>; while IBM XL C/C++ compilers require
//! <tt>-qarch=pwr8 -qaltivec</tt>. Also see PowerPC's <tt>__CRYPTO</tt> preprocessor macro.
//! \note This function is only available on PowerPC and PowerPC-64 platforms
inline bool HasSHA2()
inline bool HasSHA512()
{
if (!g_PowerpcDetectionDone)
DetectPowerpcFeatures();
return g_hasSHA2;
return g_hasSHA512;
}
//! \brief Provides the cache line size

View File

@ -23,22 +23,9 @@
# undef CRYPTOPP_POWER8_CRYPTO_AVAILABLE
#endif
#if defined(CRYPTOPP_ALTIVEC_AVAILABLE)
# include <altivec.h>
# undef vector
# undef pixel
# undef bool
#endif
#if defined(CRYPTOPP_ALTIVEC_AVAILABLE)
# if defined(CRYPTOPP_XLC_VERSION)
// #include <builtins.h>
typedef __vector unsigned char uint8x16_p8;
typedef __vector unsigned long long uint64x2_p8;
#elif defined(CRYPTOPP_GCC_VERSION)
typedef __vector unsigned char uint8x16_p8;
typedef __vector unsigned long long uint64x2_p8;
#endif
// TODO.. Change to CRYPTOPP_POWER8_CRYPTO_AVAILABLE
#if (CRYPTOPP_POWER8_AES_AVAILABLE)
# include "ppc-crypto.h"
#endif
#ifdef CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY
@ -94,14 +81,14 @@ bool CPU_ProbeAltivec()
const byte b2[16] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
CRYPTOPP_ALIGN_DATA(16) byte b3[16];
#if defined(CRYPTOPP_XLC_VERSION)
const uint8x16_p8 v1 = vec_ld(0, (const byte*)b1);
const uint8x16_p8 v2 = vec_ld(0, (const byte*)b2);
const uint8x16_p8 v3 = vec_xor(v1, v2);
const uint8x16_p8 v1 = VectorLoad(0, b1);
const uint8x16_p8 v2 = VectorLoad(0, b2);
const uint8x16_p8 v3 = VectorXor(v1, v2);
vec_st(v3, 0, (byte*)b3);
#elif defined(CRYPTOPP_GCC_VERSION)
const uint64x2_p8 v1 = (uint64x2_p8)vec_ld(0, (const byte*)b1);
const uint64x2_p8 v2 = (uint64x2_p8)vec_ld(0, (const byte*)b2);
const uint64x2_p8 v3 = (uint64x2_p8)vec_xor(v1, v2);
const uint64x2_p8 v1 = (uint64x2_p8)VectorLoad(0, b1);
const uint64x2_p8 v2 = (uint64x2_p8)VectorLoad(0, b2);
const uint64x2_p8 v3 = (uint64x2_p8)VectorXor(v1, v2);
vec_st((uint8x16_p8)v3, 0, (byte*)b3);
#endif
result = (0 == std::memcmp(b2, b3, 16));
@ -121,7 +108,7 @@ bool CPU_ProbePower7()
{
#if defined(CRYPTOPP_NO_CPU_FEATURE_PROBES)
return false;
#elif (CRYPTOPP_POWER7_AVAILABLE)
#elif (CRYPTOPP_POWER7_AVAILABLE) && 0
# if defined(CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY)
// longjmp and clobber warnings. Volatile is required.
@ -140,17 +127,7 @@ bool CPU_ProbePower7()
result = false;
else
{
CRYPTOPP_ALIGN_DATA(16) // Non-const due to XL C/C++
byte b1[19] = {-1, -1, -1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
CRYPTOPP_ALIGN_DATA(16) byte b2[16];
#if defined(CRYPTOPP_XLC_VERSION)
const uint8x16_p8 v1 = vec_xl(0, (const byte*)b1+3);
vec_xst(v1, 0, (byte*)b2);
#elif defined(CRYPTOPP_GCC_VERSION)
const uint8x16_p8 v1 = vec_vsx_ld(0, b1+3);
vec_vsx_st(v1, 0, (byte*)b2);
#endif
result = (0 == std::memcmp(b1+3, b2, 16));
// TODO
}
sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR);
@ -186,17 +163,11 @@ bool CPU_ProbePower8()
result = false;
else
{
CRYPTOPP_ALIGN_DATA(16) // Non-const due to XL C/C++
byte b1[19] = {255, 255, 255, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
CRYPTOPP_ALIGN_DATA(16) byte b2[16];
#if defined(CRYPTOPP_XLC_VERSION)
const uint8x16_p8 v1 = vec_xl(0, reinterpret_cast<byte*>(b1)+3);
vec_xst(v1, 0, reinterpret_cast<byte*>(b2));
#elif defined(CRYPTOPP_GCC_VERSION)
const uint8x16_p8 v1 = vec_vsx_ld(0, b1+3);
vec_vsx_st(v1, 0, b2);
#endif
result = (0 == std::memcmp(b1+3, b2, 16));
byte b1[19] = {255, 255, 255, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, b2[17];
const uint8x16_p8 v1 = (uint8x16_p8)VectorLoad(0, b1+3);
VectorStore(v1, b2+1);
result = (0 == std::memcmp(b1+3, b2+1, 16));
}
sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR);
@ -231,24 +202,16 @@ bool CPU_ProbeAES()
result = false;
else
{
CRYPTOPP_ALIGN_DATA(16) // Non-const due to XL C/C++
byte key[16] = {0xA0, 0xFA, 0xFE, 0x17, 0x88, 0x54, 0x2c, 0xb1, 0x23, 0xa3, 0x39, 0x39, 0x2a, 0x6c, 0x76, 0x05};
CRYPTOPP_ALIGN_DATA(16) // Non-const due to XL C/C++
byte state[16] = {0x19, 0x3d, 0xe3, 0xb3, 0xa0, 0xf4, 0xe2, 0x2b, 0x9a, 0xc6, 0x8d, 0x2a, 0xe9, 0xf8, 0x48, 0x08};
CRYPTOPP_ALIGN_DATA(16) byte r[16] = {255}, z[16] = {};
#if defined(CRYPTOPP_XLC_VERSION)
uint8x16_p8 k = vec_xl(0, reinterpret_cast<byte*>(key));
uint8x16_p8 s = vec_xl(0, reinterpret_cast<byte*>(state));
s = __vncipher(s, k);
s = __vncipherlast(s, k);
vec_xst(s, 0, reinterpret_cast<byte*>(r));
#elif defined(CRYPTOPP_GCC_VERSION)
uint64x2_p8 k = (uint64x2_p8)vec_xl(0, key);
uint64x2_p8 s = (uint64x2_p8)vec_xl(0, state);
s = __builtin_crypto_vncipher(s, k);
s = __builtin_crypto_vncipherlast(s, k);
vec_xst((uint8x16_p8)s, 0, r);
#endif
byte r[16] = {255}, z[16] = {};
uint8x16_p8 k = (uint8x16_p8)VectorLoad(0, key);
uint8x16_p8 s = (uint8x16_p8)VectorLoad(0, state);
s = VectorEncrypt(s, k);
s = VectorEncryptLast(s, k);
VectorStore(s, r);
result = (0 != std::memcmp(r, z, 16));
}
@ -261,7 +224,7 @@ bool CPU_ProbeAES()
#endif // CRYPTOPP_ALTIVEC_AVAILABLE
}
bool CPU_ProbeSHA1()
bool CPU_ProbeSHA256()
{
#if defined(CRYPTOPP_NO_CPU_FEATURE_PROBES)
return false;
@ -296,7 +259,7 @@ bool CPU_ProbeSHA1()
#endif // CRYPTOPP_ALTIVEC_AVAILABLE
}
bool CPU_ProbeSHA2()
bool CPU_ProbeSHA512()
{
#if defined(CRYPTOPP_NO_CPU_FEATURE_PROBES)
return false;

View File

@ -29,6 +29,10 @@
# endif
#endif
#if CRYPTOPP_POWER8_SHA_AVAILABLE
# include "ppc-crypto.h"
#endif
#ifdef CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY
# include <signal.h>
# include <setjmp.h>
@ -960,10 +964,41 @@ void SHA256_HashMultipleBlocks_ARMV8(word32 *state, const word32 *data, size_t l
vst1q_u32(&state[0], STATE0);
vst1q_u32(&state[4], STATE1);
}
#endif
#endif // CRYPTOPP_ARM_SHA_AVAILABLE
///////////////////////////////////////////////////////
// end of Walton/Schneiders/O'Rourke/Hovsmith's code //
///////////////////////////////////////////////////////
NAMESPACE_END
// ***************** Power8 SHA ********************
////////////////////////////////////////////////
// Begin Gustavo Serra Scalet and Walton code //
////////////////////////////////////////////////
#if CRYPTOPP_POWER8_SHA_AVAILABLE
void SHA256_HashMultipleBlocks_POWER8(word32 *state, const word32 *data, size_t length, ByteOrder order)
{
CRYPTOPP_ASSERT(state);
CRYPTOPP_ASSERT(data);
CRYPTOPP_ASSERT(length >= SHA256::BLOCKSIZE);
CRYPTOPP_ASSERT(0);
}
void SHA512_HashMultipleBlocks_POWER8(word64 *state, const word64 *data, size_t length, ByteOrder order)
{
CRYPTOPP_ASSERT(state);
CRYPTOPP_ASSERT(data);
CRYPTOPP_ASSERT(length >= SHA512::BLOCKSIZE);
CRYPTOPP_ASSERT(0);
}
#endif // CRYPTOPP_POWER8_SHA_AVAILABLE
//////////////////////////////////////////////
// End Gustavo Serra Scalet and Walton code //
//////////////////////////////////////////////
NAMESPACE_END

19
sha.cpp
View File

@ -70,6 +70,11 @@ extern void SHA1_HashMultipleBlocks_ARMV8(word32 *state, const word32 *data, siz
extern void SHA256_HashMultipleBlocks_ARMV8(word32 *state, const word32 *data, size_t length, ByteOrder order);
#endif
#if CRYPTOPP_POWER8_SHA_AVAILABLE
extern void SHA256_HashMultipleBlocks_POWER8(word32 *state, const word32 *data, size_t length, ByteOrder order);
extern void SHA512_HashMultipleBlocks_POWER8(word64 *state, const word64 *data, size_t length, ByteOrder order);
#endif
////////////////////////////////
// start of Steve Reid's code //
////////////////////////////////
@ -684,6 +689,13 @@ void SHA256::Transform(word32 *state, const word32 *data)
return;
}
#endif
#if CRYPTOPP_POWER8_SHA_AVAILABLE
if (HasSHA256())
{
SHA256_HashMultipleBlocks_POWER8(state, data, SHA256::BLOCKSIZE, LITTLE_ENDIAN_ORDER);
return;
}
#endif
SHA256_HashBlock_CXX(state, data);
}
@ -715,6 +727,13 @@ size_t SHA256::HashMultipleBlocks(const word32 *input, size_t length)
return length & (SHA256::BLOCKSIZE - 1);
}
#endif
#if CRYPTOPP_POWER8_SHA_AVAILABLE
if (HasSHA256())
{
SHA256_HashMultipleBlocks_POWER8(m_state, input, length, BIG_ENDIAN_ORDER);
return length & (SHA256::BLOCKSIZE - 1);
}
#endif
const bool noReverse = NativeByteOrderIs(this->GetByteOrder());
word32 *dataBuf = this->DataBuf();

View File

@ -379,12 +379,12 @@ bool TestSettings()
bool hasAltivec = HasAltivec();
bool hasPower8 = HasPower8();
bool hasAES = HasAES();
bool hasSHA1 = HasSHA1();
bool hasSHA2 = HasSHA2();
bool hasSHA256 = HasSHA256();
bool hasSHA512 = HasSHA512();
std::cout << "passed: ";
std::cout << "hasAltivec == " << hasAltivec << ", hasPower8 == " << hasPower8;
std::cout << ", hasAES == " << hasAES << ", hasSHA1 == " << hasSHA1 << ", hasSHA2 == " << hasSHA2 << "\n";
std::cout << ", hasAES == " << hasAES << ", hasSHA256 == " << hasSHA256 << ", hasSHA512 == " << hasSHA512 << "\n";
#endif