Implementation of operator* for uint160 and uint256.
[NovacoinLibrary.git] / Novacoin / uint256.cs
1 \feff/**
2  *  Novacoin classes library
3  *  Copyright (C) 2015 Alex D. (balthazar.ad@gmail.com)
4
5  *  This program is free software: you can redistribute it and/or modify
6  *  it under the terms of the GNU Affero General Public License as
7  *  published by the Free Software Foundation, either version 3 of the
8  *  License, or (at your option) any later version.
9
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU Affero General Public License for more details.
14
15  *  You should have received a copy of the GNU Affero General Public License
16  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 using System;
20 using System.Diagnostics.Contracts;
21
22 namespace Novacoin
23 {
24     public class uint256 : base_uint
25     {
26         #region Access to internal representation
27         new protected int nWidth {
28             get { return base.nWidth; }
29             private set { base.nWidth = value; }
30         }
31         new protected uint[] pn {
32             get { return base.pn; }
33             private set { base.pn = value; }
34         }
35         #endregion
36
37         #region Constructors
38         public uint256()
39         {
40             nWidth = 8;
41             pn = new uint[nWidth];
42         }
43
44         public uint256(uint256 b) : this()
45         {
46             for (int i = 0; i < nWidth; i++)
47             {
48                 pn[i] = b.pn[i];
49             }
50         }
51
52         public uint256(ulong n) : this()
53         {
54             pn[0] = (uint)n;
55             pn[1] = (uint)(n >> 32);
56             for (int i = 2; i < nWidth; i++)
57             {
58                 pn[i] = 0;
59             }
60         }
61
62         public uint256(byte[] bytes) : this()
63         {
64             Contract.Requires<ArgumentException>(bytes.Length == 32, "Incorrect array length");
65
66             pn = Interop.ToUInt32Array(bytes);
67         }
68
69         public uint256(string hex) : this()
70         {
71             Contract.Requires<ArgumentException>(hex.Length == 64, "Incorrect string");
72
73             var bytes = Interop.ReverseBytes(Interop.HexToArray(hex));
74             pn = Interop.ToUInt32Array(bytes);
75         }
76         #endregion
77
78         #region Cast operators
79         public static implicit operator uint256(byte[] bytes)
80         {
81             return new uint256(bytes);
82         }
83
84         public static implicit operator uint256(ulong n)
85         {
86             return new uint256(n);
87         }
88         #endregion
89
90         #region Compact representation
91         /// <summary>
92         /// Compact representation of unsigned 256bit numbers.
93         /// 
94         /// N = (-1^sign) * m * 256^(exp-3)
95         /// 
96         /// http://bitcoin.stackexchange.com/questions/30467/what-are-the-equations-to-convert-between-bits-and-difficulty
97         /// </summary>
98         public uint Compact
99         {
100             get
101             {
102                 int nSize = (bits + 7) / 8;
103                 uint nCompact = 0;
104                 if (nSize <= 3)
105                     nCompact = ((uint)Low64) << 8 * (3 - nSize);
106                 else
107                 {
108                     uint256 bn = this >> 8 * (nSize - 3);
109                     nCompact = (uint)bn.Low64;
110                 }
111
112                 if ((nCompact & 0x00800000) != 0)
113                 {
114                     nCompact >>= 8;
115                     nSize++;
116                 }
117
118                 Contract.Assert((nCompact & ~0x007fffff) == 0);
119                 Contract.Assert(nSize < 256);
120
121                 nCompact |= (uint)nSize << 24;
122                 nCompact |= 0;
123
124                 return nCompact;
125             }
126             set {
127                 int nSize = (int)value >> 24;
128                 uint nWord = value & 0x007fffff;
129
130                 uint256 i;
131
132                 if (nSize <= 3)
133                 {
134                     nWord >>= 8 * (3 - nSize);
135                     i = new uint256(nWord);
136                 }
137                 else
138                 {
139                     i = new uint256(nWord);
140                     i <<= 8 * (nSize - 3);
141                 }
142
143                 pn = i.pn;
144             }
145         }
146         #endregion
147
148         #region Bitwise operations
149         public static uint256 operator ~(uint256 a)
150         {
151             var ret = new uint256();
152             for (int i = 0; i < a.nWidth; i++)
153             {
154                 ret.pn[i] = ~a.pn[i];
155             }
156             return ret;
157         }
158
159         public static uint256 operator ^(uint256 a, uint256 b)
160         {
161             var result = new uint256();
162             result.pn = new uint[a.nWidth];
163             for (int i = 0; i < result.nWidth; i++)
164             {
165                 result.pn[i] = a.pn[i] ^ b.pn[i];
166             }
167             return result;
168         }
169
170         public static uint256 operator &(uint256 a, uint256 b)
171         {
172             var result = new uint256();
173             result.pn = new uint[a.nWidth];
174             for (int i = 0; i < result.nWidth; i++)
175             {
176                 result.pn[i] = a.pn[i] & b.pn[i];
177             }
178             return result;
179         }
180
181         public static uint256 operator |(uint256 a, uint256 b)
182         {
183             var result = new uint256();
184             result.pn = new uint[a.nWidth];
185             for (int i = 0; i < result.nWidth; i++)
186             {
187                 result.pn[i] = a.pn[i] | b.pn[i];
188             }
189             return result;
190         }
191         #endregion
192
193         #region Basic arithmetics
194         public static uint256 operator -(uint256 a)
195         {
196             var ret = new uint256();
197             for (int i = 0; i < a.nWidth; i++)
198             {
199                 ret.pn[i] = ~a.pn[i];
200             }
201             ret++;
202             return ret;
203         }
204
205         public static uint256 operator ++(uint256 a)
206         {
207             int i = 0;
208             while (++a.pn[i] == 0 && i < a.nWidth - 1)
209             {
210                 i++;
211             }
212             return a;
213         }
214
215         public static uint256 operator --(uint256 a)
216         {
217             int i = 0;
218             while (--a.pn[i] == uint.MaxValue && i < a.nWidth - 1)
219             {
220                 i++;
221             }
222             return a;
223         }
224
225
226         public static uint256 operator +(uint256 a, uint256 b)
227         {
228             var result = new uint256();
229             ulong carry = 0;
230             for (int i = 0; i < result.nWidth; i++)
231             {
232                 ulong n = carry + a.pn[i] + b.pn[i];
233                 result.pn[i] = (uint)(n & 0xffffffff);
234                 carry = n >> 32;
235             }
236             return result;
237         }
238
239         public static uint256 operator +(uint256 a, ulong b)
240         {
241             return a + new uint256(b);
242         }
243
244         public static uint256 operator -(uint256 a, uint256 b)
245         {
246             return a + (-b);
247         }
248
249         public static uint256 operator -(uint256 a, ulong b)
250         {
251             return a - new uint256(b);
252         }
253
254         public static uint256 operator /(uint256 a, uint divisor)
255         {
256             var result = new uint256();
257
258             ulong r = 0;
259             int i = a.nWidth;
260
261             while (i-- > 0)
262             {
263                 r <<= 32;
264                 r |= a.pn[i];
265                 result.pn[i] = (uint)(r / divisor);
266                 r %= divisor;
267             }
268
269             return result;
270         }
271
272         public static uint256 operator *(uint256 a, uint multiplier)
273         {
274             var result = new uint256();
275
276             ulong c = 0;
277             uint i = 0;
278
279             do
280             {
281                 c += a.pn[i] * (ulong)multiplier;
282                 result.pn[i] = (uint)c;
283                 c >>= 32;
284             } while (++i < result.nWidth);
285
286             return result;
287         }
288
289         public static uint operator %(uint256 a, uint divisor)
290         {
291             ulong r = 0;
292             int i = a.nWidth;
293
294             while (i-- > 0)
295             {
296                 r <<= 32;
297                 r |= a.pn[i];
298                 r %= divisor;
299             }
300
301             return (uint)r;
302         }
303         #endregion
304
305         #region Shift
306         public static uint256 operator <<(uint256 a, int shift)
307         {
308             var result = new uint256();
309             int k = shift / 32;
310             shift = shift % 32;
311
312             for (int i = 0; i < a.nWidth; i++)
313             {
314                 if (i + k + 1 < a.nWidth && shift != 0)
315                 {
316                     result.pn[i + k + 1] |= (a.pn[i] >> (32 - shift));
317                 }
318
319                 if (i + k < a.nWidth)
320                 {
321                     result.pn[i + k] |= (a.pn[i] << shift);
322                 }
323             }
324
325             return result;
326         }
327
328         public static uint256 operator >>(uint256 a, int shift)
329         {
330             var result = new uint256();
331             int k = shift / 32;
332             shift = shift % 32;
333
334             for (int i = 0; i < a.nWidth; i++)
335             {
336                 if (i - k - 1 >= 0 && shift != 0)
337                 {
338                     result.pn[i - k - 1] |= (a.pn[i] << (32 - shift));
339                 }
340
341                 if (i - k >= 0)
342                 {
343                     result.pn[i - k] |= (a.pn[i] >> shift);
344                 }
345             }
346
347             return result;
348         }
349         #endregion
350     }
351 }