Scrypt hashing is working now
[NovacoinLibrary.git] / Novacoin / ScryptHash256.cs
1 \feffusing System;
2 using System.Collections.Generic;
3 using System.Linq;
4
5 using System.Security.Cryptography;
6
7 namespace Novacoin
8 {
9     /// <summary>
10     /// Representation of scrypt hash
11     /// </summary>
12     public class ScryptHash256 : Hash
13     {
14         // 32 bytes
15         public override int hashSize
16         {
17             get { return 32; }
18         }
19
20         public ScryptHash256() : base() { }
21         public ScryptHash256(byte[] bytesArray) : base(bytesArray) { }
22         public ScryptHash256(IList<byte> bytesList) : base(bytesList) { }
23
24         /// <summary>
25         /// Calculate scrypt hash and return new instance of ScryptHash256 class
26         /// </summary>
27         /// <param name="inputBytes">Byte sequence to hash</param>
28         /// <returns>Hashing result instance</returns>
29         public static ScryptHash256 Compute256(IEnumerable<byte> inputBytes)
30         {
31             uint[] V = new uint[(131072 + 63) / sizeof(uint)];
32
33             byte[] dataBytes = inputBytes.ToArray();
34             byte[] keyBytes1 = PBKDF2Sha256GetBytes(128, dataBytes, dataBytes, 1);
35             uint[] X = Interop.ToUInt32Array(keyBytes1);
36
37             uint i, j, k;
38             for (i = 0; i < 1024; i++)
39             {
40                 Array.Copy(X, 0, V, i * 32, 32);
41
42                 xor_salsa8(ref X, 0, ref X, 16);
43                 xor_salsa8(ref X, 16, ref X, 0);
44             }
45             for (i = 0; i < 1024; i++)
46             {
47                 j = 32 * (X[16] & 1023);
48                 for (k = 0; k < 32; k++)
49                     X[k] ^= V[j + k];
50                 xor_salsa8(ref X, 0, ref X, 16);
51                 xor_salsa8(ref X, 16, ref X, 0);
52             }
53
54             byte[] xBytes = Interop.LEBytes(X);
55             byte[] keyBytes2 = PBKDF2Sha256GetBytes(32, dataBytes, xBytes, 1);
56
57             return new ScryptHash256(keyBytes2);
58         }
59
60         private static byte[] PBKDF2Sha256GetBytes(int dklen, byte[] password, byte[] salt, int iterationCount)
61         {
62             using (var hmac = new HMACSHA256(password))
63             {
64                 int hashLength = hmac.HashSize / 8;
65                 if ((hmac.HashSize & 7) != 0)
66                     hashLength++;
67                 int keyLength = dklen / hashLength;
68                 if ((long)dklen > (0xFFFFFFFFL * hashLength) || dklen < 0)
69                     throw new ArgumentOutOfRangeException("dklen");
70                 if (dklen % hashLength != 0)
71                     keyLength++;
72                 byte[] extendedkey = new byte[salt.Length + 4];
73                 Buffer.BlockCopy(salt, 0, extendedkey, 0, salt.Length);
74                 using (var ms = new System.IO.MemoryStream())
75                 {
76                     for (int i = 0; i < keyLength; i++)
77                     {
78                         extendedkey[salt.Length] = (byte)(((i + 1) >> 24) & 0xFF);
79                         extendedkey[salt.Length + 1] = (byte)(((i + 1) >> 16) & 0xFF);
80                         extendedkey[salt.Length + 2] = (byte)(((i + 1) >> 8) & 0xFF);
81                         extendedkey[salt.Length + 3] = (byte)(((i + 1)) & 0xFF);
82                         byte[] u = hmac.ComputeHash(extendedkey);
83                         Array.Clear(extendedkey, salt.Length, 4);
84                         byte[] f = u;
85                         for (int j = 1; j < iterationCount; j++)
86                         {
87                             u = hmac.ComputeHash(u);
88                             for (int k = 0; k < f.Length; k++)
89                             {
90                                 f[k] ^= u[k];
91                             }
92                         }
93                         ms.Write(f, 0, f.Length);
94                         Array.Clear(u, 0, u.Length);
95                         Array.Clear(f, 0, f.Length);
96                     }
97                     byte[] dk = new byte[dklen];
98                     ms.Position = 0;
99                     ms.Read(dk, 0, dklen);
100                     ms.Position = 0;
101                     for (long i = 0; i < ms.Length; i++)
102                     {
103                         ms.WriteByte(0);
104                     }
105                     Array.Clear(extendedkey, 0, extendedkey.Length);
106                     return dk;
107                 }
108             }
109         }
110
111         private static void xor_salsa8(ref uint[] B, int indexB, ref uint[] Bx, int indexBx)
112         {
113             uint x00, x01, x02, x03, x04, x05, x06, x07, x08, x09, x10, x11, x12, x13, x14, x15;
114             byte i;
115
116             x00 = (B[indexB + 0] ^= Bx[indexBx + 0]);
117             x01 = (B[indexB + 1] ^= Bx[indexBx + 1]);
118             x02 = (B[indexB + 2] ^= Bx[indexBx + 2]);
119             x03 = (B[indexB + 3] ^= Bx[indexBx + 3]);
120             x04 = (B[indexB + 4] ^= Bx[indexBx + 4]);
121             x05 = (B[indexB + 5] ^= Bx[indexBx + 5]);
122             x06 = (B[indexB + 6] ^= Bx[indexBx + 6]);
123             x07 = (B[indexB + 7] ^= Bx[indexBx + 7]);
124             x08 = (B[indexB + 8] ^= Bx[indexBx + 8]);
125             x09 = (B[indexB + 9] ^= Bx[indexBx + 9]);
126             x10 = (B[indexB + 10] ^= Bx[indexBx + 10]);
127             x11 = (B[indexB + 11] ^= Bx[indexBx + 11]);
128             x12 = (B[indexB + 12] ^= Bx[indexBx + 12]);
129             x13 = (B[indexB + 13] ^= Bx[indexBx + 13]);
130             x14 = (B[indexB + 14] ^= Bx[indexBx + 14]);
131             x15 = (B[indexB + 15] ^= Bx[indexBx + 15]);
132
133             Func<uint, int, uint> R = (a, b) => (((a) << (b)) | ((a) >> (32 - (b))));
134
135             for (i = 0; i < 8; i += 2)
136             {
137                 /* Operate on columns. */
138                 x04 ^= R(x00 + x12, 7); x09 ^= R(x05 + x01, 7);
139                 x14 ^= R(x10 + x06, 7); x03 ^= R(x15 + x11, 7);
140
141                 x08 ^= R(x04 + x00, 9); x13 ^= R(x09 + x05, 9);
142                 x02 ^= R(x14 + x10, 9); x07 ^= R(x03 + x15, 9);
143
144                 x12 ^= R(x08 + x04, 13); x01 ^= R(x13 + x09, 13);
145                 x06 ^= R(x02 + x14, 13); x11 ^= R(x07 + x03, 13);
146
147                 x00 ^= R(x12 + x08, 18); x05 ^= R(x01 + x13, 18);
148                 x10 ^= R(x06 + x02, 18); x15 ^= R(x11 + x07, 18);
149
150                 /* Operate on rows. */
151                 x01 ^= R(x00 + x03, 7); x06 ^= R(x05 + x04, 7);
152                 x11 ^= R(x10 + x09, 7); x12 ^= R(x15 + x14, 7);
153
154                 x02 ^= R(x01 + x00, 9); x07 ^= R(x06 + x05, 9);
155                 x08 ^= R(x11 + x10, 9); x13 ^= R(x12 + x15, 9);
156
157                 x03 ^= R(x02 + x01, 13); x04 ^= R(x07 + x06, 13);
158                 x09 ^= R(x08 + x11, 13); x14 ^= R(x13 + x12, 13);
159
160                 x00 ^= R(x03 + x02, 18); x05 ^= R(x04 + x07, 18);
161                 x10 ^= R(x09 + x08, 18); x15 ^= R(x14 + x13, 18);
162             }
163
164             B[indexB + 0] += x00;
165             B[indexB + 1] += x01;
166             B[indexB + 2] += x02;
167             B[indexB + 3] += x03;
168             B[indexB + 4] += x04;
169             B[indexB + 5] += x05;
170             B[indexB + 6] += x06;
171             B[indexB + 7] += x07;
172             B[indexB + 8] += x08;
173             B[indexB + 9] += x09;
174             B[indexB + 10] += x10;
175             B[indexB + 11] += x11;
176             B[indexB + 12] += x12;
177             B[indexB + 13] += x13;
178             B[indexB + 14] += x14;
179             B[indexB + 15] += x15;
180         }
181     }
182 }