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

AsconDigest

public sealed class AsconDigest : IDigest
ASCON v1.2 Hash, https://ascon.iaik.tugraz.at/ .
using Org.BouncyCastle.Crypto.Utilities; using Org.BouncyCastle.Utilities; using System; using System.Runtime.CompilerServices; namespace Org.BouncyCastle.Crypto.Digests { [Obsolete("This class is deprecated. For the latest Ascon version, use AsconHash256 instead.")] public sealed class AsconDigest : IDigest { public enum AsconParameters { AsconHash, AsconHashA } private readonly AsconParameters m_asconParameters; private readonly int ASCON_PB_ROUNDS; private ulong x0; private ulong x1; private ulong x2; private ulong x3; private ulong x4; private readonly byte[] m_buf = new byte[8]; private int m_bufPos; public string AlgorithmName { get { switch (m_asconParameters) { case AsconParameters.AsconHash: return "Ascon-Hash"; case AsconParameters.AsconHashA: return "Ascon-HashA"; default: throw new InvalidOperationException(); } } } public AsconDigest(AsconParameters parameters) { m_asconParameters = parameters; switch (parameters) { case AsconParameters.AsconHash: ASCON_PB_ROUNDS = 12; break; case AsconParameters.AsconHashA: ASCON_PB_ROUNDS = 8; break; default: throw new ArgumentException("Invalid parameter settings for Ascon Hash"); } Reset(); } public int GetDigestSize() { return 32; } public int GetByteLength() { return 8; } public void Update(byte input) { m_buf[m_bufPos] = input; if (++m_bufPos == 8) { x0 ^= Pack.BE_To_UInt64(m_buf, 0); P(ASCON_PB_ROUNDS); m_bufPos = 0; } } public void BlockUpdate(byte[] input, int inOff, int inLen) { Check.DataLength(input, inOff, inLen, "input buffer too short"); 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; x0 ^= Pack.BE_To_UInt64(m_buf, 0); P(ASCON_PB_ROUNDS); } int num3; while ((num3 = inLen - num2) >= 8) { x0 ^= Pack.BE_To_UInt64(input, inOff + num2); P(ASCON_PB_ROUNDS); num2 += 8; } Array.Copy(input, inOff + num2, m_buf, 0, num3); m_bufPos = num3; } } } public int DoFinal(byte[] output, int outOff) { Check.OutputLength(output, outOff, 32, "output buffer too short"); FinishAbsorbing(); Pack.UInt64_To_BE(x0, output, outOff); for (int i = 0; i < 3; i++) { outOff += 8; P(ASCON_PB_ROUNDS); Pack.UInt64_To_BE(x0, output, outOff); } Reset(); return 32; } public void Reset() { Array.Clear(m_buf, 0, m_buf.Length); m_bufPos = 0; switch (m_asconParameters) { case AsconParameters.AsconHashA: x0 = 92044056785660070; x1 = 8326807761760157607; x2 = 3371194088139667532; x3 = 15489749720654559101; x4 = 11618234402860862855; break; case AsconParameters.AsconHash: x0 = 17191252062196199485; x1 = 10066134719181819906; x2 = 13009371945472744034; x3 = 4834782570098516968; x4 = 3787428097924915520; break; default: throw new InvalidOperationException(); } } private void FinishAbsorbing() { m_buf[m_bufPos] = 128; x0 ^= (ulong)((long)Pack.BE_To_UInt64(m_buf, 0) & (-1 << 56 - (m_bufPos << 3))); P(12); } private void P(int nr) { if (nr == 12) { 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 = x0 ^ x1 ^ x2 ^ x3 ^ c ^ (x1 & (x0 ^ x2 ^ x4 ^ c)); ulong num2 = x0 ^ x2 ^ x3 ^ x4 ^ c ^ ((x1 ^ x2 ^ c) & (x1 ^ x3)); ulong num3 = x1 ^ x2 ^ x4 ^ c ^ (x3 & x4); ulong num4 = x0 ^ x1 ^ x2 ^ c ^ (~x0 & (x3 ^ x4)); ulong num5 = x1 ^ x3 ^ x4 ^ ((x0 ^ x4) & x1); x0 = (num ^ Longs.RotateRight(num, 19) ^ Longs.RotateRight(num, 28)); x1 = (num2 ^ Longs.RotateRight(num2, 39) ^ Longs.RotateRight(num2, 61)); x2 = ~(num3 ^ Longs.RotateRight(num3, 1) ^ Longs.RotateRight(num3, 6)); x3 = (num4 ^ Longs.RotateRight(num4, 10) ^ Longs.RotateRight(num4, 17)); x4 = (num5 ^ Longs.RotateRight(num5, 7) ^ Longs.RotateRight(num5, 41)); } } }