From 1ad33d77c24d57f7ac25e0d6cf5f430464cdb058 Mon Sep 17 00:00:00 2001 From: CryptoManiac Date: Tue, 1 Sep 2015 21:52:39 +0300 Subject: [PATCH] Complete implementation of uint256 and uint160 classes. --- Novacoin/Interop.cs | 26 ++++++ Novacoin/ScryptHash256.cs | 31 +------- Novacoin/base_uint.cs | 119 ++++------------------------ Novacoin/uint160.cs | 197 ++++++++++++++++++++++++++++++++++++++++++++ Novacoin/uint256.cs | 198 +++++++++++++++++++++++++++++++++++++++++++++ NovacoinTest/Program.cs | 31 +++++++- 6 files changed, 466 insertions(+), 136 deletions(-) diff --git a/Novacoin/Interop.cs b/Novacoin/Interop.cs index f4c1e2e..0cb7e75 100644 --- a/Novacoin/Interop.cs +++ b/Novacoin/Interop.cs @@ -28,6 +28,32 @@ namespace Novacoin public class Interop { /// + /// Convert array of unsigned integers to array of bytes. + /// + /// Array of unsigned integer values. + /// Byte array + public static byte[] LEBytes(uint[] values) + { + var result = new byte[values.Length * sizeof(uint)]; + Buffer.BlockCopy(values, 0, result, 0, result.Length); + + return result; + } + + /// + /// Convert byte array to array of unsigned integers. + /// + /// Byte array. + /// Array of integers + public static uint[] ToUInt32Array(byte[] bytes) + { + var result = new uint[bytes.Length / sizeof(uint)]; + Buffer.BlockCopy(bytes, 0, result, 0, bytes.Length); + + return result; + } + + /// /// Reverse byte array /// /// Source array diff --git a/Novacoin/ScryptHash256.cs b/Novacoin/ScryptHash256.cs index cb39dd8..4f95926 100644 --- a/Novacoin/ScryptHash256.cs +++ b/Novacoin/ScryptHash256.cs @@ -45,7 +45,7 @@ namespace Novacoin var V = new uint[(131072 + 63) / sizeof(uint)]; var keyBytes1 = CryptoUtils.PBKDF2_Sha256(128, (byte[])inputBytes, (byte[])inputBytes, 1); - var X = ToUInt32Array(keyBytes1); + var X = Interop.ToUInt32Array(keyBytes1); for (var i = 0; i < 1024; i++) { @@ -65,7 +65,7 @@ namespace Novacoin xor_salsa8(ref X, 16, ref X, 0); } - var xBytes = LEBytes(X); + var xBytes = Interop.LEBytes(X); var keyBytes2 = CryptoUtils.PBKDF2_Sha256(32, (byte[])inputBytes, xBytes, 1); return new ScryptHash256(keyBytes2); @@ -141,32 +141,5 @@ namespace Novacoin B[indexB + 14] += x14; B[indexB + 15] += x15; } - - /// - /// Convert array of unsigned integers to array of bytes. - /// - /// Array of unsigned integer values. - /// Byte array - private static byte[] LEBytes(uint[] values) - { - var result = new byte[values.Length * sizeof(uint)]; - Buffer.BlockCopy(values, 0, result, 0, result.Length); - - return result; - } - - /// - /// Convert byte array to array of unsigned integers. - /// - /// Byte array. - /// Array of integers - private static uint[] ToUInt32Array(byte[] bytes) - { - var result = new uint[bytes.Length / sizeof(uint)]; - Buffer.BlockCopy(bytes, 0, result, 0, bytes.Length); - - return result; - } - } } diff --git a/Novacoin/base_uint.cs b/Novacoin/base_uint.cs index b7eb7f9..3ec7d7b 100644 --- a/Novacoin/base_uint.cs +++ b/Novacoin/base_uint.cs @@ -18,12 +18,16 @@ using System; +using System.Diagnostics.Contracts; namespace Novacoin { + /// + /// Base class for uint256 and uint160. + /// public class base_uint : IComparable, IEquatable { - protected int nWidth; + protected readonly int nWidth; protected uint[] pn; public double getDouble() @@ -58,7 +62,6 @@ namespace Novacoin } } - public static bool operator !(base_uint a) { for (int i = 0; i < a.nWidth; i++) @@ -71,98 +74,6 @@ namespace Novacoin return true; } - public static base_uint operator ~(base_uint a) - { - var ret = new base_uint(); - for (int i = 0; i < a.nWidth; i++) - { - ret.pn[i] = ~a.pn[i]; - } - return ret; - } - - public static base_uint operator -(base_uint a) - { - var ret = new base_uint(); - for (int i = 0; i < a.nWidth; i++) - { - ret.pn[i] = ~a.pn[i]; - } - ret++; - return ret; - } - - - public static base_uint operator ++(base_uint a) - { - int i = 0; - while (++a.pn[i] == 0 && i < a.nWidth - 1) - { - i++; - } - return a; - } - - public static base_uint operator --(base_uint a) - { - int i = 0; - while (--a.pn[i] == uint.MaxValue && i < a.nWidth - 1) - { - i++; - } - return a; - } - - public static base_uint operator ^(base_uint a, base_uint b) - { - var result = new base_uint(); - result.pn = new uint[a.nWidth]; - for (int i = 0; i < result.nWidth; i++) - { - result.pn[i] = a.pn[i] ^ b.pn[i]; - } - return result; - } - - public static base_uint operator +(base_uint a, base_uint b) - { - var result = new base_uint(); - ulong carry = 0; - for (int i = 0; i < result.nWidth; i++) - { - ulong n = carry + a.pn[i] + b.pn[i]; - result.pn[i] = (uint)(n & 0xffffffff); - carry = n >> 32; - } - return result; - } - - public static base_uint operator -(base_uint a, base_uint b) - { - return a + (-b); - } - - public static base_uint operator &(base_uint a, base_uint b) - { - var result = new base_uint(); - result.pn = new uint[a.nWidth]; - for (int i = 0; i < result.nWidth; i++) - { - result.pn[i] = a.pn[i] & b.pn[i]; - } - return result; - } - - public static base_uint operator |(base_uint a, base_uint b) - { - var result = new base_uint(); - result.pn = new uint[a.nWidth]; - for (int i = 0; i < result.nWidth; i++) - { - result.pn[i] = a.pn[i] | b.pn[i]; - } - return result; - } public static bool operator <(base_uint a, base_uint b) { @@ -251,10 +162,12 @@ namespace Novacoin { return false; } + if (a.pn[1] != (uint)(b >> 32)) { return false; } + for (int i = 2; i < a.nWidth; i++) { if (a.pn[i] != 0) @@ -287,20 +200,13 @@ namespace Novacoin public static implicit operator byte[] (base_uint a) { - var result = new byte[a.nWidth]; - for (int i = 0; i < a.nWidth; i++) - { - Buffer.BlockCopy(BitConverter.GetBytes(a.pn[i]), 0, result, 4 * i, 4); - } - return result; + return Interop.LEBytes(a.pn); } private static bool ArraysEqual(uint[] a, uint[] b) { - if (a.Length != b.Length) - { - return false; - } + Contract.Requires(a.Length == b.Length, "Array length mismatch."); + for (int i = 0; i < a.Length; i++) { if (a[i] != b[i]) @@ -352,5 +258,10 @@ namespace Novacoin { return Equals(o as base_uint); } + + public override string ToString() + { + return Interop.ToHex(Interop.ReverseBytes(this)); + } } } diff --git a/Novacoin/uint160.cs b/Novacoin/uint160.cs index 26e1dd9..9a89c3d 100644 --- a/Novacoin/uint160.cs +++ b/Novacoin/uint160.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics.Contracts; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -8,5 +9,201 @@ namespace Novacoin { public class uint160 : base_uint { + new protected readonly int nWidth = 5; + + public uint160() + { + pn = new uint[nWidth]; + + for (int i = 0; i < nWidth; i++) + { + pn[i] = 0; + } + } + + public uint160(uint160 b) + { + pn = new uint[nWidth]; + + for (int i = 0; i < nWidth; i++) + { + pn[i] = b.pn[i]; + } + } + + + public uint160(ulong n) + { + pn = new uint[nWidth]; + + pn[0] = (uint)n; + pn[1] = (uint)(n >> 32); + for (int i = 2; i < nWidth; i++) + { + pn[i] = 0; + } + } + + public uint160(byte[] bytes) + { + Contract.Requires(bytes.Length == 20, "Incorrect array length"); + + pn = Interop.ToUInt32Array(bytes); + } + + public uint160(string hex) + { + Contract.Requires(hex.Length == 40, "Incorrect string"); + + var bytes = Interop.ReverseBytes(Interop.HexToArray(hex)); + pn = Interop.ToUInt32Array(bytes); + } + + public static uint160 operator ~(uint160 a) + { + var ret = new uint160(); + for (int i = 0; i < a.nWidth; i++) + { + ret.pn[i] = ~a.pn[i]; + } + return ret; + } + + public static uint160 operator -(uint160 a) + { + var ret = new uint160(); + for (int i = 0; i < a.nWidth; i++) + { + ret.pn[i] = ~a.pn[i]; + } + ret++; + return ret; + } + + + public static uint160 operator ++(uint160 a) + { + int i = 0; + while (++a.pn[i] == 0 && i < a.nWidth - 1) + { + i++; + } + return a; + } + + public static uint160 operator --(uint160 a) + { + int i = 0; + while (--a.pn[i] == uint.MaxValue && i < a.nWidth - 1) + { + i++; + } + return a; + } + + public static uint160 operator ^(uint160 a, uint160 b) + { + var result = new uint160(); + result.pn = new uint[a.nWidth]; + for (int i = 0; i < result.nWidth; i++) + { + result.pn[i] = a.pn[i] ^ b.pn[i]; + } + return result; + } + + public static uint160 operator +(uint160 a, uint160 b) + { + var result = new uint160(); + ulong carry = 0; + for (int i = 0; i < result.nWidth; i++) + { + ulong n = carry + a.pn[i] + b.pn[i]; + result.pn[i] = (uint)(n & 0xffffffff); + carry = n >> 32; + } + return result; + } + + public static uint160 operator +(uint160 a, ulong b) + { + return a + new uint160(b); + } + + public static uint160 operator -(uint160 a, uint160 b) + { + return a + (-b); + } + + public static uint160 operator -(uint160 a, ulong b) + { + return a - new uint160(b); + } + + public static uint160 operator &(uint160 a, uint160 b) + { + var result = new uint160(); + result.pn = new uint[a.nWidth]; + for (int i = 0; i < result.nWidth; i++) + { + result.pn[i] = a.pn[i] & b.pn[i]; + } + return result; + } + + public static uint160 operator |(uint160 a, uint160 b) + { + var result = new uint160(); + result.pn = new uint[a.nWidth]; + for (int i = 0; i < result.nWidth; i++) + { + result.pn[i] = a.pn[i] | b.pn[i]; + } + return result; + } + + public static uint160 operator <<(uint160 a, int shift) + { + var result = new uint160(); + int k = shift / 32; + shift = shift % 32; + + for (int i = 0; i < a.nWidth; i++) + { + if (i + k + 1 < a.nWidth && shift != 0) + { + result.pn[i + k + 1] |= (a.pn[i] >> (32 - shift)); + } + + if (i + k < a.nWidth) + { + result.pn[i + k] |= (a.pn[i] << shift); + } + } + + return result; + } + + public static uint160 operator >>(uint160 a, int shift) + { + var result = new uint160(); + int k = shift / 32; + shift = shift % 32; + + for (int i = 0; i < a.nWidth; i++) + { + if (i - k - 1 >= 0 && shift != 0) + { + result.pn[i - k - 1] |= (a.pn[i] << (32 - shift)); + } + + if (i - k >= 0) + { + result.pn[i - k] |= (a.pn[i] >> shift); + } + } + + return result; + } } } diff --git a/Novacoin/uint256.cs b/Novacoin/uint256.cs index 8ce6b97..15a9931 100644 --- a/Novacoin/uint256.cs +++ b/Novacoin/uint256.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics.Contracts; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -8,5 +9,202 @@ namespace Novacoin { public class uint256 : base_uint { + new public readonly int nWidth = 8; + + public uint256() + { + pn = new uint[nWidth]; + + for (int i = 0; i < nWidth; i++) + { + pn[i] = 0; + } + } + + public uint256(uint256 b) + { + pn = new uint[nWidth]; + + for (int i = 0; i < nWidth; i++) + { + pn[i] = b.pn[i]; + } + } + + + public uint256(ulong n) + { + pn = new uint[nWidth]; + + pn[0] = (uint)n; + pn[1] = (uint)(n >> 32); + for (int i = 2; i < nWidth; i++) + { + pn[i] = 0; + } + } + + public uint256(byte[] bytes) + { + Contract.Requires(bytes.Length == 32, "Incorrect array length"); + + pn = Interop.ToUInt32Array(bytes); + } + + public uint256(string hex) + { + Contract.Requires(hex.Length == 64, "Incorrect string"); + + var bytes = Interop.ReverseBytes(Interop.HexToArray(hex)); + pn = Interop.ToUInt32Array(bytes); + } + + + public static uint256 operator ~(uint256 a) + { + var ret = new uint256(); + for (int i = 0; i < a.nWidth; i++) + { + ret.pn[i] = ~a.pn[i]; + } + return ret; + } + + public static uint256 operator -(uint256 a) + { + var ret = new uint256(); + for (int i = 0; i < a.nWidth; i++) + { + ret.pn[i] = ~a.pn[i]; + } + ret++; + return ret; + } + + + public static uint256 operator ++(uint256 a) + { + int i = 0; + while (++a.pn[i] == 0 && i < a.nWidth - 1) + { + i++; + } + return a; + } + + public static uint256 operator --(uint256 a) + { + int i = 0; + while (--a.pn[i] == uint.MaxValue && i < a.nWidth - 1) + { + i++; + } + return a; + } + + public static uint256 operator ^(uint256 a, uint256 b) + { + var result = new uint256(); + result.pn = new uint[a.nWidth]; + for (int i = 0; i < result.nWidth; i++) + { + result.pn[i] = a.pn[i] ^ b.pn[i]; + } + return result; + } + + public static uint256 operator +(uint256 a, uint256 b) + { + var result = new uint256(); + ulong carry = 0; + for (int i = 0; i < result.nWidth; i++) + { + ulong n = carry + a.pn[i] + b.pn[i]; + result.pn[i] = (uint)(n & 0xffffffff); + carry = n >> 32; + } + return result; + } + + public static uint256 operator +(uint256 a, ulong b) + { + return a + new uint256(b); + } + + public static uint256 operator -(uint256 a, uint256 b) + { + return a + (-b); + } + + public static uint256 operator -(uint256 a, ulong b) + { + return a - new uint256(b); + } + + public static uint256 operator &(uint256 a, uint256 b) + { + var result = new uint256(); + result.pn = new uint[a.nWidth]; + for (int i = 0; i < result.nWidth; i++) + { + result.pn[i] = a.pn[i] & b.pn[i]; + } + return result; + } + + public static uint256 operator |(uint256 a, uint256 b) + { + var result = new uint256(); + result.pn = new uint[a.nWidth]; + for (int i = 0; i < result.nWidth; i++) + { + result.pn[i] = a.pn[i] | b.pn[i]; + } + return result; + } + + public static uint256 operator <<(uint256 a, int shift) + { + var result = new uint256(); + int k = shift / 32; + shift = shift % 32; + + for (int i = 0; i < a.nWidth; i++) + { + if (i + k + 1 < a.nWidth && shift != 0) + { + result.pn[i + k + 1] |= (a.pn[i] >> (32 - shift)); + } + + if (i + k < a.nWidth) + { + result.pn[i + k] |= (a.pn[i] << shift); + } + } + + return result; + } + + public static uint256 operator >>(uint256 a, int shift) + { + var result = new uint256(); + int k = shift / 32; + shift = shift % 32; + + for (int i = 0; i < a.nWidth; i++) + { + if (i - k - 1 >= 0 && shift != 0) + { + result.pn[i - k - 1] |= (a.pn[i] << (32 - shift)); + } + + if (i - k >= 0) + { + result.pn[i - k] |= (a.pn[i] >> shift); + } + } + + return result; + } } } diff --git a/NovacoinTest/Program.cs b/NovacoinTest/Program.cs index f374b3c..5a44468 100644 --- a/NovacoinTest/Program.cs +++ b/NovacoinTest/Program.cs @@ -283,7 +283,7 @@ namespace NovacoinTest Console.WriteLine("{0} != {1} : {2}", hash1.ToString(), hash2.ToString(), hash1 != hash2); Console.WriteLine("{0} == {1} : {2}\n", hash2.ToString(), hash3.ToString(), hash2 == hash3); - + /* /// Pre-09854c5 revisions were affected by integer overflow bug, this issue was caused by incorrect deserialization of input value. Below you can see an example, broken transaction and its normal version. @@ -294,11 +294,36 @@ namespace NovacoinTest Console.WriteLine(txNoBug); */ - + /* + var test1 = new uint256("0000000000021173331e7742b51afe6c853158a8881f7ad871f4391a7ddcfa4e"); + var test2 = new uint256("0000000000093bf84cea580ede01206c3ffc75487ec46771e533e38d9bda972d"); + + Console.WriteLine(test1 < test2); + Console.WriteLine(test1 > test2); + Console.WriteLine(test1 == test2); + Console.WriteLine(test1 != test2); + + Console.WriteLine(test1 - 1); + Console.WriteLine(test1 + 1); + + Console.WriteLine(test1 << 32); + Console.WriteLine(test1 >> 32); + + Output: + + False + False + True + False + 0000000000021173331e7742b51afe6c853158a8881f7ad871f4391a7ddcfa4d + 0000000000021173331e7742b51afe6c853158a8881f7ad871f4391a7ddcfa4f + 00021173331e7742b51afe6c853158a8881f7ad871f4391a7ddcfa4e00000000 + 000000000000000000021173331e7742b51afe6c853158a8881f7ad871f4391a + */ + Console.WriteLine("Reading the block file..."); var bs = new CBlockStore(); bs.ParseBlockFile(); - Console.ReadLine(); } -- 1.7.1