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