HarakaS_X86
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Runtime.Intrinsics;
using Org.BouncyCastle.Utilities;
using System;
using System.Buffers.Binary;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
namespace Org.BouncyCastle.Pqc.Crypto.SphincsPlus
{
internal class HarakaS_X86 : IXof, IDigest
{
private enum State
{
Absorbing,
Squeezing
}
private readonly Vector128<byte>[] m_roundConstants = new Vector128<byte>[40];
private readonly byte[] m_buf = new byte[64];
private int m_bufPos;
private State m_state;
public static bool IsSupported => Haraka512_X86.IsSupported;
internal ReadOnlySpan<Vector128<byte>> RoundConstants => m_roundConstants;
public string AlgorithmName => "HarakaS";
internal unsafe HarakaS_X86(ReadOnlySpan<byte> pkSeed)
{
if (!IsSupported)
throw new PlatformNotSupportedException("HarakaS_X86");
Span<byte> span = new Span<byte>(stackalloc byte[64], 64);
while (pkSeed.Length >= 32) {
Bytes.XorTo(32, pkSeed, span);
Haraka512_X86.Permute(span, span);
pkSeed = pkSeed.Slice(32, pkSeed.Length - 32);
}
Bytes.XorTo(pkSeed.Length, pkSeed, span);
span[pkSeed.Length] ^= 31;
span[31] ^= 128;
int num = 0;
while (num < 40) {
Haraka512_X86.Permute(span, span);
m_roundConstants[num++] = Load128(span.Slice(0, 16));
m_roundConstants[num++] = Load128(span.Slice(16, 16));
}
}
public int GetDigestSize()
{
return 32;
}
public int GetByteLength()
{
return 32;
}
public void Update(byte input)
{
if (m_state != 0)
throw new InvalidOperationException();
m_buf[m_bufPos++] ^= input;
if (m_bufPos == 32) {
Haraka512_X86.Permute(m_buf, m_buf, m_roundConstants);
m_bufPos = 0;
}
}
public void BlockUpdate(byte[] input, int inOff, int inLen)
{
BlockUpdate(input.AsSpan(inOff, inLen));
}
public void BlockUpdate(ReadOnlySpan<byte> input)
{
if (m_state != 0)
throw new InvalidOperationException();
int num = 32 - m_bufPos;
if (input.Length < num) {
Bytes.XorTo(input.Length, input, m_buf.AsSpan(m_bufPos));
m_bufPos += input.Length;
} else {
Bytes.XorTo(num, input, m_buf.AsSpan(m_bufPos));
int num2 = num;
input = input.Slice(num2, input.Length - num2);
Haraka512_X86.Permute(m_buf, m_buf, m_roundConstants);
while (input.Length >= 32) {
Bytes.XorTo(32, input, m_buf);
input = input.Slice(32, input.Length - 32);
Haraka512_X86.Permute(m_buf, m_buf, m_roundConstants);
}
Bytes.XorTo(input.Length, input, m_buf);
m_bufPos = input.Length;
}
}
public int DoFinal(byte[] output, int outOff)
{
return OutputFinal(output.AsSpan(outOff, 32));
}
public int DoFinal(Span<byte> output)
{
return OutputFinal(output.Slice(0, 32));
}
public int Output(byte[] output, int outOff, int outLen)
{
return Output(output.AsSpan(outOff, outLen));
}
public int Output(Span<byte> output)
{
int length = output.Length;
if (m_state != State.Squeezing) {
m_buf[m_bufPos] ^= 31;
m_buf[31] ^= 128;
m_bufPos = 32;
m_state = State.Squeezing;
if (output.IsEmpty)
return length;
} else {
int num = 32 - m_bufPos;
if (output.Length <= num) {
output.CopyFrom(m_buf.AsSpan(m_bufPos));
m_bufPos += num;
return length;
}
output.Slice(0, num).CopyFrom(m_buf.AsSpan(m_bufPos));
int num2 = num;
output = output.Slice(num2, output.Length - num2);
}
while (output.Length > 32) {
Haraka512_X86.Permute(m_buf, m_buf, m_roundConstants);
output.Slice(0, 32).CopyFrom(m_buf);
output = output.Slice(32, output.Length - 32);
}
Haraka512_X86.Permute(m_buf, m_buf, m_roundConstants);
output.CopyFrom(m_buf);
m_bufPos = output.Length;
return length;
}
public int OutputFinal(byte[] output, int outOff, int outLen)
{
return OutputFinal(output.AsSpan(outOff, outLen));
}
public int OutputFinal(Span<byte> output)
{
int result = Output(output);
Reset();
return result;
}
public void Reset()
{
Array.Clear(m_buf);
m_bufPos = 0;
m_state = State.Absorbing;
}
[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();
}
}
}