summary refs log tree commit diff
path: root/crypto/src/crypto/modes/gcm/GcmUtilities.cs
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/src/crypto/modes/gcm/GcmUtilities.cs')
-rw-r--r--crypto/src/crypto/modes/gcm/GcmUtilities.cs102
1 files changed, 102 insertions, 0 deletions
diff --git a/crypto/src/crypto/modes/gcm/GcmUtilities.cs b/crypto/src/crypto/modes/gcm/GcmUtilities.cs
index a239e9ec0..b2c74d7d0 100644
--- a/crypto/src/crypto/modes/gcm/GcmUtilities.cs
+++ b/crypto/src/crypto/modes/gcm/GcmUtilities.cs
@@ -140,6 +140,108 @@ namespace Org.BouncyCastle.Crypto.Modes.Gcm
             x.n1 = z1;
         }
 
+#if NETCOREAPP3_0_OR_GREATER
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        internal static Vector128<ulong> Load(byte[] x)
+        {
+            AsFieldElement(x, out FieldElement X);
+            return Vector128.Create(X.n1, X.n0);
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        internal static Vector128<ulong> Multiply(Vector128<ulong> X, Vector128<ulong> Y)
+        {
+            MultiplyExt(X, Y, out var Z0, out var Z1, out var Z2);
+            return Reduce3(Z0, Z1, Z2);
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        internal static void MultiplyExt(Vector128<ulong> X, Vector128<ulong> Y, out Vector128<ulong> Z0,
+            out Vector128<ulong> Z1, out Vector128<ulong> Z2)
+        {
+            if (!Pclmulqdq.IsSupported)
+                throw new PlatformNotSupportedException(nameof(GcmUtilities.MultiplyExt));
+
+            Z0 =          Pclmulqdq.CarrylessMultiply(X, Y, 0x00);
+            Z1 = Sse2.Xor(Pclmulqdq.CarrylessMultiply(X, Y, 0x01),
+                          Pclmulqdq.CarrylessMultiply(X, Y, 0x10));
+            Z2 =          Pclmulqdq.CarrylessMultiply(X, Y, 0x11);
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        internal static Vector128<ulong> Reduce2(Vector128<ulong> Z0, Vector128<ulong> Z2)
+        {
+            ulong t3 = Z0.GetElement(0);
+            ulong t2 = Z0.GetElement(1);
+            ulong t1 = Z2.GetElement(0);
+            ulong t0 = Z2.GetElement(1);
+
+            ulong z0 = (t0 << 1) | (t1 >> 63);
+            ulong z1 = (t1 << 1) | (t2 >> 63);
+            ulong z2 = (t2 << 1) | (t3 >> 63);
+            ulong z3 = (t3 << 1);
+
+            Debug.Assert(z3 << 63 == 0);
+
+            z1 ^= z3 ^ (z3 >>  1) ^ (z3 >>  2) ^ (z3 >>  7);
+//          z2 ^=      (z3 << 63) ^ (z3 << 62) ^ (z3 << 57);
+            z2 ^=                   (z3 << 62) ^ (z3 << 57);
+
+            z0 ^= z2 ^ (z2 >>  1) ^ (z2 >>  2) ^ (z2 >>  7);
+            z1 ^=      (z2 << 63) ^ (z2 << 62) ^ (z2 << 57);
+
+            return Vector128.Create(z1, z0);
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        internal static Vector128<ulong> Reduce3(Vector128<ulong> Z0, Vector128<ulong> Z1, Vector128<ulong> Z2)
+        {
+            ulong t3 = Z0.GetElement(0);
+            ulong t2 = Z0.GetElement(1) ^ Z1.GetElement(0);
+            ulong t1 = Z2.GetElement(0) ^ Z1.GetElement(1);
+            ulong t0 = Z2.GetElement(1);
+
+            ulong z0 = (t0 << 1) | (t1 >> 63);
+            ulong z1 = (t1 << 1) | (t2 >> 63);
+            ulong z2 = (t2 << 1) | (t3 >> 63);
+            ulong z3 = (t3 << 1);
+
+            Debug.Assert(z3 << 63 == 0);
+
+            z1 ^= z3 ^ (z3 >>  1) ^ (z3 >>  2) ^ (z3 >>  7);
+//          z2 ^=      (z3 << 63) ^ (z3 << 62) ^ (z3 << 57);
+            z2 ^=                   (z3 << 62) ^ (z3 << 57);
+
+            z0 ^= z2 ^ (z2 >>  1) ^ (z2 >>  2) ^ (z2 >>  7);
+            z1 ^=      (z2 << 63) ^ (z2 << 62) ^ (z2 << 57);
+
+            return Vector128.Create(z1, z0);
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        internal static void Store(Vector128<ulong> X, byte[] z)
+        {
+            AsBytes(X.GetElement(1), X.GetElement(0), z);
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        internal static Vector128<ulong> Square(Vector128<ulong> X)
+        {
+            SquareExt(X, out var Z0, out var Z2);
+            return Reduce2(Z0, Z2);
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        internal static void SquareExt(Vector128<ulong> X, out Vector128<ulong> Z0, out Vector128<ulong> Z2)
+        {
+            if (!Pclmulqdq.IsSupported)
+                throw new PlatformNotSupportedException(nameof(GcmUtilities.SquareExt));
+
+            Z0 = Pclmulqdq.CarrylessMultiply(X, X, 0x00);
+            Z2 = Pclmulqdq.CarrylessMultiply(X, X, 0x11);
+        }
+#endif
+
         internal static void MultiplyP7(ref FieldElement x)
         {
             ulong x0 = x.n0, x1 = x.n1;