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

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