SecT163Field
using Org.BouncyCastle.Math.Raw;
using Org.BouncyCastle.Runtime.Intrinsics;
using Org.BouncyCastle.Runtime.Intrinsics.X86;
using System;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
namespace Org.BouncyCastle.Math.EC.Custom.Sec
{
internal static class SecT163Field
{
private const ulong M35 = 34359738367;
private const ulong M55 = 36028797018963967;
private static readonly ulong[] ROOT_Z = new ulong[3] {
13176245766935393968,
5270498306774195053,
19634136210
};
public static void Add(ReadOnlySpan<ulong> x, ReadOnlySpan<ulong> y, Span<ulong> z)
{
z[0] = (x[0] ^ y[0]);
z[1] = (x[1] ^ y[1]);
z[2] = (x[2] ^ y[2]);
}
public static void AddBothTo(ReadOnlySpan<ulong> x, ReadOnlySpan<ulong> y, Span<ulong> z)
{
z[0] ^= (x[0] ^ y[0]);
z[1] ^= (x[1] ^ y[1]);
z[2] ^= (x[2] ^ y[2]);
}
public static void AddExt(ReadOnlySpan<ulong> xx, ReadOnlySpan<ulong> yy, Span<ulong> zz)
{
zz[0] = (xx[0] ^ yy[0]);
zz[1] = (xx[1] ^ yy[1]);
zz[2] = (xx[2] ^ yy[2]);
zz[3] = (xx[3] ^ yy[3]);
zz[4] = (xx[4] ^ yy[4]);
zz[5] = (xx[5] ^ yy[5]);
}
public static void AddOne(ReadOnlySpan<ulong> x, Span<ulong> z)
{
z[0] = (x[0] ^ 1);
z[1] = x[1];
z[2] = x[2];
}
public static void AddTo(ReadOnlySpan<ulong> x, Span<ulong> z)
{
z[0] ^= x[0];
z[1] ^= x[1];
z[2] ^= x[2];
}
public static ulong[] FromBigInteger(BigInteger x)
{
return Nat.FromBigInteger64(163, x);
}
public unsafe static void HalfTrace(ReadOnlySpan<ulong> x, Span<ulong> z)
{
Span<ulong> span = new Span<ulong>(stackalloc byte[48], 6);
Nat192.Copy64(x, z);
for (int i = 1; i < 163; i += 2) {
ImplSquare(z, span);
Reduce(span, z);
ImplSquare(z, span);
Reduce(span, z);
AddTo(x, z);
}
}
public unsafe static void Invert(ReadOnlySpan<ulong> x, Span<ulong> z)
{
if (Nat192.IsZero64(x))
throw new InvalidOperationException();
Span<ulong> span = new Span<ulong>(stackalloc byte[24], 3);
Span<ulong> span2 = new Span<ulong>(stackalloc byte[24], 3);
Square(x, span);
SquareN(span, 1, span2);
Multiply(span, span2, span);
SquareN(span2, 1, span2);
Multiply(span, span2, span);
SquareN(span, 3, span2);
Multiply(span, span2, span);
SquareN(span2, 3, span2);
Multiply(span, span2, span);
SquareN(span, 9, span2);
Multiply(span, span2, span);
SquareN(span2, 9, span2);
Multiply(span, span2, span);
SquareN(span, 27, span2);
Multiply(span, span2, span);
SquareN(span2, 27, span2);
Multiply(span, span2, span);
SquareN(span, 81, span2);
Multiply(span, span2, z);
}
public unsafe static void Multiply(ReadOnlySpan<ulong> x, ReadOnlySpan<ulong> y, Span<ulong> z)
{
Span<ulong> span = new Span<ulong>(stackalloc byte[64], 8);
ImplMultiply(x, y, span);
Reduce(span, z);
}
public unsafe static void MultiplyAddToExt(ReadOnlySpan<ulong> x, ReadOnlySpan<ulong> y, Span<ulong> zz)
{
Span<ulong> span = new Span<ulong>(stackalloc byte[64], 8);
ImplMultiply(x, y, span);
AddExt(zz, span, zz);
}
public static void MultiplyExt(ReadOnlySpan<ulong> x, ReadOnlySpan<ulong> y, Span<ulong> zz)
{
ImplMultiply(x, y, zz);
}
public static void Reduce(ReadOnlySpan<ulong> xx, Span<ulong> z)
{
ulong num = xx[0];
ulong num2 = xx[1];
ulong num3 = xx[2];
ulong num4 = xx[3];
ulong num5 = xx[4];
ulong num6 = xx[5];
num3 ^= ((num6 << 29) ^ (num6 << 32) ^ (num6 << 35) ^ (num6 << 36));
num4 ^= ((num6 >> 35) ^ (num6 >> 32) ^ (num6 >> 29) ^ (num6 >> 28));
num2 ^= ((num5 << 29) ^ (num5 << 32) ^ (num5 << 35) ^ (num5 << 36));
num3 ^= ((num5 >> 35) ^ (num5 >> 32) ^ (num5 >> 29) ^ (num5 >> 28));
num ^= ((num4 << 29) ^ (num4 << 32) ^ (num4 << 35) ^ (num4 << 36));
num2 ^= ((num4 >> 35) ^ (num4 >> 32) ^ (num4 >> 29) ^ (num4 >> 28));
ulong num7 = num3 >> 35;
z[0] = (num ^ num7 ^ (num7 << 3) ^ (num7 << 6) ^ (num7 << 7));
z[1] = num2;
z[2] = (num3 & 34359738367);
}
public static void Reduce29(ulong[] z, int zOff)
{
ulong num = z[zOff + 2];
ulong num2 = num >> 35;
z[zOff] ^= (num2 ^ (num2 << 3) ^ (num2 << 6) ^ (num2 << 7));
z[zOff + 2] = (num & 34359738367);
}
public unsafe static void Sqrt(ReadOnlySpan<ulong> x, Span<ulong> z)
{
Span<ulong> span = new Span<ulong>(stackalloc byte[24], 3);
span[0] = Interleave.Unshuffle(x[0], x[1], out ulong even);
span[1] = Interleave.Unshuffle(x[2], out ulong even2);
Multiply(span, ROOT_Z, z);
z[0] ^= even;
z[1] ^= even2;
}
public unsafe static void Square(ReadOnlySpan<ulong> x, Span<ulong> z)
{
Span<ulong> span = new Span<ulong>(stackalloc byte[48], 6);
ImplSquare(x, span);
Reduce(span, z);
}
public unsafe static void SquareAddToExt(ReadOnlySpan<ulong> x, Span<ulong> zz)
{
Span<ulong> span = new Span<ulong>(stackalloc byte[48], 6);
ImplSquare(x, span);
AddExt(zz, span, zz);
}
public static void SquareExt(ReadOnlySpan<ulong> x, Span<ulong> zz)
{
ImplSquare(x, zz);
}
public unsafe static void SquareN(ReadOnlySpan<ulong> x, int n, Span<ulong> z)
{
Span<ulong> span = new Span<ulong>(stackalloc byte[48], 6);
ImplSquare(x, span);
Reduce(span, z);
while (--n > 0) {
ImplSquare(z, span);
Reduce(span, z);
}
}
public static uint Trace(ReadOnlySpan<ulong> x)
{
return (uint)((int)(x[0] ^ (x[2] >> 29)) & 1);
}
private static void ImplCompactExt(Span<ulong> zz)
{
ulong num = zz[0];
ulong num2 = zz[1];
ulong num3 = zz[2];
ulong num4 = zz[3];
ulong num5 = zz[4];
ulong num6 = zz[5];
zz[0] = (num ^ (num2 << 55));
zz[1] = ((num2 >> 9) ^ (num3 << 46));
zz[2] = ((num3 >> 18) ^ (num4 << 37));
zz[3] = ((num4 >> 27) ^ (num5 << 28));
zz[4] = ((num5 >> 36) ^ (num6 << 19));
zz[5] = num6 >> 45;
}
private unsafe static void ImplMultiply(ReadOnlySpan<ulong> x, ReadOnlySpan<ulong> y, Span<ulong> zz)
{
if (Org.BouncyCastle.Runtime.Intrinsics.X86.Pclmulqdq.IsEnabled && Vector.IsPackedLittleEndian) {
Vector128<ulong> left = Vector128.Create(x[0], x[1]);
Vector128<ulong> left2 = Vector128.CreateScalar(x[2]);
Vector128<ulong> right = Vector128.Create(y[0], y[1]);
Vector128<ulong> right2 = Vector128.CreateScalar(y[2]);
Vector128<ulong> value = System.Runtime.Intrinsics.X86.Pclmulqdq.CarrylessMultiply(left, right, 0);
Vector128<ulong> value2 = System.Runtime.Intrinsics.X86.Sse2.Xor(System.Runtime.Intrinsics.X86.Pclmulqdq.CarrylessMultiply(left, right, 1), System.Runtime.Intrinsics.X86.Pclmulqdq.CarrylessMultiply(left, right, 16));
Vector128<ulong> value3 = System.Runtime.Intrinsics.X86.Sse2.Xor(System.Runtime.Intrinsics.X86.Pclmulqdq.CarrylessMultiply(left, right2, 0), System.Runtime.Intrinsics.X86.Sse2.Xor(System.Runtime.Intrinsics.X86.Pclmulqdq.CarrylessMultiply(left, right, 17), System.Runtime.Intrinsics.X86.Pclmulqdq.CarrylessMultiply(left2, right, 0)));
Vector128<ulong> value4 = System.Runtime.Intrinsics.X86.Sse2.Xor(System.Runtime.Intrinsics.X86.Pclmulqdq.CarrylessMultiply(left, right2, 1), System.Runtime.Intrinsics.X86.Pclmulqdq.CarrylessMultiply(left2, right, 16));
Vector128<ulong> value5 = System.Runtime.Intrinsics.X86.Pclmulqdq.CarrylessMultiply(left2, right2, 0);
value = System.Runtime.Intrinsics.X86.Sse2.Xor(value, System.Runtime.Intrinsics.X86.Sse2.ShiftLeftLogical128BitLane(value2, 8));
value3 = System.Runtime.Intrinsics.X86.Sse2.Xor(value3, System.Runtime.Intrinsics.X86.Sse2.ShiftRightLogical128BitLane(value2, 8));
value3 = System.Runtime.Intrinsics.X86.Sse2.Xor(value3, System.Runtime.Intrinsics.X86.Sse2.ShiftLeftLogical128BitLane(value4, 8));
value5 = System.Runtime.Intrinsics.X86.Sse2.Xor(value5, System.Runtime.Intrinsics.X86.Sse2.ShiftRightLogical128BitLane(value4, 8));
Span<byte> span = MemoryMarshal.AsBytes(zz);
MemoryMarshal.Write(span.Slice(0, 16), ref value);
MemoryMarshal.Write(span.Slice(16, 16), ref value3);
MemoryMarshal.Write(span.Slice(32, 16), ref value5);
} else {
ulong num = x[0];
ulong num2 = x[1];
ulong num3 = x[2];
num3 = ((num2 >> 46) ^ (num3 << 18));
num2 = (((num >> 55) ^ (num2 << 9)) & 36028797018963967);
num &= 36028797018963967;
ulong num4 = y[0];
ulong num5 = y[1];
ulong num6 = y[2];
num6 = ((num5 >> 46) ^ (num6 << 18));
num5 = (((num4 >> 55) ^ (num5 << 9)) & 36028797018963967);
num4 &= 36028797018963967;
Span<ulong> u = zz;
Span<ulong> span2 = new Span<ulong>(stackalloc byte[80], 10);
ImplMulw(u, num, num4, span2.Slice(0, span2.Length));
ImplMulw(u, num3, num6, span2.Slice(2, span2.Length - 2));
ulong num7 = num ^ num2 ^ num3;
ulong num8 = num4 ^ num5 ^ num6;
ImplMulw(u, num7, num8, span2.Slice(4, span2.Length - 4));
ulong num9 = (num2 << 1) ^ (num3 << 2);
ulong num10 = (num5 << 1) ^ (num6 << 2);
ImplMulw(u, num ^ num9, num4 ^ num10, span2.Slice(6, span2.Length - 6));
ImplMulw(u, num7 ^ num9, num8 ^ num10, span2.Slice(8, span2.Length - 8));
ulong num11 = span2[6] ^ span2[8];
ulong num12 = span2[7] ^ span2[9];
ulong num13 = (num11 << 1) ^ span2[6];
ulong num14 = num11 ^ (num12 << 1) ^ span2[7];
ulong num15 = num12;
ulong num16 = span2[0];
ulong num17 = span2[1] ^ span2[0] ^ span2[4];
ulong num18 = span2[1] ^ span2[5];
ulong num19 = num16 ^ num13 ^ (span2[2] << 4) ^ (span2[2] << 1);
ulong num20 = num17 ^ num14 ^ (span2[3] << 4) ^ (span2[3] << 1);
ulong num21 = num18 ^ num15;
num20 ^= num19 >> 55;
num19 &= 36028797018963967;
num21 ^= num20 >> 55;
num20 &= 36028797018963967;
num19 = ((num19 >> 1) ^ ((num20 & 1) << 54));
num20 = ((num20 >> 1) ^ ((num21 & 1) << 54));
num21 >>= 1;
num19 ^= num19 << 1;
num19 ^= num19 << 2;
num19 ^= num19 << 4;
num19 ^= num19 << 8;
num19 ^= num19 << 16;
num19 ^= num19 << 32;
num19 &= 36028797018963967;
num20 ^= num19 >> 54;
num20 ^= num20 << 1;
num20 ^= num20 << 2;
num20 ^= num20 << 4;
num20 ^= num20 << 8;
num20 ^= num20 << 16;
num20 ^= num20 << 32;
num20 &= 36028797018963967;
num21 ^= num20 >> 54;
num21 ^= num21 << 1;
num21 ^= num21 << 2;
num21 ^= num21 << 4;
num21 ^= num21 << 8;
num21 ^= num21 << 16;
num21 ^= num21 << 32;
zz[0] = num16;
zz[1] = (num17 ^ num19 ^ span2[2]);
zz[2] = (num18 ^ num20 ^ num19 ^ span2[3]);
zz[3] = (num21 ^ num20);
zz[4] = (num21 ^ span2[2]);
zz[5] = span2[3];
ImplCompactExt(zz);
}
}
private static void ImplMulw(Span<ulong> u, ulong x, ulong y, Span<ulong> z)
{
u[1] = y;
u[2] = u[1] << 1;
u[3] = (u[2] ^ y);
u[4] = u[2] << 1;
u[5] = (u[4] ^ y);
u[6] = u[3] << 1;
u[7] = (u[6] ^ y);
uint num = (uint)x;
ulong num2 = 0;
ulong num3 = u[(int)(num & 3)];
int num4 = 47;
do {
num = (uint)(x >> num4);
ulong num5 = u[(int)(num & 7)] ^ (u[(int)((num >> 3) & 7)] << 3) ^ (u[(int)((num >> 6) & 7)] << 6);
num3 ^= num5 << num4;
num2 ^= num5 >> -num4;
} while ((num4 -= 9) > 0);
z[0] ^= (num3 & 36028797018963967);
z[1] ^= ((num3 >> 55) ^ (num2 << 9));
}
private static void ImplSquare(ReadOnlySpan<ulong> x, Span<ulong> zz)
{
if (Org.BouncyCastle.Runtime.Intrinsics.X86.Bmi2.X64.IsEnabled) {
zz[5] = System.Runtime.Intrinsics.X86.Bmi2.X64.ParallelBitDeposit(x[2] >> 32, 6148914691236517205);
zz[4] = System.Runtime.Intrinsics.X86.Bmi2.X64.ParallelBitDeposit(x[2], 6148914691236517205);
zz[3] = System.Runtime.Intrinsics.X86.Bmi2.X64.ParallelBitDeposit(x[1] >> 32, 6148914691236517205);
zz[2] = System.Runtime.Intrinsics.X86.Bmi2.X64.ParallelBitDeposit(x[1], 6148914691236517205);
zz[1] = System.Runtime.Intrinsics.X86.Bmi2.X64.ParallelBitDeposit(x[0] >> 32, 6148914691236517205);
zz[0] = System.Runtime.Intrinsics.X86.Bmi2.X64.ParallelBitDeposit(x[0], 6148914691236517205);
} else
Interleave.Expand64To128(x.Slice(0, 3), zz.Slice(0, 6));
}
}
}