Implementation of operator* for uint160 and uint256.
[NovacoinLibrary.git] / Novacoin / uint160.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 uint160 : base_uint
25     {
26         #region Access to internal representation
27         new protected int nWidth
28         {
29             get { return base.nWidth; }
30             private set { base.nWidth = value; }
31         }
32         new protected uint[] pn
33         {
34             get { return base.pn; }
35             private set { base.pn = value; }
36         }
37         #endregion
38
39         #region Constructors
40         public uint160()
41         {
42             nWidth = 5;
43             pn = new uint[nWidth];
44         }
45
46         public uint160(uint160 b) : this()
47         {
48             for (int i = 0; i < nWidth; i++)
49             {
50                 pn[i] = b.pn[i];
51             }
52         }
53
54
55         public uint160(ulong n) : this()
56         {
57             pn[0] = (uint)n;
58             pn[1] = (uint)(n >> 32);
59             for (int i = 2; i < nWidth; i++)
60             {
61                 pn[i] = 0;
62             }
63         }
64
65         public uint160(byte[] bytes) : this()
66         {
67             Contract.Requires<ArgumentException>(bytes.Length == 20, "Incorrect array length");
68             pn = Interop.ToUInt32Array(bytes);
69         }
70
71         public uint160(string hex) : this()
72         {
73             Contract.Requires<ArgumentException>(hex.Length == 40, "Incorrect string");
74             var bytes = Interop.ReverseBytes(Interop.HexToArray(hex));
75             pn = Interop.ToUInt32Array(bytes);
76         }
77         #endregion
78
79         #region Cast operators
80         public static implicit operator uint160(byte[] bytes)
81         {
82             return new uint160(bytes);
83         }
84
85         public static implicit operator uint160(ulong n)
86         {
87             return new uint160(n);
88         }
89         #endregion
90
91         #region Bitwise operations
92         public static uint160 operator ~(uint160 a)
93         {
94             var ret = new uint160();
95             for (int i = 0; i < a.nWidth; i++)
96             {
97                 ret.pn[i] = ~a.pn[i];
98             }
99             return ret;
100         }
101
102         public static uint160 operator ^(uint160 a, uint160 b)
103         {
104             var result = new uint160();
105             result.pn = new uint[a.nWidth];
106             for (int i = 0; i < result.nWidth; i++)
107             {
108                 result.pn[i] = a.pn[i] ^ b.pn[i];
109             }
110             return result;
111         }
112
113         public static uint160 operator &(uint160 a, uint160 b)
114         {
115             var result = new uint160();
116             result.pn = new uint[a.nWidth];
117             for (int i = 0; i < result.nWidth; i++)
118             {
119                 result.pn[i] = a.pn[i] & b.pn[i];
120             }
121             return result;
122         }
123
124         public static uint160 operator |(uint160 a, uint160 b)
125         {
126             var result = new uint160();
127             result.pn = new uint[a.nWidth];
128             for (int i = 0; i < result.nWidth; i++)
129             {
130                 result.pn[i] = a.pn[i] | b.pn[i];
131             }
132             return result;
133         }
134         #endregion
135
136         #region Basic arithmetics
137         public static uint160 operator +(uint160 a, uint160 b)
138         {
139             var result = new uint160();
140             ulong carry = 0;
141             for (int i = 0; i < result.nWidth; i++)
142             {
143                 ulong n = carry + a.pn[i] + b.pn[i];
144                 result.pn[i] = (uint)(n & 0xffffffff);
145                 carry = n >> 32;
146             }
147             return result;
148         }
149
150         public static uint160 operator +(uint160 a, ulong b)
151         {
152             return a + new uint160(b);
153         }
154
155         public static uint160 operator -(uint160 a, uint160 b)
156         {
157             return a + (-b);
158         }
159
160         public static uint160 operator -(uint160 a, ulong b)
161         {
162             return a - new uint160(b);
163         }
164
165         public static uint160 operator -(uint160 a)
166         {
167             var ret = new uint160();
168             for (int i = 0; i < a.nWidth; i++)
169             {
170                 ret.pn[i] = ~a.pn[i];
171             }
172             ret++;
173             return ret;
174         }
175
176
177         public static uint160 operator ++(uint160 a)
178         {
179             int i = 0;
180             while (++a.pn[i] == 0 && i < a.nWidth - 1)
181             {
182                 i++;
183             }
184             return a;
185         }
186
187         public static uint160 operator --(uint160 a)
188         {
189             int i = 0;
190             while (--a.pn[i] == uint.MaxValue && i < a.nWidth - 1)
191             {
192                 i++;
193             }
194             return a;
195         }
196
197         public static uint160 operator /(uint160 a, uint divisor)
198         {
199             var result = new uint160();
200
201             ulong r = 0;
202             int i = a.nWidth;
203
204             while (i-- > 0)
205             {
206                 r <<= 32;
207                 r |= a.pn[i];
208                 result.pn[i] = (uint)(r / divisor);
209                 r %= divisor;
210             }
211
212             return result;
213         }
214
215         public static uint160 operator *(uint160 a, uint multiplier)
216         {
217             var result = new uint160();
218
219             ulong c = 0;
220             uint i = 0;
221
222             do
223             {
224                 c += a.pn[i] * (ulong)multiplier;
225                 result.pn[i] = (uint)c;
226                 c >>= 32;
227             } while (++i < result.nWidth);
228
229             return result;
230         }
231
232         public static uint operator %(uint160 a, uint divisor)
233         {
234             ulong r = 0;
235             int i = a.nWidth;
236
237             while (i-- > 0)
238             {
239                 r <<= 32;
240                 r |= a.pn[i];
241                 r %= divisor;
242             }
243
244             return (uint)r;
245         }
246
247         #endregion
248
249         #region Shift
250         public static uint160 operator <<(uint160 a, int shift)
251         {
252             var result = new uint160();
253             int k = shift / 32;
254             shift = shift % 32;
255
256             for (int i = 0; i < a.nWidth; i++)
257             {
258                 if (i + k + 1 < a.nWidth && shift != 0)
259                 {
260                     result.pn[i + k + 1] |= (a.pn[i] >> (32 - shift));
261                 }
262
263                 if (i + k < a.nWidth)
264                 {
265                     result.pn[i + k] |= (a.pn[i] << shift);
266                 }
267             }
268
269             return result;
270         }
271
272         public static uint160 operator >>(uint160 a, int shift)
273         {
274             var result = new uint160();
275             int k = shift / 32;
276             shift = shift % 32;
277
278             for (int i = 0; i < a.nWidth; i++)
279             {
280                 if (i - k - 1 >= 0 && shift != 0)
281                 {
282                     result.pn[i - k - 1] |= (a.pn[i] << (32 - shift));
283                 }
284
285                 if (i - k >= 0)
286                 {
287                     result.pn[i - k] |= (a.pn[i] >> shift);
288                 }
289             }
290
291             return result;
292         }
293         #endregion
294     }
295 }