<PackageReference Include="BouncyCastle.Cryptography" Version="2.5.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; 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); P12(); m_bufPos = 0; } } public void BlockUpdate(byte[] input, int inOff, int inLen) { Check.DataLength(input, inOff, inLen, "input buffer too short"); if (m_squeezing) throw new InvalidOperationException("attempt to absorb while squeezing"); if (inLen >= 1) { int num = 8 - m_bufPos; if (inLen < num) { Array.Copy(input, inOff, m_buf, m_bufPos, inLen); m_bufPos += inLen; } else { int num2 = 0; if (m_bufPos > 0) { Array.Copy(input, inOff, m_buf, m_bufPos, num); num2 += num; S0 ^= Pack.LE_To_UInt64(m_buf, 0); P12(); } int num3; while ((num3 = inLen - num2) >= 8) { S0 ^= Pack.LE_To_UInt64(input, inOff + num2); P12(); num2 += 8; } Array.Copy(input, inOff + num2, m_buf, 0, num3); m_bufPos = num3; } } } public int DoFinal(byte[] output, int outOff) { return OutputFinal(output, outOff, GetDigestSize()); } 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"); int result = Output(output, outOff, outLen); Reset(); return result; } public int Output(byte[] output, int outOff, int outLen) { Check.OutputLength(output, outOff, outLen, "output buffer is too short"); int result = outLen; if (!m_squeezing) { FinishAbsorbing(); if (outLen >= 8) { Pack.UInt64_To_LE(S0, output, outOff); outOff += 8; outLen -= 8; } else { Pack.UInt64_To_LE(S0, m_buf); m_bufPos = 0; } } if (m_bufPos < 8) { int num = 8 - m_bufPos; if (outLen <= num) { Array.Copy(m_buf, m_bufPos, output, outOff, outLen); m_bufPos += outLen; return result; } Array.Copy(m_buf, m_bufPos, output, outOff, num); outOff += num; outLen -= num; } while (outLen >= 8) { P12(); Pack.UInt64_To_LE(S0, output, outOff); outOff += 8; outLen -= 8; } if (outLen > 0) { P12(); Pack.UInt64_To_LE(S0, m_buf); Array.Copy(m_buf, 0, output, outOff, outLen); } m_bufPos = outLen; return result; } private void FinishAbsorbing() { PadAndAbsorb(); m_bufPos = m_buf.Length; m_squeezing = true; } private void InitState(byte[] z, int zOff, int zLen) { S0 = 7445901275803737603; S1 = 4886737088792722364; S2 = 16829984708047569333; S3 = 3076320316797452470; S4 = 10322000768943701062; Pack.UInt64_To_LE(Convert.ToUInt64(zLen) << 3, m_buf); P12(); BlockUpdate(z, zOff, zLen); PadAndAbsorb(); 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); P12(); } 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); } 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)); } } }