Remove Hash, Hash256, Hash160 and ScryptHash256 classes.
[NovacoinLibrary.git] / Novacoin / CryptoUtils.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 using System.IO;
22 using System.Security.Cryptography;
23
24 namespace Novacoin
25 {
26     /// <summary>
27     /// Hashing functionality.
28     /// </summary>
29     public class CryptoUtils
30     {
31         #region Private instances for various hashing algorithm implementations.
32         /// <summary>
33         /// Computes the SHA1 hash for the input data using the managed library.
34         /// </summary>
35         private static SHA1Managed _sha1 = new SHA1Managed();
36         
37         /// <summary>
38         /// Computes the SHA256 hash for the input data using the managed library.
39         /// </summary>
40         private static SHA256Managed _sha256 = new SHA256Managed();
41
42         /// <summary>
43         /// Computes the SHA1 hash for the input data using the managed library.
44         /// </summary>
45         private static RIPEMD160Managed _ripe160 = new RIPEMD160Managed();
46         #endregion
47
48         /// <summary>
49         /// Sha1 calculation
50         /// </summary>
51         /// <param name="inputBytes">Bytes to hash</param>
52         /// <returns>Hashing result</returns>
53         public static byte[] ComputeSha1(byte[] inputBytes)
54         {
55             return _sha1.ComputeHash(inputBytes, 0, inputBytes.Length);
56         }
57
58         /// <summary>
59         /// Sha256 calculation
60         /// </summary>
61         /// <param name="inputBytes">Bytes to hash</param>
62         /// <returns>Hashing result</returns>
63         public static byte[] ComputeSha256(byte[] inputBytes)
64         {
65             return _sha256.ComputeHash(inputBytes, 0, inputBytes.Length);
66         }
67
68         /// <summary>
69         /// RIPEMD-160 calculation
70         /// </summary>
71         /// <param name="inputBytes">Bytes to hash</param>
72         /// <returns>Hashing result</returns>
73         public static byte[] ComputeRipeMD160(byte[] inputBytes)
74         {
75             return _ripe160.ComputeHash(inputBytes, 0, inputBytes.Length);
76         }
77
78         /// <summary>
79         /// RipeMD160(Sha256(X)) calculation
80         /// </summary>
81         /// <param name="inputBytes">Bytes to hash</param>
82         /// <returns>Hashing result</returns>
83         public static byte[] ComputeHash160(byte[] inputBytes)
84         {
85             var digest1 = _sha256.ComputeHash(inputBytes, 0, inputBytes.Length);
86             return _ripe160.ComputeHash(digest1, 0, digest1.Length);
87         }
88
89         /// <summary>
90         /// Sha256(Sha256(X)) calculation
91         /// </summary>
92         /// <param name="inputBytes">Bytes to hash</param>
93         /// <returns>Hashing result</returns>
94         public static byte[] ComputeHash256(byte[] dataBytes)
95         {
96             var digest1 = _sha256.ComputeHash(dataBytes, 0, dataBytes.Length);
97             return _sha256.ComputeHash(digest1, 0, digest1.Length);
98         }
99
100         /// <summary>
101         /// Sha256(Sha256(X)) calculation
102         /// </summary>
103         /// <param name="input1">Reference to first half of data</param>
104         /// <param name="input2">Reference to second half of data</param>
105         /// <returns>Hashing result</returns>
106         public static byte[] ComputeHash256(ref byte[] input1, ref byte[] input2)
107         {
108             var buffer = new byte[input1.Length + input2.Length];
109
110             // Fill the buffer
111             input1.CopyTo(buffer, 0);
112             input2.CopyTo(buffer, input1.Length);
113
114             var digest1 = _sha256.ComputeHash(buffer, 0, buffer.Length);
115             return _sha256.ComputeHash(digest1, 0, digest1.Length);
116         }
117
118         /// <summary>
119         /// Calculate PBKDF2-SHA256(SALSA20/8(PBKDF2-SHA256(X)))
120         /// </summary>
121         /// <param name="inputBytes">Bytes to hash</param>
122         /// <returns>Hashing result</returns>
123         public static byte[] ComputeScryptHash256(byte[] inputBytes)
124         {
125             var V = new uint[(131072 + 63) / sizeof(uint)];
126
127             var keyBytes1 = PBKDF2_Sha256(128, inputBytes, inputBytes, 1);
128             var X = Interop.ToUInt32Array(keyBytes1);
129
130             for (var i = 0; i < 1024; i++)
131             {
132                 Array.Copy(X, 0, V, i * 32, 32);
133
134                 xor_salsa8(ref X, 0, ref X, 16);
135                 xor_salsa8(ref X, 16, ref X, 0);
136             }
137             for (var i = 0; i < 1024; i++)
138             {
139                 var j = 32 * (X[16] & 1023);
140                 for (var k = 0; k < 32; k++)
141                 {
142                     X[k] ^= V[j + k];
143                 }
144                 xor_salsa8(ref X, 0, ref X, 16);
145                 xor_salsa8(ref X, 16, ref X, 0);
146             }
147
148             var xBytes = Interop.LEBytes(X);
149
150             return PBKDF2_Sha256(32, inputBytes, xBytes, 1);
151         }
152
153
154         #region PBKDF2-SHA256
155         /// <summary>
156         /// Managed implementation of PBKDF2-SHA256.
157         /// </summary>
158         /// <param name="dklen">Key length</param>
159         /// <param name="password">Password</param>
160         /// <param name="salt">Salt</param>
161         /// <param name="iterationCount">Amount of derive iterations.</param>
162         /// <returns>Derived key</returns>
163         public static byte[] PBKDF2_Sha256(int dklen, byte[] password, byte[] salt, int iterationCount)
164         {
165             /* Init HMAC state. */
166             using (var hmac = new HMACSHA256(password))
167             {
168                 int hashLength = hmac.HashSize / 8;
169                 if ((hmac.HashSize & 7) != 0)
170                 {
171                     hashLength++;
172                 }
173                 int keyLength = dklen / hashLength;
174                 if (dklen > (0xFFFFFFFFL * hashLength) || dklen < 0)
175                 {
176                     throw new ArgumentOutOfRangeException("dklen");
177                 }
178                 if (dklen % hashLength != 0)
179                 {
180                     keyLength++;
181                 }
182                 var extendedkey = new byte[salt.Length + 4];
183                 Buffer.BlockCopy(salt, 0, extendedkey, 0, salt.Length);
184                 using (var ms = new MemoryStream())
185                 {
186                     /* Iterate through the blocks. */
187                     for (int i = 0; i < keyLength; i++)
188                     {
189                         /* Generate INT(i + 1). */
190                         extendedkey[salt.Length] = (byte)(((i + 1) >> 24) & 0xFF);
191                         extendedkey[salt.Length + 1] = (byte)(((i + 1) >> 16) & 0xFF);
192                         extendedkey[salt.Length + 2] = (byte)(((i + 1) >> 8) & 0xFF);
193                         extendedkey[salt.Length + 3] = (byte)(((i + 1)) & 0xFF);
194
195                         /* Compute U_1 = PRF(P, S || INT(i)). */
196                         var u = hmac.ComputeHash(extendedkey);
197                         Array.Clear(extendedkey, salt.Length, 4);
198
199                         /* T_i = U_1 ... */
200                         var f = u;
201                         for (int j = 1; j < iterationCount; j++)
202                         {
203                             /* Compute U_j. */
204                             u = hmac.ComputeHash(u);
205                             for (int k = 0; k < f.Length; k++)
206                             {
207                                 /* ... xor U_j ... */
208                                 f[k] ^= u[k];
209                             }
210                         }
211
212                         /* Copy as many bytes as necessary into memory stream. */
213                         ms.Write(f, 0, f.Length);
214                         Array.Clear(u, 0, u.Length);
215                         Array.Clear(f, 0, f.Length);
216                     }
217                     ms.Position = 0;
218
219                     /* Initialize result array. */
220                     var dk = new byte[dklen];
221
222                     /* Read key from memory stream. */
223                     ms.Read(dk, 0, dklen);
224
225                     ms.Position = 0;
226                     for (long i = 0; i < ms.Length; i++)
227                     {
228                         ms.WriteByte(0);
229                     }
230                     Array.Clear(extendedkey, 0, extendedkey.Length);
231                     return dk;
232                 }
233             }
234         }
235         #endregion
236
237         #region SALSA20/8
238         private static void xor_salsa8(ref uint[] B, int indexB, ref uint[] Bx, int indexBx)
239         {
240             uint x00, x01, x02, x03, x04, x05, x06, x07, x08, x09, x10, x11, x12, x13, x14, x15;
241             byte i;
242
243             x00 = (B[indexB + 0] ^= Bx[indexBx + 0]);
244             x01 = (B[indexB + 1] ^= Bx[indexBx + 1]);
245             x02 = (B[indexB + 2] ^= Bx[indexBx + 2]);
246             x03 = (B[indexB + 3] ^= Bx[indexBx + 3]);
247             x04 = (B[indexB + 4] ^= Bx[indexBx + 4]);
248             x05 = (B[indexB + 5] ^= Bx[indexBx + 5]);
249             x06 = (B[indexB + 6] ^= Bx[indexBx + 6]);
250             x07 = (B[indexB + 7] ^= Bx[indexBx + 7]);
251             x08 = (B[indexB + 8] ^= Bx[indexBx + 8]);
252             x09 = (B[indexB + 9] ^= Bx[indexBx + 9]);
253             x10 = (B[indexB + 10] ^= Bx[indexBx + 10]);
254             x11 = (B[indexB + 11] ^= Bx[indexBx + 11]);
255             x12 = (B[indexB + 12] ^= Bx[indexBx + 12]);
256             x13 = (B[indexB + 13] ^= Bx[indexBx + 13]);
257             x14 = (B[indexB + 14] ^= Bx[indexBx + 14]);
258             x15 = (B[indexB + 15] ^= Bx[indexBx + 15]);
259
260             Func<uint, int, uint> R = (a, b) => (((a) << (b)) | ((a) >> (32 - (b))));
261
262             for (i = 0; i < 8; i += 2)
263             {
264                 /* Operate on columns. */
265                 x04 ^= R(x00 + x12, 7); x09 ^= R(x05 + x01, 7);
266                 x14 ^= R(x10 + x06, 7); x03 ^= R(x15 + x11, 7);
267
268                 x08 ^= R(x04 + x00, 9); x13 ^= R(x09 + x05, 9);
269                 x02 ^= R(x14 + x10, 9); x07 ^= R(x03 + x15, 9);
270
271                 x12 ^= R(x08 + x04, 13); x01 ^= R(x13 + x09, 13);
272                 x06 ^= R(x02 + x14, 13); x11 ^= R(x07 + x03, 13);
273
274                 x00 ^= R(x12 + x08, 18); x05 ^= R(x01 + x13, 18);
275                 x10 ^= R(x06 + x02, 18); x15 ^= R(x11 + x07, 18);
276
277                 /* Operate on rows. */
278                 x01 ^= R(x00 + x03, 7); x06 ^= R(x05 + x04, 7);
279                 x11 ^= R(x10 + x09, 7); x12 ^= R(x15 + x14, 7);
280
281                 x02 ^= R(x01 + x00, 9); x07 ^= R(x06 + x05, 9);
282                 x08 ^= R(x11 + x10, 9); x13 ^= R(x12 + x15, 9);
283
284                 x03 ^= R(x02 + x01, 13); x04 ^= R(x07 + x06, 13);
285                 x09 ^= R(x08 + x11, 13); x14 ^= R(x13 + x12, 13);
286
287                 x00 ^= R(x03 + x02, 18); x05 ^= R(x04 + x07, 18);
288                 x10 ^= R(x09 + x08, 18); x15 ^= R(x14 + x13, 18);
289             }
290
291             B[indexB + 0] += x00;
292             B[indexB + 1] += x01;
293             B[indexB + 2] += x02;
294             B[indexB + 3] += x03;
295             B[indexB + 4] += x04;
296             B[indexB + 5] += x05;
297             B[indexB + 6] += x06;
298             B[indexB + 7] += x07;
299             B[indexB + 8] += x08;
300             B[indexB + 9] += x09;
301             B[indexB + 10] += x10;
302             B[indexB + 11] += x11;
303             B[indexB + 12] += x12;
304             B[indexB + 13] += x13;
305             B[indexB + 14] += x14;
306             B[indexB + 15] += x15;
307         }
308         #endregion
309     }
310 }