diff --git a/AOpCodeTable.cs b/AOpCodeTable.cs index 97404bb..dc8cfc0 100644 --- a/AOpCodeTable.cs +++ b/AOpCodeTable.cs @@ -180,6 +180,10 @@ namespace ChocolArm64 SetA64("0>001110<<1xxxxx101111xxxxxxxxxx", AInstEmit.Addp_V, typeof(AOpCodeSimdReg)); SetA64("000011100x110001101110xxxxxxxxxx", AInstEmit.Addv_V, typeof(AOpCodeSimd)); SetA64("01001110<<110001101110xxxxxxxxxx", AInstEmit.Addv_V, typeof(AOpCodeSimd)); + SetA64("0100111000101000010110xxxxxxxxxx", AInstEmit.Aesd_V, typeof(AOpCodeSimd)); + SetA64("0100111000101000010010xxxxxxxxxx", AInstEmit.Aese_V, typeof(AOpCodeSimd)); + SetA64("0100111000101000011110xxxxxxxxxx", AInstEmit.Aesimc_V, typeof(AOpCodeSimd)); + SetA64("0100111000101000011010xxxxxxxxxx", AInstEmit.Aesmc_V, typeof(AOpCodeSimd)); SetA64("0x001110001xxxxx000111xxxxxxxxxx", AInstEmit.And_V, typeof(AOpCodeSimdReg)); SetA64("0x001110011xxxxx000111xxxxxxxxxx", AInstEmit.Bic_V, typeof(AOpCodeSimdReg)); SetA64("0x10111100000xxx< AESInvMixColumns(Vector128 op) + { + byte[] InState = new byte[16]; + byte[] OutState = new byte[16]; + + FromVectorToByteArray(InState, ref op); + + for (int Columns = 0; Columns <= 3; Columns++) + { + int Idx = Columns << 2; + + byte Row0 = InState[Idx + 0]; // A, E, I, M: [Row0, Col0-Col3] + byte Row1 = InState[Idx + 1]; // B, F, J, N: [Row1, Col0-Col3] + byte Row2 = InState[Idx + 2]; // C, G, K, O: [Row2, Col0-Col3] + byte Row3 = InState[Idx + 3]; // D, H, L, P: [Row3, Col0-Col3] + + OutState[Idx + 0] = (byte)((uint)GFMul_0E[Row0] ^ GFMul_0B[Row1] ^ GFMul_0D[Row2] ^ GFMul_09[Row3]); + OutState[Idx + 1] = (byte)((uint)GFMul_09[Row0] ^ GFMul_0E[Row1] ^ GFMul_0B[Row2] ^ GFMul_0D[Row3]); + OutState[Idx + 2] = (byte)((uint)GFMul_0D[Row0] ^ GFMul_09[Row1] ^ GFMul_0E[Row2] ^ GFMul_0B[Row3]); + OutState[Idx + 3] = (byte)((uint)GFMul_0B[Row0] ^ GFMul_0D[Row1] ^ GFMul_09[Row2] ^ GFMul_0E[Row3]); + } + + FromByteArrayToVector(OutState, ref op); + + return op; + } + + public static Vector128 AESInvShiftRows(Vector128 op) + { + byte[] InState = new byte[16]; + byte[] OutState = new byte[16]; + + FromVectorToByteArray(InState, ref op); + + for (int Idx = 0; Idx <= 15; Idx++) + { + OutState[ISRPerm[Idx]] = InState[Idx]; + } + + FromByteArrayToVector(OutState, ref op); + + return op; + } + + public static Vector128 AESInvSubBytes(Vector128 op) + { + byte[] InState = new byte[16]; + byte[] OutState = new byte[16]; + + FromVectorToByteArray(InState, ref op); + + for (int Idx = 0; Idx <= 15; Idx++) + { + OutState[Idx] = InvSBox[InState[Idx]]; + } + + FromByteArrayToVector(OutState, ref op); + + return op; + } + + public static Vector128 AESMixColumns(Vector128 op) + { + byte[] InState = new byte[16]; + byte[] OutState = new byte[16]; + + FromVectorToByteArray(InState, ref op); + + for (int Columns = 0; Columns <= 3; Columns++) + { + int Idx = Columns << 2; + + byte Row0 = InState[Idx + 0]; // A, E, I, M: [Row0, Col0-Col3] + byte Row1 = InState[Idx + 1]; // B, F, J, N: [Row1, Col0-Col3] + byte Row2 = InState[Idx + 2]; // C, G, K, O: [Row2, Col0-Col3] + byte Row3 = InState[Idx + 3]; // D, H, L, P: [Row3, Col0-Col3] + + OutState[Idx + 0] = (byte)((uint)GFMul_02[Row0] ^ GFMul_03[Row1] ^ Row2 ^ Row3); + OutState[Idx + 1] = (byte)((uint)Row0 ^ GFMul_02[Row1] ^ GFMul_03[Row2] ^ Row3); + OutState[Idx + 2] = (byte)((uint)Row0 ^ Row1 ^ GFMul_02[Row2] ^ GFMul_03[Row3]); + OutState[Idx + 3] = (byte)((uint)GFMul_03[Row0] ^ Row1 ^ Row2 ^ GFMul_02[Row3]); + } + + FromByteArrayToVector(OutState, ref op); + + return op; + } + + public static Vector128 AESShiftRows(Vector128 op) + { + byte[] InState = new byte[16]; + byte[] OutState = new byte[16]; + + FromVectorToByteArray(InState, ref op); + + for (int Idx = 0; Idx <= 15; Idx++) + { + OutState[SRPerm[Idx]] = InState[Idx]; + } + + FromByteArrayToVector(OutState, ref op); + + return op; + } + + public static Vector128 AESSubBytes(Vector128 op) + { + byte[] InState = new byte[16]; + byte[] OutState = new byte[16]; + + FromVectorToByteArray(InState, ref op); + + for (int Idx = 0; Idx <= 15; Idx++) + { + OutState[Idx] = SBox[InState[Idx]]; + } + + FromByteArrayToVector(OutState, ref op); + + return op; + } + + private static void FromVectorToByteArray(byte[] State, ref Vector128 op) + { + ulong ULongLow = AVectorHelper.VectorExtractIntZx((op), (byte)0, 3); + ulong ULongHigh = AVectorHelper.VectorExtractIntZx((op), (byte)1, 3); + + for (int Idx = 0; Idx <= 7; Idx++) + { + State[Idx + 0] = (byte)(ULongLow & 0xFFUL); + State[Idx + 8] = (byte)(ULongHigh & 0xFFUL); + + ULongLow >>= 8; + ULongHigh >>= 8; + } + } + + private static void FromByteArrayToVector(byte[] State, ref Vector128 op) + { + if (!Sse2.IsSupported) + { + throw new PlatformNotSupportedException(); + } + + op = Sse.StaticCast(Sse2.SetVector128( + State[15], State[14], State[13], State[12], + State[11], State[10], State[9], State[8], + State[7], State[6], State[5], State[4], + State[3], State[2], State[1], State[0])); + } + } +} diff --git a/Instruction/AInstEmitSimdCrypto.cs b/Instruction/AInstEmitSimdCrypto.cs new file mode 100644 index 0000000..b2680a5 --- /dev/null +++ b/Instruction/AInstEmitSimdCrypto.cs @@ -0,0 +1,54 @@ +using ChocolArm64.Decoder; +using ChocolArm64.Translation; + +namespace ChocolArm64.Instruction +{ + static partial class AInstEmit + { + public static void Aesd_V(AILEmitterCtx Context) + { + AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; + + Context.EmitLdvec(Op.Rd); + Context.EmitLdvec(Op.Rn); + + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.Decrypt)); + + Context.EmitStvec(Op.Rd); + } + + public static void Aese_V(AILEmitterCtx Context) + { + AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; + + Context.EmitLdvec(Op.Rd); + Context.EmitLdvec(Op.Rn); + + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.Encrypt)); + + Context.EmitStvec(Op.Rd); + } + + public static void Aesimc_V(AILEmitterCtx Context) + { + AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; + + Context.EmitLdvec(Op.Rn); + + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.InverseMixColumns)); + + Context.EmitStvec(Op.Rd); + } + + public static void Aesmc_V(AILEmitterCtx Context) + { + AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; + + Context.EmitLdvec(Op.Rn); + + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.MixColumns)); + + Context.EmitStvec(Op.Rd); + } + } +} diff --git a/Instruction/ASoftFallback.cs b/Instruction/ASoftFallback.cs index 0c8a39a..0ae84ab 100644 --- a/Instruction/ASoftFallback.cs +++ b/Instruction/ASoftFallback.cs @@ -410,6 +410,42 @@ namespace ChocolArm64.Instruction } #endregion +#region "Aes" + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 Decrypt(Vector128 value, Vector128 roundKey) + { + if (!Sse.IsSupported) + { + throw new PlatformNotSupportedException(); + } + + return ACryptoHelper.AESInvSubBytes(ACryptoHelper.AESInvShiftRows(Sse.Xor(value, roundKey))); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 Encrypt(Vector128 value, Vector128 roundKey) + { + if (!Sse.IsSupported) + { + throw new PlatformNotSupportedException(); + } + + return ACryptoHelper.AESSubBytes(ACryptoHelper.AESShiftRows(Sse.Xor(value, roundKey))); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 InverseMixColumns(Vector128 value) + { + return ACryptoHelper.AESInvMixColumns(value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 MixColumns(Vector128 value) + { + return ACryptoHelper.AESMixColumns(value); + } +#endregion + #region "Sha256" [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector128 HashLower(Vector128 hash_abcd, Vector128 hash_efgh, Vector128 wk)