#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; namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Digests { using Aes = System.Runtime.Intrinsics.X86.Aes; using Sse2 = System.Runtime.Intrinsics.X86.Sse2; public static class Haraka256_X86 { public static bool IsSupported => Aes.IsSupported; public static void Hash(ReadOnlySpan input, Span output) { if (!IsSupported) throw new PlatformNotSupportedException(nameof(Haraka256_X86)); var s0 = Load128(input[ ..16]); var s1 = Load128(input[16..32]); ImplRounds(ref s0, ref s1, Haraka512_X86.DefaultRoundConstants.AsSpan(0, 20)); s0 = Sse2.Xor(s0, Load128(input[ ..16])); s1 = Sse2.Xor(s1, Load128(input[16..32])); Store128(s0, output[ ..16]); Store128(s1, output[16..32]); } public static void Hash(ReadOnlySpan input, Span output, ReadOnlySpan> roundConstants) { if (!IsSupported) throw new PlatformNotSupportedException(nameof(Haraka256_X86)); var s0 = Load128(input[ ..16]); var s1 = Load128(input[16..32]); ImplRounds(ref s0, ref s1, roundConstants[..20]); s0 = Sse2.Xor(s0, Load128(input[ ..16])); s1 = Sse2.Xor(s1, Load128(input[16..32])); Store128(s0, output[ ..16]); Store128(s1, output[16..32]); } public static void Permute(ReadOnlySpan input, Span output) { if (!IsSupported) throw new PlatformNotSupportedException(nameof(Haraka256_X86)); var s0 = Load128(input[ ..16]); var s1 = Load128(input[16..32]); ImplRounds(ref s0, ref s1, Haraka512_X86.DefaultRoundConstants.AsSpan(0, 20)); Store128(s0, output[ ..16]); Store128(s1, output[16..32]); } public static void Permute(ReadOnlySpan input, Span output, ReadOnlySpan> roundConstants) { if (!IsSupported) throw new PlatformNotSupportedException(nameof(Haraka256_X86)); var s0 = Load128(input[ ..16]); var s1 = Load128(input[16..32]); ImplRounds(ref s0, ref s1, roundConstants[..20]); Store128(s0, output[ ..16]); Store128(s1, output[16..32]); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void ImplRounds(ref Vector128 s0, ref Vector128 s1, ReadOnlySpan> rc) { ImplRound(ref s0, ref s1, rc[ .. 4]); ImplRound(ref s0, ref s1, rc[ 4.. 8]); ImplRound(ref s0, ref s1, rc[ 8..12]); ImplRound(ref s0, ref s1, rc[12..16]); ImplRound(ref s0, ref s1, rc[16..20]); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void ImplRound(ref Vector128 s0, ref Vector128 s1, ReadOnlySpan> rc) { ImplAes(ref s0, ref s1, rc[..4]); ImplMix(ref s0, ref s1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void ImplAes(ref Vector128 s0, ref Vector128 s1, ReadOnlySpan> rc) { s0 = Aes.Encrypt(s0, rc[0]); s1 = Aes.Encrypt(s1, rc[1]); s0 = Aes.Encrypt(s0, rc[2]); s1 = Aes.Encrypt(s1, rc[3]); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void ImplMix(ref Vector128 s0, ref Vector128 s1) { Vector128 t0 = s0.AsUInt32(); Vector128 t1 = s1.AsUInt32(); s0 = Sse2.UnpackLow(t0, t1).AsByte(); s1 = Sse2.UnpackHigh(t0, t1).AsByte(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Vector128 Load128(ReadOnlySpan t) { if (BitConverter.IsLittleEndian && Unsafe.SizeOf>() == 16) return MemoryMarshal.Read>(t); return Vector128.Create( BinaryPrimitives.ReadUInt64LittleEndian(t[..8]), BinaryPrimitives.ReadUInt64LittleEndian(t[8..]) ).AsByte(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void Store128(Vector128 s, Span t) { if (BitConverter.IsLittleEndian && Unsafe.SizeOf>() == 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 #pragma warning restore #endif