#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
#pragma warning disable
#if NETCOREAPP3_0_OR_GREATER
using System;
using System.Buffers.Binary;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;

using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Utilities;

namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Engines
{
    using Aes = System.Runtime.Intrinsics.X86.Aes;
    using Sse2 = System.Runtime.Intrinsics.X86.Sse2;

    public struct AesEngine_X86
        : IBlockCipher
    {
        public static bool IsSupported => Aes.IsSupported;

        private static Vector128<byte>[] CreateRoundKeys(byte[] key, bool forEncryption)
        {
            Vector128<byte>[] K;

            switch (key.Length)
            {
            case 16:
            {
                ReadOnlySpan<byte> rcon = stackalloc byte[]{ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 };

                K = new Vector128<byte>[11];

                var s = Load128(key.AsSpan(0, 16));
                K[0] = s;

                for (int round = 0; round < 10;)
                {
                    var t = Aes.KeygenAssist(s, rcon[round++]);
                    t = Sse2.Shuffle(t.AsInt32(), 0xFF).AsByte();
                    s = Sse2.Xor(s, Sse2.ShiftLeftLogical128BitLane(s, 8));
                    s = Sse2.Xor(s, Sse2.ShiftLeftLogical128BitLane(s, 4));
                    s = Sse2.Xor(s, t);
                    K[round] = s;
                }

                break;
            }
            case 24:
            {
                K = new Vector128<byte>[13];

                var s1 = Load128(key.AsSpan(0, 16));
                var s2 = Load64(key.AsSpan(16, 8)).ToVector128();
                K[0] = s1;

                byte rcon = 0x01;
                for (int round = 0;;)
                {
                    var t1 = Aes.KeygenAssist(s2, rcon);    rcon <<= 1;
                    t1 = Sse2.Shuffle(t1.AsInt32(), 0x55).AsByte();

                    s1 = Sse2.Xor(s1, Sse2.ShiftLeftLogical128BitLane(s1, 8));
                    s1 = Sse2.Xor(s1, Sse2.ShiftLeftLogical128BitLane(s1, 4));
                    s1 = Sse2.Xor(s1, t1);

                    K[++round] = Sse2.Xor(s2, Sse2.ShiftLeftLogical128BitLane(s1, 8));

                    var s3 = Sse2.Xor(s2, Sse2.ShiftRightLogical128BitLane(s1, 12));
                    s3 = Sse2.Xor(s3, Sse2.ShiftLeftLogical128BitLane(s3, 4));

                    K[++round] = Sse2.Xor(
                        Sse2.ShiftRightLogical128BitLane(s1, 8),
                        Sse2.ShiftLeftLogical128BitLane(s3, 8));

                    var t2 = Aes.KeygenAssist(s3, rcon);    rcon <<= 1;
                    t2 = Sse2.Shuffle(t2.AsInt32(), 0x55).AsByte();

                    s1 = Sse2.Xor(s1, Sse2.ShiftLeftLogical128BitLane(s1, 8));
                    s1 = Sse2.Xor(s1, Sse2.ShiftLeftLogical128BitLane(s1, 4));
                    s1 = Sse2.Xor(s1, t2);

                    K[++round] = s1;

                    if (round == 12)
                        break;

                    s2 = Sse2.Xor(s3, Sse2.ShiftRightLogical128BitLane(s1, 12));
                    s2 = Sse2.Xor(s2, Sse2.ShiftLeftLogical128BitLane(s2, 4));
                    s2 = s2.WithUpper(Vector64<byte>.Zero);
                }

                break;
            }
            case 32:
            {
                K = new Vector128<byte>[15];

                var s1 = Load128(key.AsSpan(0, 16));
                var s2 = Load128(key.AsSpan(16, 16));
                K[0] = s1;
                K[1] = s2;

                byte rcon = 0x01;
                for (int round = 1;;)
                {
                    var t1 = Aes.KeygenAssist(s2, rcon);    rcon <<= 1;
                    t1 = Sse2.Shuffle(t1.AsInt32(), 0xFF).AsByte();
                    s1 = Sse2.Xor(s1, Sse2.ShiftLeftLogical128BitLane(s1, 8));
                    s1 = Sse2.Xor(s1, Sse2.ShiftLeftLogical128BitLane(s1, 4));
                    s1 = Sse2.Xor(s1, t1);
                    K[++round] = s1;

                    if (round == 14)
                        break;

                    var t2 = Aes.KeygenAssist(s1, 0x00);
                    t2 = Sse2.Shuffle(t2.AsInt32(), 0xAA).AsByte();
                    s2 = Sse2.Xor(s2, Sse2.ShiftLeftLogical128BitLane(s2, 8));
                    s2 = Sse2.Xor(s2, Sse2.ShiftLeftLogical128BitLane(s2, 4));
                    s2 = Sse2.Xor(s2, t2);
                    K[++round] = s2;
                }

                break;
            }
            default:
                throw new ArgumentException("Key length not 128/192/256 bits.");
            }

            if (!forEncryption)
            {
                for (int i = 1, last = K.Length - 1; i < last; ++i)
                {
                    K[i] = Aes.InverseMixColumns(K[i]);
                }

                Array.Reverse(K);
            }

            return K;
        }

        private enum Mode { DEC_128, DEC_192, DEC_256, ENC_128, ENC_192, ENC_256, UNINITIALIZED };

        private Vector128<byte>[] m_roundKeys = null;
        private Mode m_mode = Mode.UNINITIALIZED;

        public AesEngine_X86()
        {
            if (!IsSupported)
                throw new PlatformNotSupportedException(nameof(AesEngine_X86));
        }

        public string AlgorithmName => "AES";

        public int GetBlockSize() => 16;

        public void Init(bool forEncryption, ICipherParameters parameters)
        {
            if (!(parameters is KeyParameter keyParameter))
            {
                ArgumentNullException.ThrowIfNull(parameters, nameof(parameters));
                throw new ArgumentException("invalid type: " + Org.BouncyCastle.Utilities.Platform.GetTypeName(parameters), nameof(parameters));
            }

            m_roundKeys = CreateRoundKeys(keyParameter.GetKey(), forEncryption);

            if (m_roundKeys.Length == 11)
            {
                m_mode = forEncryption ? Mode.ENC_128 : Mode.DEC_128;
            }
            else if (m_roundKeys.Length == 13)
            {
                m_mode = forEncryption ? Mode.ENC_192 : Mode.DEC_192;
            }
            else
            {
                m_mode = forEncryption ? Mode.ENC_256 : Mode.DEC_256;
            }
        }

        public int ProcessBlock(byte[] inBuf, int inOff, byte[] outBuf, int outOff)
        {
            Check.DataLength(inBuf, inOff, 16, "input buffer too short");
            Check.OutputLength(outBuf, outOff, 16, "output buffer too short");

            var state = Load128(inBuf.AsSpan(inOff, 16));
            ImplRounds(ref state);
            Store128(state, outBuf.AsSpan(outOff, 16));
            return 16;
        }

        public int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
        {
            Check.DataLength(input, 16, "input buffer too short");
            Check.OutputLength(output, 16, "output buffer too short");

            var state = Load128(input[..16]);
            ImplRounds(ref state);
            Store128(state, output[..16]);
            return 16;
        }

        public int ProcessFourBlocks(ReadOnlySpan<byte> input, Span<byte> output)
        {
            Check.DataLength(input, 64, "input buffer too short");
            Check.OutputLength(output, 64, "output buffer too short");

            var s1 = Load128(input[..16]);
            var s2 = Load128(input[16..32]);
            var s3 = Load128(input[32..48]);
            var s4 = Load128(input[48..64]);
            ImplRounds(ref s1, ref s2, ref s3, ref s4);
            Store128(s1, output[..16]);
            Store128(s2, output[16..32]);
            Store128(s3, output[32..48]);
            Store128(s4, output[48..64]);
            return 64;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void ImplRounds(ref Vector128<byte> state)
        {
            switch (m_mode)
            {
            case Mode.DEC_128: Decrypt128(m_roundKeys, ref state); break;
            case Mode.DEC_192: Decrypt192(m_roundKeys, ref state); break;
            case Mode.DEC_256: Decrypt256(m_roundKeys, ref state); break;
            case Mode.ENC_128: Encrypt128(m_roundKeys, ref state); break;
            case Mode.ENC_192: Encrypt192(m_roundKeys, ref state); break;
            case Mode.ENC_256: Encrypt256(m_roundKeys, ref state); break;
            default: throw new InvalidOperationException(nameof(AesEngine_X86) + " not initialised");
            }
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void ImplRounds(
            ref Vector128<byte> s1, ref Vector128<byte> s2, ref Vector128<byte> s3, ref Vector128<byte> s4)
        {
            switch (m_mode)
            {
            case Mode.DEC_128: DecryptFour128(m_roundKeys, ref s1, ref s2, ref s3, ref s4); break;
            case Mode.DEC_192: DecryptFour192(m_roundKeys, ref s1, ref s2, ref s3, ref s4); break;
            case Mode.DEC_256: DecryptFour256(m_roundKeys, ref s1, ref s2, ref s3, ref s4); break;
            case Mode.ENC_128: EncryptFour128(m_roundKeys, ref s1, ref s2, ref s3, ref s4); break;
            case Mode.ENC_192: EncryptFour192(m_roundKeys, ref s1, ref s2, ref s3, ref s4); break;
            case Mode.ENC_256: EncryptFour256(m_roundKeys, ref s1, ref s2, ref s3, ref s4); break;
            default: throw new InvalidOperationException(nameof(AesEngine_X86) + " not initialised");
            }
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static void Decrypt128(Vector128<byte>[] roundKeys, ref Vector128<byte> state)
        {
            state = Sse2.Xor(state, roundKeys[0]);
            state = Aes.Decrypt(state, roundKeys[1]);
            state = Aes.Decrypt(state, roundKeys[2]);
            state = Aes.Decrypt(state, roundKeys[3]);
            state = Aes.Decrypt(state, roundKeys[4]);
            state = Aes.Decrypt(state, roundKeys[5]);
            state = Aes.Decrypt(state, roundKeys[6]);
            state = Aes.Decrypt(state, roundKeys[7]);
            state = Aes.Decrypt(state, roundKeys[8]);
            state = Aes.Decrypt(state, roundKeys[9]);
            state = Aes.DecryptLast(state, roundKeys[10]);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static void Decrypt192(Vector128<byte>[] roundKeys, ref Vector128<byte> state)
        {
            state = Sse2.Xor(state, roundKeys[0]);
            state = Aes.Decrypt(state, roundKeys[1]);
            state = Aes.Decrypt(state, roundKeys[2]);
            state = Aes.Decrypt(state, roundKeys[3]);
            state = Aes.Decrypt(state, roundKeys[4]);
            state = Aes.Decrypt(state, roundKeys[5]);
            state = Aes.Decrypt(state, roundKeys[6]);
            state = Aes.Decrypt(state, roundKeys[7]);
            state = Aes.Decrypt(state, roundKeys[8]);
            state = Aes.Decrypt(state, roundKeys[9]);
            state = Aes.Decrypt(state, roundKeys[10]);
            state = Aes.Decrypt(state, roundKeys[11]);
            state = Aes.DecryptLast(state, roundKeys[12]);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static void Decrypt256(Vector128<byte>[] roundKeys, ref Vector128<byte> state)
        {
            state = Sse2.Xor(state, roundKeys[0]);
            state = Aes.Decrypt(state, roundKeys[1]);
            state = Aes.Decrypt(state, roundKeys[2]);
            state = Aes.Decrypt(state, roundKeys[3]);
            state = Aes.Decrypt(state, roundKeys[4]);
            state = Aes.Decrypt(state, roundKeys[5]);
            state = Aes.Decrypt(state, roundKeys[6]);
            state = Aes.Decrypt(state, roundKeys[7]);
            state = Aes.Decrypt(state, roundKeys[8]);
            state = Aes.Decrypt(state, roundKeys[9]);
            state = Aes.Decrypt(state, roundKeys[10]);
            state = Aes.Decrypt(state, roundKeys[11]);
            state = Aes.Decrypt(state, roundKeys[12]);
            state = Aes.Decrypt(state, roundKeys[13]);
            state = Aes.DecryptLast(state, roundKeys[14]);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static void DecryptFour128(Vector128<byte>[] rk,
            ref Vector128<byte> s1, ref Vector128<byte> s2, ref Vector128<byte> s3, ref Vector128<byte> s4)
        {
            s1 = Sse2.Xor(s1, rk[0]);
            s2 = Sse2.Xor(s2, rk[0]);
            s3 = Sse2.Xor(s3, rk[0]);
            s4 = Sse2.Xor(s4, rk[0]);

            s1 = Aes.Decrypt(s1, rk[1]);
            s2 = Aes.Decrypt(s2, rk[1]);
            s3 = Aes.Decrypt(s3, rk[1]);
            s4 = Aes.Decrypt(s4, rk[1]);

            s1 = Aes.Decrypt(s1, rk[2]);
            s2 = Aes.Decrypt(s2, rk[2]);
            s3 = Aes.Decrypt(s3, rk[2]);
            s4 = Aes.Decrypt(s4, rk[2]);

            s1 = Aes.Decrypt(s1, rk[3]);
            s2 = Aes.Decrypt(s2, rk[3]);
            s3 = Aes.Decrypt(s3, rk[3]);
            s4 = Aes.Decrypt(s4, rk[3]);

            s1 = Aes.Decrypt(s1, rk[4]);
            s2 = Aes.Decrypt(s2, rk[4]);
            s3 = Aes.Decrypt(s3, rk[4]);
            s4 = Aes.Decrypt(s4, rk[4]);

            s1 = Aes.Decrypt(s1, rk[5]);
            s2 = Aes.Decrypt(s2, rk[5]);
            s3 = Aes.Decrypt(s3, rk[5]);
            s4 = Aes.Decrypt(s4, rk[5]);

            s1 = Aes.Decrypt(s1, rk[6]);
            s2 = Aes.Decrypt(s2, rk[6]);
            s3 = Aes.Decrypt(s3, rk[6]);
            s4 = Aes.Decrypt(s4, rk[6]);

            s1 = Aes.Decrypt(s1, rk[7]);
            s2 = Aes.Decrypt(s2, rk[7]);
            s3 = Aes.Decrypt(s3, rk[7]);
            s4 = Aes.Decrypt(s4, rk[7]);

            s1 = Aes.Decrypt(s1, rk[8]);
            s2 = Aes.Decrypt(s2, rk[8]);
            s3 = Aes.Decrypt(s3, rk[8]);
            s4 = Aes.Decrypt(s4, rk[8]);

            s1 = Aes.Decrypt(s1, rk[9]);
            s2 = Aes.Decrypt(s2, rk[9]);
            s3 = Aes.Decrypt(s3, rk[9]);
            s4 = Aes.Decrypt(s4, rk[9]);

            s1 = Aes.DecryptLast(s1, rk[10]);
            s2 = Aes.DecryptLast(s2, rk[10]);
            s3 = Aes.DecryptLast(s3, rk[10]);
            s4 = Aes.DecryptLast(s4, rk[10]);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static void DecryptFour192(Vector128<byte>[] rk,
            ref Vector128<byte> s1, ref Vector128<byte> s2, ref Vector128<byte> s3, ref Vector128<byte> s4)
        {
            s1 = Sse2.Xor(s1, rk[0]);
            s2 = Sse2.Xor(s2, rk[0]);
            s3 = Sse2.Xor(s3, rk[0]);
            s4 = Sse2.Xor(s4, rk[0]);

            s1 = Aes.Decrypt(s1, rk[1]);
            s2 = Aes.Decrypt(s2, rk[1]);
            s3 = Aes.Decrypt(s3, rk[1]);
            s4 = Aes.Decrypt(s4, rk[1]);

            s1 = Aes.Decrypt(s1, rk[2]);
            s2 = Aes.Decrypt(s2, rk[2]);
            s3 = Aes.Decrypt(s3, rk[2]);
            s4 = Aes.Decrypt(s4, rk[2]);

            s1 = Aes.Decrypt(s1, rk[3]);
            s2 = Aes.Decrypt(s2, rk[3]);
            s3 = Aes.Decrypt(s3, rk[3]);
            s4 = Aes.Decrypt(s4, rk[3]);

            s1 = Aes.Decrypt(s1, rk[4]);
            s2 = Aes.Decrypt(s2, rk[4]);
            s3 = Aes.Decrypt(s3, rk[4]);
            s4 = Aes.Decrypt(s4, rk[4]);

            s1 = Aes.Decrypt(s1, rk[5]);
            s2 = Aes.Decrypt(s2, rk[5]);
            s3 = Aes.Decrypt(s3, rk[5]);
            s4 = Aes.Decrypt(s4, rk[5]);

            s1 = Aes.Decrypt(s1, rk[6]);
            s2 = Aes.Decrypt(s2, rk[6]);
            s3 = Aes.Decrypt(s3, rk[6]);
            s4 = Aes.Decrypt(s4, rk[6]);

            s1 = Aes.Decrypt(s1, rk[7]);
            s2 = Aes.Decrypt(s2, rk[7]);
            s3 = Aes.Decrypt(s3, rk[7]);
            s4 = Aes.Decrypt(s4, rk[7]);

            s1 = Aes.Decrypt(s1, rk[8]);
            s2 = Aes.Decrypt(s2, rk[8]);
            s3 = Aes.Decrypt(s3, rk[8]);
            s4 = Aes.Decrypt(s4, rk[8]);

            s1 = Aes.Decrypt(s1, rk[9]);
            s2 = Aes.Decrypt(s2, rk[9]);
            s3 = Aes.Decrypt(s3, rk[9]);
            s4 = Aes.Decrypt(s4, rk[9]);

            s1 = Aes.Decrypt(s1, rk[10]);
            s2 = Aes.Decrypt(s2, rk[10]);
            s3 = Aes.Decrypt(s3, rk[10]);
            s4 = Aes.Decrypt(s4, rk[10]);

            s1 = Aes.Decrypt(s1, rk[11]);
            s2 = Aes.Decrypt(s2, rk[11]);
            s3 = Aes.Decrypt(s3, rk[11]);
            s4 = Aes.Decrypt(s4, rk[11]);

            s1 = Aes.DecryptLast(s1, rk[12]);
            s2 = Aes.DecryptLast(s2, rk[12]);
            s3 = Aes.DecryptLast(s3, rk[12]);
            s4 = Aes.DecryptLast(s4, rk[12]);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static void DecryptFour256(Vector128<byte>[] rk,
            ref Vector128<byte> s1, ref Vector128<byte> s2, ref Vector128<byte> s3, ref Vector128<byte> s4)
        {
            s1 = Sse2.Xor(s1, rk[0]);
            s2 = Sse2.Xor(s2, rk[0]);
            s3 = Sse2.Xor(s3, rk[0]);
            s4 = Sse2.Xor(s4, rk[0]);

            s1 = Aes.Decrypt(s1, rk[1]);
            s2 = Aes.Decrypt(s2, rk[1]);
            s3 = Aes.Decrypt(s3, rk[1]);
            s4 = Aes.Decrypt(s4, rk[1]);

            s1 = Aes.Decrypt(s1, rk[2]);
            s2 = Aes.Decrypt(s2, rk[2]);
            s3 = Aes.Decrypt(s3, rk[2]);
            s4 = Aes.Decrypt(s4, rk[2]);

            s1 = Aes.Decrypt(s1, rk[3]);
            s2 = Aes.Decrypt(s2, rk[3]);
            s3 = Aes.Decrypt(s3, rk[3]);
            s4 = Aes.Decrypt(s4, rk[3]);

            s1 = Aes.Decrypt(s1, rk[4]);
            s2 = Aes.Decrypt(s2, rk[4]);
            s3 = Aes.Decrypt(s3, rk[4]);
            s4 = Aes.Decrypt(s4, rk[4]);

            s1 = Aes.Decrypt(s1, rk[5]);
            s2 = Aes.Decrypt(s2, rk[5]);
            s3 = Aes.Decrypt(s3, rk[5]);
            s4 = Aes.Decrypt(s4, rk[5]);

            s1 = Aes.Decrypt(s1, rk[6]);
            s2 = Aes.Decrypt(s2, rk[6]);
            s3 = Aes.Decrypt(s3, rk[6]);
            s4 = Aes.Decrypt(s4, rk[6]);

            s1 = Aes.Decrypt(s1, rk[7]);
            s2 = Aes.Decrypt(s2, rk[7]);
            s3 = Aes.Decrypt(s3, rk[7]);
            s4 = Aes.Decrypt(s4, rk[7]);

            s1 = Aes.Decrypt(s1, rk[8]);
            s2 = Aes.Decrypt(s2, rk[8]);
            s3 = Aes.Decrypt(s3, rk[8]);
            s4 = Aes.Decrypt(s4, rk[8]);

            s1 = Aes.Decrypt(s1, rk[9]);
            s2 = Aes.Decrypt(s2, rk[9]);
            s3 = Aes.Decrypt(s3, rk[9]);
            s4 = Aes.Decrypt(s4, rk[9]);

            s1 = Aes.Decrypt(s1, rk[10]);
            s2 = Aes.Decrypt(s2, rk[10]);
            s3 = Aes.Decrypt(s3, rk[10]);
            s4 = Aes.Decrypt(s4, rk[10]);

            s1 = Aes.Decrypt(s1, rk[11]);
            s2 = Aes.Decrypt(s2, rk[11]);
            s3 = Aes.Decrypt(s3, rk[11]);
            s4 = Aes.Decrypt(s4, rk[11]);

            s1 = Aes.Decrypt(s1, rk[12]);
            s2 = Aes.Decrypt(s2, rk[12]);
            s3 = Aes.Decrypt(s3, rk[12]);
            s4 = Aes.Decrypt(s4, rk[12]);

            s1 = Aes.Decrypt(s1, rk[13]);
            s2 = Aes.Decrypt(s2, rk[13]);
            s3 = Aes.Decrypt(s3, rk[13]);
            s4 = Aes.Decrypt(s4, rk[13]);

            s1 = Aes.DecryptLast(s1, rk[14]);
            s2 = Aes.DecryptLast(s2, rk[14]);
            s3 = Aes.DecryptLast(s3, rk[14]);
            s4 = Aes.DecryptLast(s4, rk[14]);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static void Encrypt128(Vector128<byte>[] roundKeys, ref Vector128<byte> state)
        {
            state = Sse2.Xor(state, roundKeys[0]);
            state = Aes.Encrypt(state, roundKeys[1]);
            state = Aes.Encrypt(state, roundKeys[2]);
            state = Aes.Encrypt(state, roundKeys[3]);
            state = Aes.Encrypt(state, roundKeys[4]);
            state = Aes.Encrypt(state, roundKeys[5]);
            state = Aes.Encrypt(state, roundKeys[6]);
            state = Aes.Encrypt(state, roundKeys[7]);
            state = Aes.Encrypt(state, roundKeys[8]);
            state = Aes.Encrypt(state, roundKeys[9]);
            state = Aes.EncryptLast(state, roundKeys[10]);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static void Encrypt192(Vector128<byte>[] roundKeys, ref Vector128<byte> state)
        {
            state = Sse2.Xor(state, roundKeys[0]);
            state = Aes.Encrypt(state, roundKeys[1]);
            state = Aes.Encrypt(state, roundKeys[2]);
            state = Aes.Encrypt(state, roundKeys[3]);
            state = Aes.Encrypt(state, roundKeys[4]);
            state = Aes.Encrypt(state, roundKeys[5]);
            state = Aes.Encrypt(state, roundKeys[6]);
            state = Aes.Encrypt(state, roundKeys[7]);
            state = Aes.Encrypt(state, roundKeys[8]);
            state = Aes.Encrypt(state, roundKeys[9]);
            state = Aes.Encrypt(state, roundKeys[10]);
            state = Aes.Encrypt(state, roundKeys[11]);
            state = Aes.EncryptLast(state, roundKeys[12]);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static void Encrypt256(Vector128<byte>[] roundKeys, ref Vector128<byte> state)
        {
            state = Sse2.Xor(state, roundKeys[0]);
            state = Aes.Encrypt(state, roundKeys[1]);
            state = Aes.Encrypt(state, roundKeys[2]);
            state = Aes.Encrypt(state, roundKeys[3]);
            state = Aes.Encrypt(state, roundKeys[4]);
            state = Aes.Encrypt(state, roundKeys[5]);
            state = Aes.Encrypt(state, roundKeys[6]);
            state = Aes.Encrypt(state, roundKeys[7]);
            state = Aes.Encrypt(state, roundKeys[8]);
            state = Aes.Encrypt(state, roundKeys[9]);
            state = Aes.Encrypt(state, roundKeys[10]);
            state = Aes.Encrypt(state, roundKeys[11]);
            state = Aes.Encrypt(state, roundKeys[12]);
            state = Aes.Encrypt(state, roundKeys[13]);
            state = Aes.EncryptLast(state, roundKeys[14]);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static void EncryptFour128(Vector128<byte>[] rk,
            ref Vector128<byte> s1, ref Vector128<byte> s2, ref Vector128<byte> s3, ref Vector128<byte> s4)
        {
            s1 = Sse2.Xor(s1, rk[0]);
            s2 = Sse2.Xor(s2, rk[0]);
            s3 = Sse2.Xor(s3, rk[0]);
            s4 = Sse2.Xor(s4, rk[0]);

            s1 = Aes.Encrypt(s1, rk[1]);
            s2 = Aes.Encrypt(s2, rk[1]);
            s3 = Aes.Encrypt(s3, rk[1]);
            s4 = Aes.Encrypt(s4, rk[1]);

            s1 = Aes.Encrypt(s1, rk[2]);
            s2 = Aes.Encrypt(s2, rk[2]);
            s3 = Aes.Encrypt(s3, rk[2]);
            s4 = Aes.Encrypt(s4, rk[2]);

            s1 = Aes.Encrypt(s1, rk[3]);
            s2 = Aes.Encrypt(s2, rk[3]);
            s3 = Aes.Encrypt(s3, rk[3]);
            s4 = Aes.Encrypt(s4, rk[3]);

            s1 = Aes.Encrypt(s1, rk[4]);
            s2 = Aes.Encrypt(s2, rk[4]);
            s3 = Aes.Encrypt(s3, rk[4]);
            s4 = Aes.Encrypt(s4, rk[4]);

            s1 = Aes.Encrypt(s1, rk[5]);
            s2 = Aes.Encrypt(s2, rk[5]);
            s3 = Aes.Encrypt(s3, rk[5]);
            s4 = Aes.Encrypt(s4, rk[5]);

            s1 = Aes.Encrypt(s1, rk[6]);
            s2 = Aes.Encrypt(s2, rk[6]);
            s3 = Aes.Encrypt(s3, rk[6]);
            s4 = Aes.Encrypt(s4, rk[6]);

            s1 = Aes.Encrypt(s1, rk[7]);
            s2 = Aes.Encrypt(s2, rk[7]);
            s3 = Aes.Encrypt(s3, rk[7]);
            s4 = Aes.Encrypt(s4, rk[7]);

            s1 = Aes.Encrypt(s1, rk[8]);
            s2 = Aes.Encrypt(s2, rk[8]);
            s3 = Aes.Encrypt(s3, rk[8]);
            s4 = Aes.Encrypt(s4, rk[8]);

            s1 = Aes.Encrypt(s1, rk[9]);
            s2 = Aes.Encrypt(s2, rk[9]);
            s3 = Aes.Encrypt(s3, rk[9]);
            s4 = Aes.Encrypt(s4, rk[9]);

            s1 = Aes.EncryptLast(s1, rk[10]);
            s2 = Aes.EncryptLast(s2, rk[10]);
            s3 = Aes.EncryptLast(s3, rk[10]);
            s4 = Aes.EncryptLast(s4, rk[10]);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static void EncryptFour192(Vector128<byte>[] rk,
            ref Vector128<byte> s1, ref Vector128<byte> s2, ref Vector128<byte> s3, ref Vector128<byte> s4)
        {
            s1 = Sse2.Xor(s1, rk[0]);
            s2 = Sse2.Xor(s2, rk[0]);
            s3 = Sse2.Xor(s3, rk[0]);
            s4 = Sse2.Xor(s4, rk[0]);

            s1 = Aes.Encrypt(s1, rk[1]);
            s2 = Aes.Encrypt(s2, rk[1]);
            s3 = Aes.Encrypt(s3, rk[1]);
            s4 = Aes.Encrypt(s4, rk[1]);

            s1 = Aes.Encrypt(s1, rk[2]);
            s2 = Aes.Encrypt(s2, rk[2]);
            s3 = Aes.Encrypt(s3, rk[2]);
            s4 = Aes.Encrypt(s4, rk[2]);

            s1 = Aes.Encrypt(s1, rk[3]);
            s2 = Aes.Encrypt(s2, rk[3]);
            s3 = Aes.Encrypt(s3, rk[3]);
            s4 = Aes.Encrypt(s4, rk[3]);

            s1 = Aes.Encrypt(s1, rk[4]);
            s2 = Aes.Encrypt(s2, rk[4]);
            s3 = Aes.Encrypt(s3, rk[4]);
            s4 = Aes.Encrypt(s4, rk[4]);

            s1 = Aes.Encrypt(s1, rk[5]);
            s2 = Aes.Encrypt(s2, rk[5]);
            s3 = Aes.Encrypt(s3, rk[5]);
            s4 = Aes.Encrypt(s4, rk[5]);

            s1 = Aes.Encrypt(s1, rk[6]);
            s2 = Aes.Encrypt(s2, rk[6]);
            s3 = Aes.Encrypt(s3, rk[6]);
            s4 = Aes.Encrypt(s4, rk[6]);

            s1 = Aes.Encrypt(s1, rk[7]);
            s2 = Aes.Encrypt(s2, rk[7]);
            s3 = Aes.Encrypt(s3, rk[7]);
            s4 = Aes.Encrypt(s4, rk[7]);

            s1 = Aes.Encrypt(s1, rk[8]);
            s2 = Aes.Encrypt(s2, rk[8]);
            s3 = Aes.Encrypt(s3, rk[8]);
            s4 = Aes.Encrypt(s4, rk[8]);

            s1 = Aes.Encrypt(s1, rk[9]);
            s2 = Aes.Encrypt(s2, rk[9]);
            s3 = Aes.Encrypt(s3, rk[9]);
            s4 = Aes.Encrypt(s4, rk[9]);

            s1 = Aes.Encrypt(s1, rk[10]);
            s2 = Aes.Encrypt(s2, rk[10]);
            s3 = Aes.Encrypt(s3, rk[10]);
            s4 = Aes.Encrypt(s4, rk[10]);

            s1 = Aes.Encrypt(s1, rk[11]);
            s2 = Aes.Encrypt(s2, rk[11]);
            s3 = Aes.Encrypt(s3, rk[11]);
            s4 = Aes.Encrypt(s4, rk[11]);

            s1 = Aes.EncryptLast(s1, rk[12]);
            s2 = Aes.EncryptLast(s2, rk[12]);
            s3 = Aes.EncryptLast(s3, rk[12]);
            s4 = Aes.EncryptLast(s4, rk[12]);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static void EncryptFour256(Vector128<byte>[] rk,
            ref Vector128<byte> s1, ref Vector128<byte> s2, ref Vector128<byte> s3, ref Vector128<byte> s4)
        {
            s1 = Sse2.Xor(s1, rk[0]);
            s2 = Sse2.Xor(s2, rk[0]);
            s3 = Sse2.Xor(s3, rk[0]);
            s4 = Sse2.Xor(s4, rk[0]);

            s1 = Aes.Encrypt(s1, rk[1]);
            s2 = Aes.Encrypt(s2, rk[1]);
            s3 = Aes.Encrypt(s3, rk[1]);
            s4 = Aes.Encrypt(s4, rk[1]);

            s1 = Aes.Encrypt(s1, rk[2]);
            s2 = Aes.Encrypt(s2, rk[2]);
            s3 = Aes.Encrypt(s3, rk[2]);
            s4 = Aes.Encrypt(s4, rk[2]);

            s1 = Aes.Encrypt(s1, rk[3]);
            s2 = Aes.Encrypt(s2, rk[3]);
            s3 = Aes.Encrypt(s3, rk[3]);
            s4 = Aes.Encrypt(s4, rk[3]);

            s1 = Aes.Encrypt(s1, rk[4]);
            s2 = Aes.Encrypt(s2, rk[4]);
            s3 = Aes.Encrypt(s3, rk[4]);
            s4 = Aes.Encrypt(s4, rk[4]);

            s1 = Aes.Encrypt(s1, rk[5]);
            s2 = Aes.Encrypt(s2, rk[5]);
            s3 = Aes.Encrypt(s3, rk[5]);
            s4 = Aes.Encrypt(s4, rk[5]);

            s1 = Aes.Encrypt(s1, rk[6]);
            s2 = Aes.Encrypt(s2, rk[6]);
            s3 = Aes.Encrypt(s3, rk[6]);
            s4 = Aes.Encrypt(s4, rk[6]);

            s1 = Aes.Encrypt(s1, rk[7]);
            s2 = Aes.Encrypt(s2, rk[7]);
            s3 = Aes.Encrypt(s3, rk[7]);
            s4 = Aes.Encrypt(s4, rk[7]);

            s1 = Aes.Encrypt(s1, rk[8]);
            s2 = Aes.Encrypt(s2, rk[8]);
            s3 = Aes.Encrypt(s3, rk[8]);
            s4 = Aes.Encrypt(s4, rk[8]);

            s1 = Aes.Encrypt(s1, rk[9]);
            s2 = Aes.Encrypt(s2, rk[9]);
            s3 = Aes.Encrypt(s3, rk[9]);
            s4 = Aes.Encrypt(s4, rk[9]);

            s1 = Aes.Encrypt(s1, rk[10]);
            s2 = Aes.Encrypt(s2, rk[10]);
            s3 = Aes.Encrypt(s3, rk[10]);
            s4 = Aes.Encrypt(s4, rk[10]);

            s1 = Aes.Encrypt(s1, rk[11]);
            s2 = Aes.Encrypt(s2, rk[11]);
            s3 = Aes.Encrypt(s3, rk[11]);
            s4 = Aes.Encrypt(s4, rk[11]);

            s1 = Aes.Encrypt(s1, rk[12]);
            s2 = Aes.Encrypt(s2, rk[12]);
            s3 = Aes.Encrypt(s3, rk[12]);
            s4 = Aes.Encrypt(s4, rk[12]);

            s1 = Aes.Encrypt(s1, rk[13]);
            s2 = Aes.Encrypt(s2, rk[13]);
            s3 = Aes.Encrypt(s3, rk[13]);
            s4 = Aes.Encrypt(s4, rk[13]);

            s1 = Aes.EncryptLast(s1, rk[14]);
            s2 = Aes.EncryptLast(s2, rk[14]);
            s3 = Aes.EncryptLast(s3, rk[14]);
            s4 = Aes.EncryptLast(s4, rk[14]);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static Vector128<byte> Load128(ReadOnlySpan<byte> t)
        {
#if NET7_0_OR_GREATER
            return Vector128.Create<byte>(t);
#else
            if (BitConverter.IsLittleEndian && Unsafe.SizeOf<Vector128<byte>>() == 16)
                return MemoryMarshal.Read<Vector128<byte>>(t);

            return Vector128.Create(
                BinaryPrimitives.ReadUInt64LittleEndian(t[..8]),
                BinaryPrimitives.ReadUInt64LittleEndian(t[8..])
            ).AsByte();
#endif
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static Vector64<byte> Load64(ReadOnlySpan<byte> t)
        {
#if NET7_0_OR_GREATER
            return Vector64.Create<byte>(t);
#else
            if (BitConverter.IsLittleEndian && Unsafe.SizeOf<Vector64<byte>>() == 8)
                return MemoryMarshal.Read<Vector64<byte>>(t);

            return Vector64.Create(
                BinaryPrimitives.ReadUInt64LittleEndian(t[..8])
            ).AsByte();
#endif
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static void Store128(Vector128<byte> s, Span<byte> t)
        {
#if NET7_0_OR_GREATER
            Vector128.CopyTo(s, t);
#else
            if (BitConverter.IsLittleEndian && Unsafe.SizeOf<Vector128<byte>>() == 16)
            {
                MemoryMarshal.Write(t, ref s);
                return;
            }

            var u = s.AsUInt64();
            BinaryPrimitives.WriteUInt64LittleEndian(t[..8], u.GetElement(0));
            BinaryPrimitives.WriteUInt64LittleEndian(t[8..], u.GetElement(1));
#endif
        }
    }
}
#endif
#pragma warning restore
#endif
