Uses Sha3 to Shuffle Primitive Arrays
using System; public class ArrayMixer { private readonly SHA3ModInt _alg; private readonly int _moveSize; public ArrayMixer() : this(256, 24) { } public ArrayMixer(int hashSize) : this(hashSize, 24) { } public ArrayMixer(int hashSize, int rounds) { _alg = new SHA3ModInt(hashSize, rounds); _moveSize = _alg.ComputeHash(2.GetBytes()).Length; } public byte[] Mix(byte[] buf, int iterations = 1000) { var bufferSize = buf.Length; var lBuffer = new byte[_moveSize]; var oBuffer = new byte[bufferSize]; for (var i = 0; i < iterations; ++i) { var bytesSuffled = 0; var moveSize = _moveSize; var p = 0; while (true) { var rBytesShuffle = bufferSize - bytesSuffled; if (rBytesShuffle < moveSize) moveSize = rBytesShuffle; if (rBytesShuffle <= 0) break; Buffer.BlockCopy(buf, p, lBuffer, 0, moveSize); lBuffer = _alg.ComputeHash(lBuffer); Buffer.BlockCopy(lBuffer, 0, oBuffer, p, moveSize); p += moveSize; bytesSuffled += moveSize; } Buffer.BlockCopy(oBuffer, 0, buf, 0, bufferSize); } lBuffer.Fill(0); oBuffer.Fill(0); return buf; } public ushort[] Mix(ushort[] buf, int iterations = 1000) { var bb = buf.GetBytes(); return Mix(bb, iterations).ToUShortArray(); } public uint[] Mix(uint[] buf, int iterations = 1000) { var bb = buf.GetBytes(); return Mix(bb, iterations).ToUIntArray(); } public ulong[] Mix(ulong[] buf, int iterations = 1000) { var bb = buf.GetBytes(); return Mix(bb, iterations).ToULongArray(); } /// <summary> /// Will round up finalSize to the nearest 8 byte boundary. /// </summary> /// <param name="ba"></param> /// <param name="finalSize"></param> /// <returns></returns> private static ulong[] ByteArrayToULongArray(byte[] ba, int finalSize) { var minSize = ba.Length / 8; if (finalSize < minSize) finalSize = minSize; ba = PadULong(ba); var os = finalSize / 8; if (os * 8 < finalSize) os++; var result = new ulong[os]; for (var i = 0; i < ba.Length; i += 8) Buffer.BlockCopy(ba, i, result, i, 8); return result; } private static byte[] PadULong(byte[] ba) { var s = ba.Length % 8; switch (s) { case 0: break; case 1: Array.Resize(ref ba, ba.Length + 7); ba[ba.Length - 1] = 0x80; ba[ba.Length - 2] = 0x80; ba[ba.Length - 3] = 0x80; ba[ba.Length - 4] = 0x80; ba[ba.Length - 5] = 0x80; ba[ba.Length - 6] = 0x80; ba[ba.Length - 7] = 0x80; break; case 2: Array.Resize(ref ba, ba.Length + 6); ba[ba.Length - 1] = 0x80; ba[ba.Length - 2] = 0x80; ba[ba.Length - 3] = 0x80; ba[ba.Length - 4] = 0x80; ba[ba.Length - 5] = 0x80; ba[ba.Length - 6] = 0x80; break; case 3: Array.Resize(ref ba, ba.Length + 5); ba[ba.Length - 1] = 0x80; ba[ba.Length - 2] = 0x80; ba[ba.Length - 3] = 0x80; ba[ba.Length - 4] = 0x80; ba[ba.Length - 5] = 0x80; break; case 4: Array.Resize(ref ba, ba.Length + 4); ba[ba.Length - 1] = 0x80; ba[ba.Length - 2] = 0x80; ba[ba.Length - 3] = 0x80; ba[ba.Length - 4] = 0x80; break; case 5: Array.Resize(ref ba, ba.Length + 3); ba[ba.Length - 1] = 0x80; ba[ba.Length - 2] = 0x80; ba[ba.Length - 3] = 0x80; break; case 6: Array.Resize(ref ba, ba.Length + 2); ba[ba.Length - 1] = 0x80; ba[ba.Length - 2] = 0x80; break; case 7: Array.Resize(ref ba, ba.Length + 1); ba[ba.Length - 1] = 0x80; break; } return ba; } private static void Expand(ulong[] x, int iterations = 1) { var size = x.Length; for (var k = 0; k < iterations; ++k) for (var i = 0; i < size; ++i) { ulong n = 0; var j = 0; while (j < size) { n ^= x[j]; ++j; } x[i] = (n << 1) | (n >> 56); } } /// <summary> /// ExpandAndMixArray resizes the array by extrusion then mixes the array using a Sha3 one way hash /// </summary> /// <param name="ba">The buffer</param> /// <param name="size">The final desired size</param> /// <param name="iterations">The number of iterations to mix the final array</param> public byte[] ExpandAndMixArray(byte[] ba, int size, int iterations = 1000) { var ula = ByteArrayToULongArray(ba, size); Expand(ula, 1); var array = ula.GetBytes(); return Mix(array, iterations); } public ushort[] ExpandAndMixArray(ushort[] ba, int size, int iterations = 1000) { var bb = ba.GetBytes(); return ExpandAndMixArray(bb, size, iterations).ToUShortArray(); } public uint[] ExpandAndMixArray(uint[] ba, int size, int iterations = 1000) { var bb = ba.GetBytes(); return ExpandAndMixArray(bb, size, iterations).ToUIntArray(); } public ulong[] ExpandAndMixArray(ulong[] ba, int size, int iterations = 1000) { var bb = ba.GetBytes(); return ExpandAndMixArray(bb, size, iterations).ToULongArray(); } }