summaryrefslogtreecommitdiffstats
path: root/security/nss/lib/freebl/gcm-ppc.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/lib/freebl/gcm-ppc.c')
-rw-r--r--security/nss/lib/freebl/gcm-ppc.c109
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 000000000..9bd4f2956
--- /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) */