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));
}
}
}
}