<PackageReference Include="BouncyCastle.Cryptography" Version="2.7.0-beta.98" />

AsconXof128

public sealed class AsconXof128 : IXof, IDigest
Ascon-XOF128 was introduced in NIST Special Publication (SP) 800-232 (Initial Public Draft).
using Org.BouncyCastle.Crypto.Utilities; using Org.BouncyCastle.Utilities; using System; using System.Runtime.CompilerServices; namespace Org.BouncyCastle.Crypto.Digests { public sealed class AsconXof128 : IXof, IDigest { private const int Rate = 8; private readonly byte[] m_buf = new byte[8]; private ulong S0; private ulong S1; private ulong S2; private ulong S3; private ulong S4; private int m_bufPos; private bool m_squeezing; public string AlgorithmName => "Ascon-XOF128"; public AsconXof128() { Reset(); } public int GetDigestSize() { return 32; } public int GetByteLength() { return 8; } public void Update(byte input) { if (m_squeezing) throw new InvalidOperationException("attempt to absorb while squeezing"); m_buf[m_bufPos] = input; if (++m_bufPos == 8) { S0 ^= Pack.LE_To_UInt64(m_buf, 0); m_bufPos = 0; P12(); } } public void BlockUpdate(byte[] input, int inOff, int inLen) { Check.DataLength(input, inOff, inLen, "input buffer too short"); BlockUpdate(input.AsSpan(inOff, inLen)); } public void BlockUpdate(ReadOnlySpan<byte> input) { if (m_squeezing) throw new InvalidOperationException("attempt to absorb while squeezing"); int num = 8 - m_bufPos; if (input.Length < num) { input.CopyTo(m_buf.AsSpan(m_bufPos)); m_bufPos += input.Length; } else { if (m_bufPos > 0) { input.Slice(0, num).CopyTo(m_buf.AsSpan(m_bufPos)); S0 ^= Pack.LE_To_UInt64(m_buf); int num2 = num; input = input.Slice(num2, input.Length - num2); P12(); } while (input.Length >= 8) { S0 ^= Pack.LE_To_UInt64(input); input = input.Slice(8, input.Length - 8); P12(); } input.CopyTo(m_buf); m_bufPos = input.Length; } } public int DoFinal(byte[] output, int outOff) { return OutputFinal(output, outOff, GetDigestSize()); } public int DoFinal(Span<byte> output) { int digestSize = GetDigestSize(); Check.OutputLength(output, digestSize, "output buffer is too short"); return OutputFinal(output.Slice(0, digestSize)); } public void Reset() { S0 = 15745374255817443307; S1 = 14734905824818166121; S2 = 16667980376626976305; S3 = 1072114354614917324; S4 = 16164673763700313054; Array.Clear(m_buf, 0, m_buf.Length); m_bufPos = 0; m_squeezing = false; } public int OutputFinal(byte[] output, int outOff, int outLen) { Check.OutputLength(output, outOff, outLen, "output buffer is too short"); return OutputFinal(output.AsSpan(outOff, outLen)); } public int OutputFinal(Span<byte> output) { int result = Output(output); Reset(); return result; } public int Output(byte[] output, int outOff, int outLen) { Check.OutputLength(output, outOff, outLen, "output buffer is too short"); return Output(output.AsSpan(outOff, outLen)); } public int Output(Span<byte> output) { int length = output.Length; if (!m_squeezing) { PadAndAbsorb(); m_squeezing = true; m_bufPos = 8; } else if (m_bufPos < 8) { int num = 8 - m_bufPos; if (output.Length <= num) { output.CopyFrom(m_buf.AsSpan(m_bufPos)); m_bufPos += output.Length; return length; } output.Slice(0, num).CopyFrom(m_buf.AsSpan(m_bufPos)); int num2 = num; output = output.Slice(num2, output.Length - num2); m_bufPos = 8; } while (output.Length >= 8) { P12(); Pack.UInt64_To_LE(S0, output); output = output.Slice(8, output.Length - 8); } if (!output.IsEmpty) { P12(); Pack.UInt64_To_LE(S0, m_buf); output.CopyFrom(m_buf); m_bufPos = output.Length; } return length; } private void PadAndAbsorb() { int num = m_bufPos << 3; S0 ^= (Pack.LE_To_UInt64(m_buf, 0) & (72057594037927935 >> 56 - num)); S0 ^= (ulong)(1 << num); } private void P12() { Round(240); Round(225); Round(210); Round(195); Round(180); Round(165); Round(150); Round(135); Round(120); Round(105); Round(90); Round(75); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void Round(ulong c) { ulong num = S2 ^ c; ulong num2 = S0 ^ S1 ^ num ^ S3 ^ (S1 & (S0 ^ num ^ S4)); ulong num3 = S0 ^ num ^ S3 ^ S4 ^ ((S1 ^ num) & (S1 ^ S3)); ulong num4 = S1 ^ num ^ S4 ^ (S3 & S4); ulong num5 = S0 ^ S1 ^ num ^ (~S0 & (S3 ^ S4)); ulong num6 = S1 ^ S3 ^ S4 ^ ((S0 ^ S4) & S1); S0 = (num2 ^ Longs.RotateRight(num2, 19) ^ Longs.RotateRight(num2, 28)); S1 = (num3 ^ Longs.RotateRight(num3, 39) ^ Longs.RotateRight(num3, 61)); S2 = ~(num4 ^ Longs.RotateRight(num4, 1) ^ Longs.RotateRight(num4, 6)); S3 = (num5 ^ Longs.RotateRight(num5, 10) ^ Longs.RotateRight(num5, 17)); S4 = (num6 ^ Longs.RotateRight(num6, 7) ^ Longs.RotateRight(num6, 41)); } } }