diff options
Diffstat (limited to 'security/nss/lib/freebl/gcm-ppc.c')
-rw-r--r-- | security/nss/lib/freebl/gcm-ppc.c | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/security/nss/lib/freebl/gcm-ppc.c b/security/nss/lib/freebl/gcm-ppc.c new file mode 100644 index 0000000000..9bd4f29569 --- /dev/null +++ b/security/nss/lib/freebl/gcm-ppc.c @@ -0,0 +1,109 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifdef FREEBL_NO_DEPEND +#include "stubs.h" +#endif +#include "gcm.h" +#include "secerr.h" + +#if defined(USE_PPC_CRYPTO) + +SECStatus +gcm_HashWrite_hw(gcmHashContext *ghash, unsigned char *outbuf) +{ + vec_xst_be((vec_u8)ghash->x, 0, outbuf); + return SECSuccess; +} + +static vec_u64 +vpmsumd(const vec_u64 a, const vec_u64 b) +{ +#if defined(__clang__) + /* Clang uses a different name */ + return __builtin_altivec_crypto_vpmsumd(a, b); +#elif (__GNUC__ >= 10) || (__GNUC__ == 9 && __GNUC_MINOR__ >= 3) || \ + (__GNUC__ == 8 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ == 7 && __GNUC_MINOR__ >= 5) + /* GCC versions not affected by https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91275 */ + return __builtin_crypto_vpmsumd(a, b); +#else + /* GCC versions where this builtin is buggy */ + vec_u64 vr; + __asm("vpmsumd %0, %1, %2" + : "=v"(vr) + : "v"(a), "v"(b)); + return vr; +#endif +} + +SECStatus +gcm_HashMult_hw(gcmHashContext *ghash, const unsigned char *buf, + unsigned int count) +{ + const vec_u8 leftshift = vec_splat_u8(1); + const vec_u64 onebit = (vec_u64){ 1, 0 }; + const unsigned long long pd = 0xc2LLU << 56; + + vec_u64 ci, v, r0, r1; + vec_u64 hibit; + unsigned i; + + ci = ghash->x; + + for (i = 0; i < count; i++, buf += 16) { + /* clang needs the following cast away from const; maybe a bug in 7.0.0 */ + v = (vec_u64)vec_xl_be(0, (unsigned char *)buf); + ci ^= v; + + /* Do binary mult ghash->X = C * ghash->H (Karatsuba). */ + r0 = vpmsumd((vec_u64){ ci[0], 0 }, (vec_u64){ ghash->h[0], 0 }); + r1 = vpmsumd((vec_u64){ ci[1], 0 }, (vec_u64){ ghash->h[1], 0 }); + v = (vec_u64){ ci[0] ^ ci[1], ghash->h[0] ^ ghash->h[1] }; + v = vpmsumd((vec_u64){ v[0], 0 }, (vec_u64){ v[1], 0 }); + v ^= r0; + v ^= r1; + r0 ^= (vec_u64){ 0, v[0] }; + r1 ^= (vec_u64){ v[1], 0 }; + + /* Shift one (multiply by x) as gcm spec is stupid. */ + hibit = (vec_u64)vec_splat((vec_u8)r0, 15); + hibit = (vec_u64)vec_rl((vec_u8)hibit, leftshift); + hibit &= onebit; + r0 = vec_sll(r0, leftshift); + r1 = vec_sll(r1, leftshift); + r1 |= hibit; + + /* Reduce */ + v = vpmsumd((vec_u64){ r0[0], 0 }, (vec_u64){ pd, 0 }); + r0 ^= (vec_u64){ 0, v[0] }; + r1 ^= (vec_u64){ v[1], 0 }; + v = vpmsumd((vec_u64){ r0[1], 0 }, (vec_u64){ pd, 0 }); + r1 ^= v; + ci = r0 ^ r1; + } + + ghash->x = ci; + + return SECSuccess; +} + +SECStatus +gcm_HashInit_hw(gcmHashContext *ghash) +{ + ghash->x = (vec_u64)vec_splat_u32(0); + ghash->h = (vec_u64){ ghash->h_low, ghash->h_high }; + ghash->ghash_mul = gcm_HashMult_hw; + ghash->hw = PR_TRUE; + return SECSuccess; +} + +SECStatus +gcm_HashZeroX_hw(gcmHashContext *ghash) +{ + ghash->x = (vec_u64)vec_splat_u32(0); + return SECSuccess; +} + +#endif /* defined(USE_PPC_CRYPTO) */ |