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

AsconCXof128

public sealed class AsconCXof128 : IXof, IDigest
Ascon-CXOF128 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 AsconCXof128 : IXof, IDigest { private const int Rate = 8; private readonly byte[] m_buf = new byte[8]; private readonly ulong Z0; private readonly ulong Z1; private readonly ulong Z2; private readonly ulong Z3; private readonly ulong Z4; 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-CXOF128"; public AsconCXof128() : this(Array.Empty<byte>()) { } public AsconCXof128(byte[] z) : this(z, 0, z.Length) { } public AsconCXof128(byte[] z, int zOff, int zLen) { Arrays.ValidateSegment(z, zOff, zLen); if (zLen > 256) throw new ArgumentOutOfRangeException("customization string too long"); InitState(z, zOff, zLen); Z0 = S0; Z1 = S1; Z2 = S2; Z3 = S3; Z4 = S4; } 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 = Z0; S1 = Z1; S2 = Z2; S3 = Z3; S4 = Z4; 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 InitState(byte[] z, int zOff, int zLen) { if (zLen == 0) { S0 = 5768210384618244584; S1 = 6623958265790276749; S2 = 4252419465292010770; S3 = 1238191464582506891; S4 = 56353695744608240; } else { S0 = 7445901275803737603; S1 = 4886737088792722364; S2 = 16829984708047569333; S3 = 3076320316797452470; S4 = 10322000768943701062; ulong num = Convert.ToUInt64(zLen) << 3; S0 ^= num; P12(); BlockUpdate(z, zOff, zLen); PadAndAbsorb(); P12(); } m_bufPos = 0; } 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)); } } }