Complete implementation of uint256 and uint160 classes.
authorCryptoManiac <balthazar@yandex.ru>
Tue, 1 Sep 2015 18:52:39 +0000 (21:52 +0300)
committerCryptoManiac <balthazar@yandex.ru>
Tue, 1 Sep 2015 18:52:39 +0000 (21:52 +0300)
Novacoin/Interop.cs
Novacoin/ScryptHash256.cs
Novacoin/base_uint.cs
Novacoin/uint160.cs
Novacoin/uint256.cs
NovacoinTest/Program.cs

index f4c1e2e..0cb7e75 100644 (file)
@@ -28,6 +28,32 @@ namespace Novacoin
     public class Interop
     {
         /// <summary>
+        /// Convert array of unsigned integers to array of bytes.
+        /// </summary>
+        /// <param name="values">Array of unsigned integer values.</param>
+        /// <returns>Byte array</returns>
+        public static byte[] LEBytes(uint[] values)
+        {
+            var result = new byte[values.Length * sizeof(uint)];
+            Buffer.BlockCopy(values, 0, result, 0, result.Length);
+
+            return result;
+        }
+
+        /// <summary>
+        /// Convert byte array to array of unsigned integers.
+        /// </summary>
+        /// <param name="bytes">Byte array.</param>
+        /// <returns>Array of integers</returns>
+        public static uint[] ToUInt32Array(byte[] bytes)
+        {
+            var result = new uint[bytes.Length / sizeof(uint)];
+            Buffer.BlockCopy(bytes, 0, result, 0, bytes.Length);
+
+            return result;
+        }
+
+        /// <summary>
         /// Reverse byte array
         /// </summary>
         /// <param name="source">Source array</param>
index cb39dd8..4f95926 100644 (file)
@@ -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;
         }
-
-        /// <summary>
-        /// Convert array of unsigned integers to array of bytes.
-        /// </summary>
-        /// <param name="values">Array of unsigned integer values.</param>
-        /// <returns>Byte array</returns>
-        private static byte[] LEBytes(uint[] values)
-        {
-            var result = new byte[values.Length * sizeof(uint)];
-            Buffer.BlockCopy(values, 0, result, 0, result.Length);
-
-            return result;
-        }
-
-        /// <summary>
-        /// Convert byte array to array of unsigned integers.
-        /// </summary>
-        /// <param name="bytes">Byte array.</param>
-        /// <returns>Array of integers</returns>
-        private static uint[] ToUInt32Array(byte[] bytes)
-        {
-            var result = new uint[bytes.Length / sizeof(uint)];
-            Buffer.BlockCopy(bytes, 0, result, 0, bytes.Length);
-
-            return result;
-        }
-
     }
 }
index b7eb7f9..3ec7d7b 100644 (file)
 
 
 using System;
+using System.Diagnostics.Contracts;
 
 namespace Novacoin
 {
+    /// <summary>
+    /// Base class for uint256 and uint160.
+    /// </summary>
     public class base_uint : IComparable<base_uint>, IEquatable<base_uint>
     {
-        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<ArgumentException>(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));
+        }
     }
 }
index 26e1dd9..9a89c3d 100644 (file)
@@ -1,5 +1,6 @@
 \feffusing 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<ArgumentException>(bytes.Length == 20, "Incorrect array length");
+
+            pn = Interop.ToUInt32Array(bytes);
+        }
+
+        public uint160(string hex)
+        {
+            Contract.Requires<ArgumentException>(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;
+        }
     }
 }
index 8ce6b97..15a9931 100644 (file)
@@ -1,5 +1,6 @@
 \feffusing 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<ArgumentException>(bytes.Length == 32, "Incorrect array length");
+
+            pn = Interop.ToUInt32Array(bytes);
+        }
+
+        public uint256(string hex)
+        {
+            Contract.Requires<ArgumentException>(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;
+        }
     }
 }
index f374b3c..5a44468 100644 (file)
@@ -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();
         }