AsconHash256
Ascon-Hash256 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 AsconHash256 : 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;
public string AlgorithmName => "Ascon-Hash256";
public AsconHash256()
{
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) {
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");
BlockUpdate(input.AsSpan(inOff, inLen));
}
public void BlockUpdate(ReadOnlySpan<byte> input)
{
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);
P12();
int num2 = num;
input = input.Slice(num2, input.Length - num2);
}
while (input.Length >= 8) {
S0 ^= Pack.LE_To_UInt64(input);
P12();
input = input.Slice(8, input.Length - 8);
}
input.CopyTo(m_buf);
m_bufPos = input.Length;
}
}
public int DoFinal(byte[] output, int outOff)
{
return DoFinal(output.AsSpan(outOff));
}
public int DoFinal(Span<byte> output)
{
Check.OutputLength(output, 32, "output buffer too short");
PadAndAbsorb();
Pack.UInt64_To_LE(S0, output);
for (int i = 0; i < 3; i++) {
output = output.Slice(8, output.Length - 8);
P12();
Pack.UInt64_To_LE(S0, output);
}
Reset();
return 32;
}
public void Reset()
{
S0 = 11177464323724596865;
S1 = 5459383224871899602;
S2 = 12566513473065105434;
S3 = 4359436768738168243;
S4 = 1899470422303676269;
Array.Clear(m_buf, 0, m_buf.Length);
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);
}
[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));
}
}
}