/**
* Novacoin classes library
* Copyright (C) 2015 Alex D. (balthazar.ad@gmail.com)
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
using System;
using System.Diagnostics.Contracts;
using System.Linq;
namespace Novacoin
{
public abstract class Hash : IEquatable, IComparable
{
///
/// Array of digest bytes.
///
protected byte[] _hashBytes;
///
/// Hash size, must be overriden
///
public abstract int hashSize
{
get;
}
///
/// Initializes an empty instance of the Hash class.
///
public Hash()
{
_hashBytes = new byte[hashSize];
}
///
/// Initializes a new instance of Hash class
///
/// Array of bytes
public Hash(byte[] bytes, int offset = 0)
{
if (bytes.Length - offset < hashSize)
{
throw new ArgumentException("You need to provide a sufficient amount of data to initialize new instance of hash object.");
}
_hashBytes = new byte[hashSize];
Array.Copy(bytes, offset, _hashBytes, 0, hashSize);
}
///
/// Initializes a new instance of Hash class as a copy of another one
///
/// Instance of hash class
public Hash(Hash h)
{
_hashBytes = new byte[h.hashSize];
h._hashBytes.CopyTo(_hashBytes, 0);
}
public bool IsZero
{
get { return !_hashBytes.Any(b => b != 0); }
}
public static implicit operator byte[](Hash h)
{
return h._hashBytes;
}
public bool Equals(Hash item)
{
if ((object)item == null)
{
return false;
}
return _hashBytes.SequenceEqual((byte[])item);
}
public override bool Equals(object o)
{
if (o == null)
{
return false;
}
return _hashBytes.SequenceEqual(((Hash)o)._hashBytes);
}
public override int GetHashCode()
{
int hash = 17;
unchecked
{
foreach (var element in _hashBytes)
{
hash = hash * 31 + element.GetHashCode();
}
}
return hash;
}
public int CompareTo(Hash item)
{
if (this > item)
{
return 1;
}
else if (this < item)
{
return -1;
}
return 0;
}
public static bool operator <(Hash a, Hash b)
{
Contract.Requires((object)a != null && (object)b != null, "Null references are not allowed.");
Contract.Requires(a.hashSize == b.hashSize, "Hashes must have the same size.");
for (int i = a.hashSize - 1; i >= 0; i--)
{
if (a._hashBytes[i] < b._hashBytes[i])
{
return true;
}
else if (a._hashBytes[i] > b._hashBytes[i])
{
return false;
}
}
return false;
}
public static bool operator <=(Hash a, Hash b)
{
Contract.Requires((object)a != null && (object)b != null, "Null references are not allowed.");
Contract.Requires(a.hashSize == b.hashSize, "Hashes must have the same size.");
for (int i = a.hashSize - 1; i >= 0; i--)
{
if (a._hashBytes[i] < b._hashBytes[i])
{
return true;
}
else if (a._hashBytes[i] > b._hashBytes[i])
{
return false;
}
}
return false;
}
public static bool operator >(Hash a, Hash b)
{
Contract.Requires((object)a != null && (object)b != null, "Null references are not allowed.");
Contract.Requires(a.hashSize == b.hashSize, "Hashes must have the same size.");
for (int i = a.hashSize - 1; i >= 0; i--)
{
if (a._hashBytes[i] > b._hashBytes[i])
{
return true;
}
else if (a._hashBytes[i] < b._hashBytes[i])
{
return false;
}
}
return false;
}
public static bool operator >=(Hash a, Hash b)
{
Contract.Requires((object)a != null && (object)b != null, "Null references are not allowed.");
Contract.Requires(a.hashSize == b.hashSize, "Hashes must have the same size.");
for (int i = a.hashSize - 1; i >= 0; i--)
{
if (a._hashBytes[i] > b._hashBytes[i])
{
return true;
}
else if (a._hashBytes[i] < b._hashBytes[i])
{
return false;
}
}
return true;
}
public static bool operator ==(Hash a, Hash b)
{
Contract.Requires((object)a != null && (object)b != null, "Null references are not allowed.");
Contract.Requires(a.hashSize == b.hashSize, "Hashes must have the same size.");
return a._hashBytes.SequenceEqual(b._hashBytes);
}
public static bool operator !=(Hash a, Hash b)
{
return !(a == b);
}
public override string ToString()
{
return Interop.ToHex(Interop.ReverseBytes(_hashBytes));
}
}
}