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

XoodyakDigest

public sealed class XoodyakDigest : IDigest
using Org.BouncyCastle.Crypto.Utilities; using Org.BouncyCastle.Utilities; using System; using System.IO; namespace Org.BouncyCastle.Crypto.Digests { public sealed class XoodyakDigest : IDigest { private enum MODE { ModeHash, ModeKeyed } private const int Rkin = 44; private static readonly uint[] RC = new uint[12] { 88, 56, 960, 208, 288, 20, 96, 44, 896, 240, 416, 18 }; private byte[] state; private int phase; private MODE mode; private int Rabsorb; private const int f_bPrime = 48; private const int Rkout = 24; private const int PhaseDown = 1; private const int PhaseUp = 2; private const int NLANES = 12; private const int NROWS = 3; private const int NCOLUMNS = 4; private const int MAXROUNDS = 12; private const int TAGLEN = 16; private const int Rhash = 16; private readonly MemoryStream buffer = new MemoryStream(); public string AlgorithmName => "Xoodyak Hash"; public XoodyakDigest() { state = new byte[48]; Reset(); } public int GetDigestSize() { return 32; } public int GetByteLength() { return Rabsorb; } public void Update(byte input) { buffer.WriteByte(input); } public void BlockUpdate(byte[] input, int inOff, int inLen) { Check.DataLength(input, inOff, inLen, "input buffer too short"); buffer.Write(input, inOff, inLen); } public int DoFinal(byte[] output, int outOff) { Check.OutputLength(output, outOff, 32, "output buffer too short"); byte[] xi = buffer.GetBuffer(); int num = (int)buffer.Length; int num2 = 0; uint cd = 3; do { if (phase != 2) Up(null, 0, 0, 0); int num3 = System.Math.Min(num, Rabsorb); Down(xi, num2, num3, cd); cd = 0; num2 += num3; num -= num3; } while (num != 0); Up(output, outOff, 16, 64); Down(null, 0, 0, 0); Up(output, outOff + 16, 16, 0); return 32; } public void Reset() { Array.Clear(state, 0, state.Length); phase = 2; mode = MODE.ModeHash; Rabsorb = 16; buffer.SetLength(0); } private void Up(byte[] Yi, int YiOff, int YiLen, uint Cu) { if (mode != 0) state[47] ^= (byte)Cu; uint[] array = new uint[12]; Pack.LE_To_UInt32(state, 0, array, 0, array.Length); uint[] array2 = new uint[12]; uint[] array3 = new uint[4]; uint[] array4 = new uint[4]; for (int i = 0; i < 12; i++) { for (uint num = 0; num < 4; num++) { array3[num] = (array[index(num, 0)] ^ array[index(num, 1)] ^ array[index(num, 2)]); } for (uint num = 0; num < 4; num++) { uint i2 = array3[(num + 3) & 3]; array4[num] = (Integers.RotateLeft(i2, 5) ^ Integers.RotateLeft(i2, 14)); } for (uint num = 0; num < 4; num++) { for (uint i2 = 0; i2 < 3; i2++) { array[index(num, i2)] ^= array4[num]; } } for (uint num = 0; num < 4; num++) { array2[index(num, 0)] = array[index(num, 0)]; array2[index(num, 1)] = array[index(num + 3, 1)]; array2[index(num, 2)] = Integers.RotateLeft(array[index(num, 2)], 11); } array2[0] ^= RC[i]; for (uint num = 0; num < 4; num++) { for (uint i2 = 0; i2 < 3; i2++) { array[index(num, i2)] = (array2[index(num, i2)] ^ (~array2[index(num, i2 + 1)] & array2[index(num, i2 + 2)])); } } for (uint num = 0; num < 4; num++) { array2[index(num, 0)] = array[index(num, 0)]; array2[index(num, 1)] = Integers.RotateLeft(array[index(num, 1)], 1); array2[index(num, 2)] = Integers.RotateLeft(array[index(num + 2, 2)], 8); } Array.Copy(array2, 0, array, 0, 12); } Pack.UInt32_To_LE(array, 0, array.Length, state, 0); phase = 2; if (Yi != null) Array.Copy(state, 0, Yi, YiOff, YiLen); } private void Down(byte[] Xi, int XiOff, int XiLen, uint Cd) { for (int i = 0; i < XiLen; i++) { state[i] ^= Xi[XiOff++]; } state[XiLen] ^= 1; state[47] ^= (byte)((mode == MODE.ModeHash) ? (Cd & 1) : Cd); phase = 1; } private uint index(uint x, uint y) { return y % 3 * 4 + x % 4; } } }