Haraka512Digest
using Org.BouncyCastle.Utilities;
using System;
namespace Org.BouncyCastle.Crypto.Digests
{
public sealed class Haraka512Digest : HarakaBase
{
private readonly byte[] m_buf;
private int m_bufPos;
public override string AlgorithmName => "Haraka-512";
public Haraka512Digest()
{
m_buf = new byte[64];
m_bufPos = 0;
}
public override int GetByteLength()
{
return 64;
}
public override void Update(byte input)
{
if (m_bufPos > 63)
throw new ArgumentException("total input cannot be more than 64 bytes");
m_buf[m_bufPos++] = input;
}
public override void BlockUpdate(byte[] input, int inOff, int len)
{
if (m_bufPos > 64 - len)
throw new ArgumentException("total input cannot be more than 64 bytes");
Array.Copy(input, inOff, m_buf, m_bufPos, len);
m_bufPos += len;
}
public override void BlockUpdate(ReadOnlySpan<byte> input)
{
if (m_bufPos > 64 - input.Length)
throw new ArgumentException("total input cannot be more than 64 bytes");
input.CopyTo(m_buf.AsSpan(m_bufPos));
m_bufPos += input.Length;
}
public override int DoFinal(byte[] output, int outOff)
{
return DoFinal(output.AsSpan(outOff));
}
public override int DoFinal(Span<byte> output)
{
if (m_bufPos != 64)
throw new ArgumentException("input must be exactly 64 bytes");
if (output.Length < 32)
throw new ArgumentException("output too short to receive digest");
if (Haraka512_X86.IsSupported) {
Haraka512_X86.Hash(m_buf, output);
Reset();
return 32;
}
int result = Haraka512256(m_buf, output);
Reset();
return result;
}
public override void Reset()
{
m_bufPos = 0;
Array.Clear(m_buf, 0, 64);
}
private static int Haraka512256(ReadOnlySpan<byte> msg, Span<byte> output)
{
byte[][] array = new byte[4][] {
new byte[16],
new byte[16],
new byte[16],
new byte[16]
};
byte[][] array2 = new byte[4][] {
new byte[16],
new byte[16],
new byte[16],
new byte[16]
};
ReadOnlySpan<byte> readOnlySpan = msg.Slice(0, 16);
readOnlySpan.CopyTo(array[0]);
readOnlySpan = msg.Slice(16, 16);
readOnlySpan.CopyTo(array[1]);
readOnlySpan = msg.Slice(32, 16);
readOnlySpan.CopyTo(array[2]);
readOnlySpan = msg.Slice(48, 16);
readOnlySpan.CopyTo(array[3]);
array[0] = HarakaBase.AesEnc(array[0], HarakaBase.RC[0]);
array[1] = HarakaBase.AesEnc(array[1], HarakaBase.RC[1]);
array[2] = HarakaBase.AesEnc(array[2], HarakaBase.RC[2]);
array[3] = HarakaBase.AesEnc(array[3], HarakaBase.RC[3]);
array[0] = HarakaBase.AesEnc(array[0], HarakaBase.RC[4]);
array[1] = HarakaBase.AesEnc(array[1], HarakaBase.RC[5]);
array[2] = HarakaBase.AesEnc(array[2], HarakaBase.RC[6]);
array[3] = HarakaBase.AesEnc(array[3], HarakaBase.RC[7]);
Mix512(array, array2);
array[0] = HarakaBase.AesEnc(array2[0], HarakaBase.RC[8]);
array[1] = HarakaBase.AesEnc(array2[1], HarakaBase.RC[9]);
array[2] = HarakaBase.AesEnc(array2[2], HarakaBase.RC[10]);
array[3] = HarakaBase.AesEnc(array2[3], HarakaBase.RC[11]);
array[0] = HarakaBase.AesEnc(array[0], HarakaBase.RC[12]);
array[1] = HarakaBase.AesEnc(array[1], HarakaBase.RC[13]);
array[2] = HarakaBase.AesEnc(array[2], HarakaBase.RC[14]);
array[3] = HarakaBase.AesEnc(array[3], HarakaBase.RC[15]);
Mix512(array, array2);
array[0] = HarakaBase.AesEnc(array2[0], HarakaBase.RC[16]);
array[1] = HarakaBase.AesEnc(array2[1], HarakaBase.RC[17]);
array[2] = HarakaBase.AesEnc(array2[2], HarakaBase.RC[18]);
array[3] = HarakaBase.AesEnc(array2[3], HarakaBase.RC[19]);
array[0] = HarakaBase.AesEnc(array[0], HarakaBase.RC[20]);
array[1] = HarakaBase.AesEnc(array[1], HarakaBase.RC[21]);
array[2] = HarakaBase.AesEnc(array[2], HarakaBase.RC[22]);
array[3] = HarakaBase.AesEnc(array[3], HarakaBase.RC[23]);
Mix512(array, array2);
array[0] = HarakaBase.AesEnc(array2[0], HarakaBase.RC[24]);
array[1] = HarakaBase.AesEnc(array2[1], HarakaBase.RC[25]);
array[2] = HarakaBase.AesEnc(array2[2], HarakaBase.RC[26]);
array[3] = HarakaBase.AesEnc(array2[3], HarakaBase.RC[27]);
array[0] = HarakaBase.AesEnc(array[0], HarakaBase.RC[28]);
array[1] = HarakaBase.AesEnc(array[1], HarakaBase.RC[29]);
array[2] = HarakaBase.AesEnc(array[2], HarakaBase.RC[30]);
array[3] = HarakaBase.AesEnc(array[3], HarakaBase.RC[31]);
Mix512(array, array2);
array[0] = HarakaBase.AesEnc(array2[0], HarakaBase.RC[32]);
array[1] = HarakaBase.AesEnc(array2[1], HarakaBase.RC[33]);
array[2] = HarakaBase.AesEnc(array2[2], HarakaBase.RC[34]);
array[3] = HarakaBase.AesEnc(array2[3], HarakaBase.RC[35]);
array[0] = HarakaBase.AesEnc(array[0], HarakaBase.RC[36]);
array[1] = HarakaBase.AesEnc(array[1], HarakaBase.RC[37]);
array[2] = HarakaBase.AesEnc(array[2], HarakaBase.RC[38]);
array[3] = HarakaBase.AesEnc(array[3], HarakaBase.RC[39]);
Mix512(array, array2);
Bytes.Xor(16, array2[0], msg, array[0]);
Bytes.Xor(16, array2[1], msg.Slice(16, msg.Length - 16), array[1]);
Bytes.Xor(16, array2[2], msg.Slice(32, msg.Length - 32), array[2]);
Bytes.Xor(16, array2[3], msg.Slice(48, msg.Length - 48), array[3]);
Span<byte> span = array[0].AsSpan(8, 8);
span.CopyTo(output);
span = array[1].AsSpan(8, 8);
span.CopyTo(output.Slice(8, output.Length - 8));
span = array[2].AsSpan(0, 8);
span.CopyTo(output.Slice(16, output.Length - 16));
span = array[3].AsSpan(0, 8);
span.CopyTo(output.Slice(24, output.Length - 24));
return HarakaBase.DIGEST_SIZE;
}
private static void Mix512(byte[][] s1, byte[][] s2)
{
Array.Copy(s1[0], 12, s2[0], 0, 4);
Array.Copy(s1[2], 12, s2[0], 4, 4);
Array.Copy(s1[1], 12, s2[0], 8, 4);
Array.Copy(s1[3], 12, s2[0], 12, 4);
Array.Copy(s1[2], 0, s2[1], 0, 4);
Array.Copy(s1[0], 0, s2[1], 4, 4);
Array.Copy(s1[3], 0, s2[1], 8, 4);
Array.Copy(s1[1], 0, s2[1], 12, 4);
Array.Copy(s1[2], 4, s2[2], 0, 4);
Array.Copy(s1[0], 4, s2[2], 4, 4);
Array.Copy(s1[3], 4, s2[2], 8, 4);
Array.Copy(s1[1], 4, s2[2], 12, 4);
Array.Copy(s1[0], 8, s2[3], 0, 4);
Array.Copy(s1[2], 8, s2[3], 4, 4);
Array.Copy(s1[1], 8, s2[3], 8, 4);
Array.Copy(s1[3], 8, s2[3], 12, 4);
}
}
}