using System;
using System.Diagnostics;
using System.Text;
#pragma warning disable 03021
namespace Nethereum.Util.Keccak
{
internal class KeccakDigest
{
private static readonly ulong[] KeccakRoundConstants = KeccakInitializeRoundConstants();
private static readonly int[] KeccakRhoOffsets = KeccakInitializeRhoOffsets();
private static ulong[] KeccakInitializeRoundConstants()
{
ulong[] keccakRoundConstants = new ulong[24];
byte LFSRState = 0x01;
for (int i = 0; i < 24; i++)
{
keccakRoundConstants[i] = 0;
for (int j = 0; j < 7; j++)
{
int bitPosition = (1 << j) - 1;
// LFSR86540
bool loBit = (LFSRState & 0x01) != 0;
if (loBit)
{
keccakRoundConstants[i] ^= 1UL << bitPosition;
}
bool hiBit = (LFSRState & 0x80) != 0;
LFSRState <<= 1;
if (hiBit)
{
LFSRState ^= 0x71;
}
}
}
return keccakRoundConstants;
}
private static int[] KeccakInitializeRhoOffsets()
{
int[] keccakRhoOffsets = new int[25];
int x, y, t, newX, newY;
int rhoOffset = 0;
keccakRhoOffsets[0] = rhoOffset;
x = 1;
y = 0;
for (t = 1; t < 25; t++)
{
rhoOffset = (rhoOffset + t) & 63;
keccakRhoOffsets[(((x) % 5) + 5 * ((y) % 5))] = rhoOffset;
newX = (0 * x + 1 * y) % 5;
newY = (2 * x + 3 * y) % 5;
x = newX;
y = newY;
}
return keccakRhoOffsets;
}
private static readonly int STATE_LENGTH = (1600 / 8);
private ulong[] state = new ulong[STATE_LENGTH / 8];
protected byte[] dataQueue = new byte[1536 / 8];
protected int rate;
protected int bitsInQueue;
protected int fixedOutputLength;
protected bool squeezing;
protected int bitsAvailableForSqueezing;
public KeccakDigest()
: this(288)
{
}
public KeccakDigest(int bitLength)
{
Init(bitLength);
}
public KeccakDigest(KeccakDigest source)
{
CopyIn(source);
}
private void CopyIn(KeccakDigest source)
{
Array.Copy(source.state, 0, this.state, 0, source.state.Length);
Array.Copy(source.dataQueue, 0, this.dataQueue, 0, source.dataQueue.Length);
this.rate = source.rate;
this.bitsInQueue = source.bitsInQueue;
this.fixedOutputLength = source.fixedOutputLength;
this.squeezing = source.squeezing;
this.bitsAvailableForSqueezing = source.bitsAvailableForSqueezing;
}
public virtual string AlgorithmName
{
get { return "Keccak-" + fixedOutputLength; }
}
public virtual int GetDigestSize()
{
return fixedOutputLength >> 3;
}
public virtual void Update(byte input)
{
Absorb(new byte[] {input}, 0, 1);
}
public virtual void BlockUpdate(byte[] input, int inOff, int len)
{
Absorb(input, inOff, len);
}
public virtual int DoFinal(byte[] output, int outOff)
{
Squeeze(output, outOff, fixedOutputLength >> 3);
Reset();
return GetDigestSize();
}
/*
* TODO Possible API change to support partial-byte suffixes.
*/
protected virtual int DoFinal(byte[] output, int outOff, byte partialByte, int partialBits)
{
if (partialBits > 0)
{
AbsorbBits(partialByte, partialBits);
}
Squeeze(output, outOff, fixedOutputLength >> 3);
Reset();
return GetDigestSize();
}
public virtual void Reset()
{
Init(fixedOutputLength);
}
/**
* Return the size of block that the compression function is applied to in bytes.
*
* @return internal byte length of a block.
*/
public virtual int GetByteLength()
{
return rate >> 3;
}
private void Init(int bitLength)
{
switch (bitLength)
{
case 128:
case 224:
case 256:
case 288:
case 384:
case 512:
InitSponge(1600 - (bitLength << 1));
break;
default:
throw new ArgumentException("must be one of 128, 224, 256, 288, 384, or 512.", "bitLength");
}
}
private void InitSponge(int rate)
{
if (rate <= 0 || rate >= 1600 || (rate & 63) != 0)
throw new InvalidOperationException("invalid rate value");
this.rate = rate;
Array.Clear(state, 0, state.Length);
Arrays.Fill(this.dataQueue, (byte) 0);
this.bitsInQueue = 0;
this.squeezing = false;
this.bitsAvailableForSqueezing = 0;
this.fixedOutputLength = (1600 - rate) >> 1;
}
protected void Absorb(byte[] data, int off, int len)
{
if ((bitsInQueue & 7) != 0)
throw new InvalidOperationException("attempt to absorb with odd length queue");
if (squeezing)
throw new InvalidOperationException("attempt to absorb while squeezing");
int bytesInQueue = bitsInQueue >> 3;
int rateBytes = rate >> 3;
int count = 0;
while (count < len)
{
if (bytesInQueue == 0 && count <= (len - rateBytes))
{
do
{
KeccakAbsorb(data, off + count);
count += rateBytes;
} while (count <= (len - rateBytes));
}
else
{
int partialBlock = System.Math.Min(rateBytes - bytesInQueue, len - count);
Array.Copy(data, off + count, dataQueue, bytesInQueue, partialBlock);
bytesInQueue += partialBlock;
count += partialBlock;
if (bytesInQueue == rateBytes)
{
KeccakAbsorb(dataQueue, 0);
bytesInQueue = 0;
}
}
}
bitsInQueue = bytesInQueue << 3;
}
protected void AbsorbBits(int data, int bits)
{
if (bits < 1 || bits > 7)
throw new ArgumentException("must be in the range 1 to 7", "bits");
if ((bitsInQueue & 7) != 0)
throw new InvalidOperationException("attempt to absorb with odd length queue");
if (squeezing)
throw new InvalidOperationException("attempt to absorb while squeezing");
int mask = (1 << bits) - 1;
dataQueue[bitsInQueue >> 3] = (byte) (data & mask);
// NOTE: After this, bitsInQueue is no longer a multiple of 8, so no more absorbs will work
bitsInQueue += bits;
}
private void PadAndSwitchToSqueezingPhase()
{
Debug.Assert(bitsInQueue < rate);
dataQueue[bitsInQueue >> 3] |= (byte) (1U << (bitsInQueue & 7));
if (++bitsInQueue == rate)
{
KeccakAbsorb(dataQueue, 0);
bitsInQueue = 0;
}
{
int full = bitsInQueue >> 6, partial = bitsInQueue & 63;
int off = 0;
for (int i = 0; i < full; ++i)
{
state[i] ^= Pack.LE_To_UInt64(dataQueue, off);
off += 8;
}
if (partial > 0)
{
ulong mask = (1UL << partial) - 1UL;
state[full] ^= Pack.LE_To_UInt64(dataQueue, off) & mask;
}
state[(rate - 1) >> 6] ^= (1UL << 63);
}
KeccakPermutation();
KeccakExtract();
bitsAvailableForSqueezing = rate;
bitsInQueue = 0;
squeezing = true;
}
protected void Squeeze(byte[] output, int off, int len)
{
if (!squeezing)
{
PadAndSwitchToSqueezingPhase();
}
long outputLength = (long) len << 3;
long i = 0;
while (i < outputLength)
{
if (bitsAvailableForSqueezing == 0)
{
KeccakPermutation();
KeccakExtract();
bitsAvailableForSqueezing = rate;
}
int partialBlock = (int) System.Math.Min((long) bitsAvailableForSqueezing, outputLength - i);
Array.Copy(dataQueue, (rate - bitsAvailableForSqueezing) >> 3, output, off + (int) (i >> 3),
partialBlock >> 3);
bitsAvailableForSqueezing -= partialBlock;
i += partialBlock;
}
}
private void KeccakAbsorb(byte[] data, int off)
{
int count = rate >> 6;
for (int i = 0; i < count; ++i)
{
state[i] ^= Pack.LE_To_UInt64(data, off);
off += 8;
}
KeccakPermutation();
}
private void KeccakExtract()
{
Pack.UInt64_To_LE(state, 0, rate >> 6, dataQueue, 0);
}
private void KeccakPermutation()
{
for (int i = 0; i < 24; i++)
{
Theta(state);
Rho(state);
Pi(state);
Chi(state);
Iota(state, i);
}
}
private static ulong leftRotate(ulong v, int r)
{
return (v << r) | (v >> -r);
}
private static void Theta(ulong[] A)
{
ulong C0 = A[0 + 0] ^ A[0 + 5] ^ A[0 + 10] ^ A[0 + 15] ^ A[0 + 20];
ulong C1 = A[1 + 0] ^ A[1 + 5] ^ A[1 + 10] ^ A[1 + 15] ^ A[1 + 20];
ulong C2 = A[2 + 0] ^ A[2 + 5] ^ A[2 + 10] ^ A[2 + 15] ^ A[2 + 20];
ulong C3 = A[3 + 0] ^ A[3 + 5] ^ A[3 + 10] ^ A[3 + 15] ^ A[3 + 20];
ulong C4 = A[4 + 0] ^ A[4 + 5] ^ A[4 + 10] ^ A[4 + 15] ^ A[4 + 20];
ulong dX = leftRotate(C1, 1) ^ C4;
A[0] ^= dX;
A[5] ^= dX;
A[10] ^= dX;
A[15] ^= dX;
A[20] ^= dX;
dX = leftRotate(C2, 1) ^ C0;
A[1] ^= dX;
A[6] ^= dX;
A[11] ^= dX;
A[16] ^= dX;
A[21] ^= dX;
dX = leftRotate(C3, 1) ^ C1;
A[2] ^= dX;
A[7] ^= dX;
A[12] ^= dX;
A[17] ^= dX;
A[22] ^= dX;
dX = leftRotate(C4, 1) ^ C2;
A[3] ^= dX;
A[8] ^= dX;
A[13] ^= dX;
A[18] ^= dX;
A[23] ^= dX;
dX = leftRotate(C0, 1) ^ C3;
A[4] ^= dX;
A[9] ^= dX;
A[14] ^= dX;
A[19] ^= dX;
A[24] ^= dX;
}
private static void Rho(ulong[] A)
{
// KeccakRhoOffsets[0] == 0
for (int x = 1; x < 25; x++)
{
A[x] = leftRotate(A[x], KeccakRhoOffsets[x]);
}
}
private static void Pi(ulong[] A)
{
ulong a1 = A[1];
A[1] = A[6];
A[6] = A[9];
A[9] = A[22];
A[22] = A[14];
A[14] = A[20];
A[20] = A[2];
A[2] = A[12];
A[12] = A[13];
A[13] = A[19];
A[19] = A[23];
A[23] = A[15];
A[15] = A[4];
A[4] = A[24];
A[24] = A[21];
A[21] = A[8];
A[8] = A[16];
A[16] = A[5];
A[5] = A[3];
A[3] = A[18];
A[18] = A[17];
A[17] = A[11];
A[11] = A[7];
A[7] = A[10];
A[10] = a1;
}
private static void Chi(ulong[] A)
{
ulong chiC0, chiC1, chiC2, chiC3, chiC4;
for (int yBy5 = 0; yBy5 < 25; yBy5 += 5)
{
chiC0 = A[0 + yBy5] ^ ((~A[(((0 + 1) % 5) + yBy5)]) & A[(((0 + 2) % 5) + yBy5)]);
chiC1 = A[1 + yBy5] ^ ((~A[(((1 + 1) % 5) + yBy5)]) & A[(((1 + 2) % 5) + yBy5)]);
chiC2 = A[2 + yBy5] ^ ((~A[(((2 + 1) % 5) + yBy5)]) & A[(((2 + 2) % 5) + yBy5)]);
chiC3 = A[3 + yBy5] ^ ((~A[(((3 + 1) % 5) + yBy5)]) & A[(((3 + 2) % 5) + yBy5)]);
chiC4 = A[4 + yBy5] ^ ((~A[(((4 + 1) % 5) + yBy5)]) & A[(((4 + 2) % 5) + yBy5)]);
A[0 + yBy5] = chiC0;
A[1 + yBy5] = chiC1;
A[2 + yBy5] = chiC2;
A[3 + yBy5] = chiC3;
A[4 + yBy5] = chiC4;
}
}
private static void Iota(ulong[] A, int indexRound)
{
A[0] ^= KeccakRoundConstants[indexRound];
}
}
internal sealed class Pack
{
private Pack()
{
}
internal static void UInt16_To_BE(ushort n, byte[] bs)
{
bs[0] = (byte) (n >> 8);
bs[1] = (byte) (n);
}
internal static void UInt16_To_BE(ushort n, byte[] bs, int off)
{
bs[off] = (byte) (n >> 8);
bs[off + 1] = (byte) (n);
}
internal static ushort BE_To_UInt16(byte[] bs)
{
uint n = (uint) bs[0] << 8
| (uint) bs[1];
return (ushort) n;
}
internal static ushort BE_To_UInt16(byte[] bs, int off)
{
uint n = (uint) bs[off] << 8
| (uint) bs[off + 1];
return (ushort) n;
}
internal static byte[] UInt32_To_BE(uint n)
{
byte[] bs = new byte[4];
UInt32_To_BE(n, bs, 0);
return bs;
}
internal static void UInt32_To_BE(uint n, byte[] bs)
{
bs[0] = (byte) (n >> 24);
bs[1] = (byte) (n >> 16);
bs[2] = (byte) (n >> 8);
bs[3] = (byte) (n);
}
internal static void UInt32_To_BE(uint n, byte[] bs, int off)
{
bs[off] = (byte) (n >> 24);
bs[off + 1] = (byte) (n >> 16);
bs[off + 2] = (byte) (n >> 8);
bs[off + 3] = (byte) (n);
}
internal static byte[] UInt32_To_BE(uint[] ns)
{
byte[] bs = new byte[4 * ns.Length];
UInt32_To_BE(ns, bs, 0);
return bs;
}
internal static void UInt32_To_BE(uint[] ns, byte[] bs, int off)
{
for (int i = 0; i < ns.Length; ++i)
{
UInt32_To_BE(ns[i], bs, off);
off += 4;
}
}
internal static uint BE_To_UInt32(byte[] bs)
{
return (uint) bs[0] << 24
| (uint) bs[1] << 16
| (uint) bs[2] << 8
| (uint) bs[3];
}
internal static uint BE_To_UInt32(byte[] bs, int off)
{
return (uint) bs[off] << 24
| (uint) bs[off + 1] << 16
| (uint) bs[off + 2] << 8
| (uint) bs[off + 3];
}
internal static void BE_To_UInt32(byte[] bs, int off, uint[] ns)
{
for (int i = 0; i < ns.Length; ++i)
{
ns[i] = BE_To_UInt32(bs, off);
off += 4;
}
}
internal static byte[] UInt64_To_BE(ulong n)
{
byte[] bs = new byte[8];
UInt64_To_BE(n, bs, 0);
return bs;
}
internal static void UInt64_To_BE(ulong n, byte[] bs)
{
UInt32_To_BE((uint) (n >> 32), bs);
UInt32_To_BE((uint) (n), bs, 4);
}
internal static void UInt64_To_BE(ulong n, byte[] bs, int off)
{
UInt32_To_BE((uint) (n >> 32), bs, off);
UInt32_To_BE((uint) (n), bs, off + 4);
}
internal static byte[] UInt64_To_BE(ulong[] ns)
{
byte[] bs = new byte[8 * ns.Length];
UInt64_To_BE(ns, bs, 0);
return bs;
}
internal static void UInt64_To_BE(ulong[] ns, byte[] bs, int off)
{
for (int i = 0; i < ns.Length; ++i)
{
UInt64_To_BE(ns[i], bs, off);
off += 8;
}
}
internal static ulong BE_To_UInt64(byte[] bs)
{
uint hi = BE_To_UInt32(bs);
uint lo = BE_To_UInt32(bs, 4);
return ((ulong) hi << 32) | (ulong) lo;
}
internal static ulong BE_To_UInt64(byte[] bs, int off)
{
uint hi = BE_To_UInt32(bs, off);
uint lo = BE_To_UInt32(bs, off + 4);
return ((ulong) hi << 32) | (ulong) lo;
}
internal static void BE_To_UInt64(byte[] bs, int off, ulong[] ns)
{
for (int i = 0; i < ns.Length; ++i)
{
ns[i] = BE_To_UInt64(bs, off);
off += 8;
}
}
internal static void UInt16_To_LE(ushort n, byte[] bs)
{
bs[0] = (byte) (n);
bs[1] = (byte) (n >> 8);
}
internal static void UInt16_To_LE(ushort n, byte[] bs, int off)
{
bs[off] = (byte) (n);
bs[off + 1] = (byte) (n >> 8);
}
internal static ushort LE_To_UInt16(byte[] bs)
{
uint n = (uint) bs[0]
| (uint) bs[1] << 8;
return (ushort) n;
}
internal static ushort LE_To_UInt16(byte[] bs, int off)
{
uint n = (uint) bs[off]
| (uint) bs[off + 1] << 8;
return (ushort) n;
}
internal static byte[] UInt32_To_LE(uint n)
{
byte[] bs = new byte[4];
UInt32_To_LE(n, bs, 0);
return bs;
}
internal static void UInt32_To_LE(uint n, byte[] bs)
{
bs[0] = (byte) (n);
bs[1] = (byte) (n >> 8);
bs[2] = (byte) (n >> 16);
bs[3] = (byte) (n >> 24);
}
internal static void UInt32_To_LE(uint n, byte[] bs, int off)
{
bs[off] = (byte) (n);
bs[off + 1] = (byte) (n >> 8);
bs[off + 2] = (byte) (n >> 16);
bs[off + 3] = (byte) (n >> 24);
}
internal static byte[] UInt32_To_LE(uint[] ns)
{
byte[] bs = new byte[4 * ns.Length];
UInt32_To_LE(ns, bs, 0);
return bs;
}
internal static void UInt32_To_LE(uint[] ns, byte[] bs, int off)
{
for (int i = 0; i < ns.Length; ++i)
{
UInt32_To_LE(ns[i], bs, off);
off += 4;
}
}
internal static uint LE_To_UInt32(byte[] bs)
{
return (uint) bs[0]
| (uint) bs[1] << 8
| (uint) bs[2] << 16
| (uint) bs[3] << 24;
}
internal static uint LE_To_UInt32(byte[] bs, int off)
{
return (uint) bs[off]
| (uint) bs[off + 1] << 8
| (uint) bs[off + 2] << 16
| (uint) bs[off + 3] << 24;
}
internal static void LE_To_UInt32(byte[] bs, int off, uint[] ns)
{
for (int i = 0; i < ns.Length; ++i)
{
ns[i] = LE_To_UInt32(bs, off);
off += 4;
}
}
internal static void LE_To_UInt32(byte[] bs, int bOff, uint[] ns, int nOff, int count)
{
for (int i = 0; i < count; ++i)
{
ns[nOff + i] = LE_To_UInt32(bs, bOff);
bOff += 4;
}
}
internal static uint[] LE_To_UInt32(byte[] bs, int off, int count)
{
uint[] ns = new uint[count];
for (int i = 0; i < ns.Length; ++i)
{
ns[i] = LE_To_UInt32(bs, off);
off += 4;
}
return ns;
}
internal static byte[] UInt64_To_LE(ulong n)
{
byte[] bs = new byte[8];
UInt64_To_LE(n, bs, 0);
return bs;
}
internal static void UInt64_To_LE(ulong n, byte[] bs)
{
UInt32_To_LE((uint) (n), bs);
UInt32_To_LE((uint) (n >> 32), bs, 4);
}
internal static void UInt64_To_LE(ulong n, byte[] bs, int off)
{
UInt32_To_LE((uint) (n), bs, off);
UInt32_To_LE((uint) (n >> 32), bs, off + 4);
}
internal static byte[] UInt64_To_LE(ulong[] ns)
{
byte[] bs = new byte[8 * ns.Length];
UInt64_To_LE(ns, bs, 0);
return bs;
}
internal static void UInt64_To_LE(ulong[] ns, byte[] bs, int off)
{
for (int i = 0; i < ns.Length; ++i)
{
UInt64_To_LE(ns[i], bs, off);
off += 8;
}
}
internal static void UInt64_To_LE(ulong[] ns, int nsOff, int nsLen, byte[] bs, int bsOff)
{
for (int i = 0; i < nsLen; ++i)
{
UInt64_To_LE(ns[nsOff + i], bs, bsOff);
bsOff += 8;
}
}
internal static ulong LE_To_UInt64(byte[] bs)
{
uint lo = LE_To_UInt32(bs);
uint hi = LE_To_UInt32(bs, 4);
return ((ulong) hi << 32) | (ulong) lo;
}
internal static ulong LE_To_UInt64(byte[] bs, int off)
{
uint lo = LE_To_UInt32(bs, off);
uint hi = LE_To_UInt32(bs, off + 4);
return ((ulong) hi << 32) | (ulong) lo;
}
internal static void LE_To_UInt64(byte[] bs, int off, ulong[] ns)
{
for (int i = 0; i < ns.Length; ++i)
{
ns[i] = LE_To_UInt64(bs, off);
off += 8;
}
}
internal static void LE_To_UInt64(byte[] bs, int bsOff, ulong[] ns, int nsOff, int nsLen)
{
for (int i = 0; i < nsLen; ++i)
{
ns[nsOff + i] = LE_To_UInt64(bs, bsOff);
bsOff += 8;
}
}
}
/// General array utilities.
internal abstract class Arrays
{
public static bool AreEqual(
bool[] a,
bool[] b)
{
if (a == b)
return true;
if (a == null || b == null)
return false;
return HaveSameContents(a, b);
}
public static bool AreEqual(
char[] a,
char[] b)
{
if (a == b)
return true;
if (a == null || b == null)
return false;
return HaveSameContents(a, b);
}
///
/// Are two arrays equal.
///
/// Left side.
/// Right side.
/// True if equal.
public static bool AreEqual(
byte[] a,
byte[] b)
{
if (a == b)
return true;
if (a == null || b == null)
return false;
return HaveSameContents(a, b);
}
[Obsolete("Use 'AreEqual' method instead")]
public static bool AreSame(
byte[] a,
byte[] b)
{
return AreEqual(a, b);
}
///
/// A constant time equals comparison - does not terminate early if
/// test will fail.
///
/// first array
/// second array
/// true if arrays equal, false otherwise.
public static bool ConstantTimeAreEqual(
byte[] a,
byte[] b)
{
int i = a.Length;
if (i != b.Length)
return false;
int cmp = 0;
while (i != 0)
{
--i;
cmp |= (a[i] ^ b[i]);
}
return cmp == 0;
}
public static bool AreEqual(
int[] a,
int[] b)
{
if (a == b)
return true;
if (a == null || b == null)
return false;
return HaveSameContents(a, b);
}
public static bool AreEqual(uint[] a, uint[] b)
{
if (a == b)
return true;
if (a == null || b == null)
return false;
return HaveSameContents(a, b);
}
private static bool HaveSameContents(
bool[] a,
bool[] b)
{
int i = a.Length;
if (i != b.Length)
return false;
while (i != 0)
{
--i;
if (a[i] != b[i])
return false;
}
return true;
}
private static bool HaveSameContents(
char[] a,
char[] b)
{
int i = a.Length;
if (i != b.Length)
return false;
while (i != 0)
{
--i;
if (a[i] != b[i])
return false;
}
return true;
}
private static bool HaveSameContents(
byte[] a,
byte[] b)
{
int i = a.Length;
if (i != b.Length)
return false;
while (i != 0)
{
--i;
if (a[i] != b[i])
return false;
}
return true;
}
private static bool HaveSameContents(
int[] a,
int[] b)
{
int i = a.Length;
if (i != b.Length)
return false;
while (i != 0)
{
--i;
if (a[i] != b[i])
return false;
}
return true;
}
private static bool HaveSameContents(uint[] a, uint[] b)
{
int i = a.Length;
if (i != b.Length)
return false;
while (i != 0)
{
--i;
if (a[i] != b[i])
return false;
}
return true;
}
public static string ToString(
object[] a)
{
StringBuilder sb = new StringBuilder('[');
if (a.Length > 0)
{
sb.Append(a[0]);
for (int index = 1; index < a.Length; ++index)
{
sb.Append(", ").Append(a[index]);
}
}
sb.Append(']');
return sb.ToString();
}
public static int GetHashCode(byte[] data)
{
if (data == null)
{
return 0;
}
int i = data.Length;
int hc = i + 1;
while (--i >= 0)
{
hc *= 257;
hc ^= data[i];
}
return hc;
}
public static int GetHashCode(byte[] data, int off, int len)
{
if (data == null)
{
return 0;
}
int i = len;
int hc = i + 1;
while (--i >= 0)
{
hc *= 257;
hc ^= data[off + i];
}
return hc;
}
public static int GetHashCode(int[] data)
{
if (data == null)
return 0;
int i = data.Length;
int hc = i + 1;
while (--i >= 0)
{
hc *= 257;
hc ^= data[i];
}
return hc;
}
public static int GetHashCode(int[] data, int off, int len)
{
if (data == null)
return 0;
int i = len;
int hc = i + 1;
while (--i >= 0)
{
hc *= 257;
hc ^= data[off + i];
}
return hc;
}
[CLSCompliantAttribute(false)]
public static int GetHashCode(uint[] data)
{
if (data == null)
return 0;
int i = data.Length;
int hc = i + 1;
while (--i >= 0)
{
hc *= 257;
hc ^= (int) data[i];
}
return hc;
}
[CLSCompliantAttribute(false)]
public static int GetHashCode(uint[] data, int off, int len)
{
if (data == null)
return 0;
int i = len;
int hc = i + 1;
while (--i >= 0)
{
hc *= 257;
hc ^= (int) data[off + i];
}
return hc;
}
[CLSCompliantAttribute(false)]
public static int GetHashCode(ulong[] data)
{
if (data == null)
return 0;
int i = data.Length;
int hc = i + 1;
while (--i >= 0)
{
ulong di = data[i];
hc *= 257;
hc ^= (int) di;
hc *= 257;
hc ^= (int) (di >> 32);
}
return hc;
}
[CLSCompliantAttribute(false)]
public static int GetHashCode(ulong[] data, int off, int len)
{
if (data == null)
return 0;
int i = len;
int hc = i + 1;
while (--i >= 0)
{
ulong di = data[off + i];
hc *= 257;
hc ^= (int) di;
hc *= 257;
hc ^= (int) (di >> 32);
}
return hc;
}
public static byte[] Clone(
byte[] data)
{
return data == null ? null : (byte[]) data.Clone();
}
public static byte[] Clone(
byte[] data,
byte[] existing)
{
if (data == null)
{
return null;
}
if ((existing == null) || (existing.Length != data.Length))
{
return Clone(data);
}
Array.Copy(data, 0, existing, 0, existing.Length);
return existing;
}
public static int[] Clone(
int[] data)
{
return data == null ? null : (int[]) data.Clone();
}
internal static uint[] Clone(uint[] data)
{
return data == null ? null : (uint[]) data.Clone();
}
public static long[] Clone(long[] data)
{
return data == null ? null : (long[]) data.Clone();
}
[CLSCompliantAttribute(false)]
public static ulong[] Clone(
ulong[] data)
{
return data == null ? null : (ulong[]) data.Clone();
}
[CLSCompliantAttribute(false)]
public static ulong[] Clone(
ulong[] data,
ulong[] existing)
{
if (data == null)
{
return null;
}
if ((existing == null) || (existing.Length != data.Length))
{
return Clone(data);
}
Array.Copy(data, 0, existing, 0, existing.Length);
return existing;
}
public static bool Contains(byte[] a, byte n)
{
for (int i = 0; i < a.Length; ++i)
{
if (a[i] == n)
return true;
}
return false;
}
public static bool Contains(short[] a, short n)
{
for (int i = 0; i < a.Length; ++i)
{
if (a[i] == n)
return true;
}
return false;
}
public static bool Contains(int[] a, int n)
{
for (int i = 0; i < a.Length; ++i)
{
if (a[i] == n)
return true;
}
return false;
}
public static void Fill(
byte[] buf,
byte b)
{
int i = buf.Length;
while (i > 0)
{
buf[--i] = b;
}
}
public static byte[] CopyOf(byte[] data, int newLength)
{
byte[] tmp = new byte[newLength];
Array.Copy(data, 0, tmp, 0, System.Math.Min(newLength, data.Length));
return tmp;
}
public static char[] CopyOf(char[] data, int newLength)
{
char[] tmp = new char[newLength];
Array.Copy(data, 0, tmp, 0, System.Math.Min(newLength, data.Length));
return tmp;
}
public static int[] CopyOf(int[] data, int newLength)
{
int[] tmp = new int[newLength];
Array.Copy(data, 0, tmp, 0, System.Math.Min(newLength, data.Length));
return tmp;
}
public static long[] CopyOf(long[] data, int newLength)
{
long[] tmp = new long[newLength];
Array.Copy(data, 0, tmp, 0, System.Math.Min(newLength, data.Length));
return tmp;
}
/**
* Make a copy of a range of bytes from the passed in data array. The range can
* extend beyond the end of the input array, in which case the return array will
* be padded with zeroes.
*
* @param data the array from which the data is to be copied.
* @param from the start index at which the copying should take place.
* @param to the final index of the range (exclusive).
*
* @return a new byte array containing the range given.
*/
public static byte[] CopyOfRange(byte[] data, int from, int to)
{
int newLength = GetLength(from, to);
byte[] tmp = new byte[newLength];
Array.Copy(data, from, tmp, 0, System.Math.Min(newLength, data.Length - from));
return tmp;
}
public static int[] CopyOfRange(int[] data, int from, int to)
{
int newLength = GetLength(from, to);
int[] tmp = new int[newLength];
Array.Copy(data, from, tmp, 0, System.Math.Min(newLength, data.Length - from));
return tmp;
}
public static long[] CopyOfRange(long[] data, int from, int to)
{
int newLength = GetLength(from, to);
long[] tmp = new long[newLength];
Array.Copy(data, from, tmp, 0, System.Math.Min(newLength, data.Length - from));
return tmp;
}
private static int GetLength(int from, int to)
{
int newLength = to - from;
if (newLength < 0)
throw new ArgumentException(from + " > " + to);
return newLength;
}
public static byte[] Append(byte[] a, byte b)
{
if (a == null)
return new byte[] {b};
int length = a.Length;
byte[] result = new byte[length + 1];
Array.Copy(a, 0, result, 0, length);
result[length] = b;
return result;
}
public static short[] Append(short[] a, short b)
{
if (a == null)
return new short[] {b};
int length = a.Length;
short[] result = new short[length + 1];
Array.Copy(a, 0, result, 0, length);
result[length] = b;
return result;
}
public static int[] Append(int[] a, int b)
{
if (a == null)
return new int[] {b};
int length = a.Length;
int[] result = new int[length + 1];
Array.Copy(a, 0, result, 0, length);
result[length] = b;
return result;
}
public static byte[] Concatenate(byte[] a, byte[] b)
{
if (a == null)
return Clone(b);
if (b == null)
return Clone(a);
byte[] rv = new byte[a.Length + b.Length];
Array.Copy(a, 0, rv, 0, a.Length);
Array.Copy(b, 0, rv, a.Length, b.Length);
return rv;
}
public static byte[] ConcatenateAll(params byte[][] vs)
{
byte[][] nonNull = new byte[vs.Length][];
int count = 0;
int totalLength = 0;
for (int i = 0; i < vs.Length; ++i)
{
byte[] v = vs[i];
if (v != null)
{
nonNull[count++] = v;
totalLength += v.Length;
}
}
byte[] result = new byte[totalLength];
int pos = 0;
for (int j = 0; j < count; ++j)
{
byte[] v = nonNull[j];
Array.Copy(v, 0, result, pos, v.Length);
pos += v.Length;
}
return result;
}
public static int[] Concatenate(int[] a, int[] b)
{
if (a == null)
return Clone(b);
if (b == null)
return Clone(a);
int[] rv = new int[a.Length + b.Length];
Array.Copy(a, 0, rv, 0, a.Length);
Array.Copy(b, 0, rv, a.Length, b.Length);
return rv;
}
public static byte[] Prepend(byte[] a, byte b)
{
if (a == null)
return new byte[] {b};
int length = a.Length;
byte[] result = new byte[length + 1];
Array.Copy(a, 0, result, 1, length);
result[0] = b;
return result;
}
public static short[] Prepend(short[] a, short b)
{
if (a == null)
return new short[] {b};
int length = a.Length;
short[] result = new short[length + 1];
Array.Copy(a, 0, result, 1, length);
result[0] = b;
return result;
}
public static int[] Prepend(int[] a, int b)
{
if (a == null)
return new int[] {b};
int length = a.Length;
int[] result = new int[length + 1];
Array.Copy(a, 0, result, 1, length);
result[0] = b;
return result;
}
public static byte[] Reverse(byte[] a)
{
if (a == null)
return null;
int p1 = 0, p2 = a.Length;
byte[] result = new byte[p2];
while (--p2 >= 0)
{
result[p2] = a[p1++];
}
return result;
}
public static int[] Reverse(int[] a)
{
if (a == null)
return null;
int p1 = 0, p2 = a.Length;
int[] result = new int[p2];
while (--p2 >= 0)
{
result[p2] = a[p1++];
}
return result;
}
}
}