/* 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) */