<PackageReference Include="BouncyCastle.Cryptography" Version="2.4.0" />

Haraka256_X86

public static class Haraka256_X86
using Org.BouncyCastle.Runtime.Intrinsics; using Org.BouncyCastle.Runtime.Intrinsics.X86; using System; using System.Buffers.Binary; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; namespace Org.BouncyCastle.Crypto.Digests { public static class Haraka256_X86 { public static bool IsSupported => Org.BouncyCastle.Runtime.Intrinsics.X86.Aes.IsEnabled; public static void Hash(ReadOnlySpan<byte> input, Span<byte> output) { if (!IsSupported) throw new PlatformNotSupportedException("Haraka256_X86"); Vector128<byte> s = Load128(input.Slice(0, 16)); Vector128<byte> s2 = Load128(input.Slice(16, 16)); ImplRounds(ref s, ref s2, Haraka512_X86.DefaultRoundConstants.AsSpan(0, 20)); s = System.Runtime.Intrinsics.X86.Sse2.Xor(s, Load128(input.Slice(0, 16))); s2 = System.Runtime.Intrinsics.X86.Sse2.Xor(s2, Load128(input.Slice(16, 16))); Store128(s, output.Slice(0, 16)); Store128(s2, output.Slice(16, 16)); } public static void Hash(ReadOnlySpan<byte> input, Span<byte> output, ReadOnlySpan<Vector128<byte>> roundConstants) { if (!IsSupported) throw new PlatformNotSupportedException("Haraka256_X86"); Vector128<byte> s = Load128(input.Slice(0, 16)); Vector128<byte> s2 = Load128(input.Slice(16, 16)); ImplRounds(ref s, ref s2, roundConstants.Slice(0, 20)); s = System.Runtime.Intrinsics.X86.Sse2.Xor(s, Load128(input.Slice(0, 16))); s2 = System.Runtime.Intrinsics.X86.Sse2.Xor(s2, Load128(input.Slice(16, 16))); Store128(s, output.Slice(0, 16)); Store128(s2, output.Slice(16, 16)); } public static void Permute(ReadOnlySpan<byte> input, Span<byte> output) { if (!IsSupported) throw new PlatformNotSupportedException("Haraka256_X86"); Vector128<byte> s = Load128(input.Slice(0, 16)); Vector128<byte> s2 = Load128(input.Slice(16, 16)); ImplRounds(ref s, ref s2, Haraka512_X86.DefaultRoundConstants.AsSpan(0, 20)); Store128(s, output.Slice(0, 16)); Store128(s2, output.Slice(16, 16)); } public static void Permute(ReadOnlySpan<byte> input, Span<byte> output, ReadOnlySpan<Vector128<byte>> roundConstants) { if (!IsSupported) throw new PlatformNotSupportedException("Haraka256_X86"); Vector128<byte> s = Load128(input.Slice(0, 16)); Vector128<byte> s2 = Load128(input.Slice(16, 16)); ImplRounds(ref s, ref s2, roundConstants.Slice(0, 20)); Store128(s, output.Slice(0, 16)); Store128(s2, output.Slice(16, 16)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void ImplRounds(ref Vector128<byte> s0, ref Vector128<byte> s1, ReadOnlySpan<Vector128<byte>> rc) { ImplRound(ref s0, ref s1, rc.Slice(0, 4)); ImplRound(ref s0, ref s1, rc.Slice(4, 4)); ImplRound(ref s0, ref s1, rc.Slice(8, 4)); ImplRound(ref s0, ref s1, rc.Slice(12, 4)); ImplRound(ref s0, ref s1, rc.Slice(16, 4)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void ImplRound(ref Vector128<byte> s0, ref Vector128<byte> s1, ReadOnlySpan<Vector128<byte>> rc) { ImplAes(ref s0, ref s1, rc.Slice(0, 4)); ImplMix(ref s0, ref s1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void ImplAes(ref Vector128<byte> s0, ref Vector128<byte> s1, ReadOnlySpan<Vector128<byte>> rc) { Vector128<byte> value = System.Runtime.Intrinsics.X86.Aes.Encrypt(s0, rc[0]); Vector128<byte> value2 = System.Runtime.Intrinsics.X86.Aes.Encrypt(s1, rc[1]); s0 = System.Runtime.Intrinsics.X86.Aes.Encrypt(value, rc[2]); s1 = System.Runtime.Intrinsics.X86.Aes.Encrypt(value2, rc[3]); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void ImplMix(ref Vector128<byte> s0, ref Vector128<byte> s1) { Vector128<uint> left = s0.AsUInt32(); Vector128<uint> right = s1.AsUInt32(); s0 = System.Runtime.Intrinsics.X86.Sse2.UnpackLow(left, right).AsByte(); s1 = System.Runtime.Intrinsics.X86.Sse2.UnpackHigh(left, right).AsByte(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Vector128<byte> Load128(ReadOnlySpan<byte> t) { if (Vector.IsPackedLittleEndian) return MemoryMarshal.Read<Vector128<byte>>(t); return Vector128.Create(BinaryPrimitives.ReadUInt64LittleEndian(t.Slice(0, 8)), BinaryPrimitives.ReadUInt64LittleEndian(t.Slice(8, t.Length - 8))).AsByte(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void Store128(Vector128<byte> s, Span<byte> t) { if (Vector.IsPackedLittleEndian) MemoryMarshal.Write(t, ref s); else { Vector128<ulong> vector = s.AsUInt64(); BinaryPrimitives.WriteUInt64LittleEndian(t.Slice(0, 8), vector.GetElement(0)); BinaryPrimitives.WriteUInt64LittleEndian(t.Slice(8, t.Length - 8), vector.GetElement(1)); } } } }