From 3bd01f73bae3ded9bc5b01681151bcfaf252d7cf Mon Sep 17 00:00:00 2001 From: Jeffrey Walton Date: Fri, 22 Sep 2017 08:58:50 -0400 Subject: [PATCH] Add Power8 SHA256 and SHA512 support (GH #513) --- cpu.cpp | 14 ++++----- cpu.h | 18 +++++------ ppc-simd.cpp | 89 +++++++++++++++------------------------------------- sha-simd.cpp | 39 +++++++++++++++++++++-- sha.cpp | 19 +++++++++++ validat1.cpp | 6 ++-- 6 files changed, 101 insertions(+), 84 deletions(-) diff --git a/cpu.cpp b/cpu.cpp index 4a06385b..827aa8c7 100644 --- a/cpu.cpp +++ b/cpu.cpp @@ -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 diff --git a/cpu.h b/cpu.h index 9e2b7572..35710a93 100644 --- a/cpu.h +++ b/cpu.h @@ -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 -mcpu=power8; while IBM XL C/C++ compilers require //! -qarch=pwr8 -qaltivec. Also see PowerPC's __CRYPTO 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 -mcpu=power8; while IBM XL C/C++ compilers require //! -qarch=pwr8 -qaltivec. Also see PowerPC's __CRYPTO 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 diff --git a/ppc-simd.cpp b/ppc-simd.cpp index 7fc18503..cabe8e7c 100644 --- a/ppc-simd.cpp +++ b/ppc-simd.cpp @@ -23,22 +23,9 @@ # undef CRYPTOPP_POWER8_CRYPTO_AVAILABLE #endif -#if defined(CRYPTOPP_ALTIVEC_AVAILABLE) -# include -# undef vector -# undef pixel -# undef bool -#endif - -#if defined(CRYPTOPP_ALTIVEC_AVAILABLE) -# if defined(CRYPTOPP_XLC_VERSION) - // #include - 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(b1)+3); - vec_xst(v1, 0, reinterpret_cast(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(key)); - uint8x16_p8 s = vec_xl(0, reinterpret_cast(state)); - s = __vncipher(s, k); - s = __vncipherlast(s, k); - vec_xst(s, 0, reinterpret_cast(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; diff --git a/sha-simd.cpp b/sha-simd.cpp index 0dfd733a..9b16fb1c 100644 --- a/sha-simd.cpp +++ b/sha-simd.cpp @@ -29,6 +29,10 @@ # endif #endif +#if CRYPTOPP_POWER8_SHA_AVAILABLE +# include "ppc-crypto.h" +#endif + #ifdef CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY # include # include @@ -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 \ No newline at end of file +// ***************** 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 diff --git a/sha.cpp b/sha.cpp index 713a1914..04dfb4d9 100644 --- a/sha.cpp +++ b/sha.cpp @@ -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(); diff --git a/validat1.cpp b/validat1.cpp index 81fa5582..b5062418 100644 --- a/validat1.cpp +++ b/validat1.cpp @@ -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