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; } } }