|
1 | | -// SHA-256 for JavaScript. |
2 | | -// Original implementation https://github.com/dchest/fast-sha256-js/blob/master/src/sha256.ts |
3 | | -const digestLength = 32; |
4 | | -const blockSize = 64; |
5 | | - |
6 | | -// SHA-256 constants |
7 | | -const K = new Uint32Array([ |
8 | | - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, |
9 | | - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, |
10 | | - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, |
11 | | - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, |
12 | | - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, |
13 | | - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, |
14 | | - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, |
15 | | - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 |
16 | | -]); |
17 | | - |
18 | | -function hashBlocks(w: Int32Array, v: Int32Array, p: Uint8Array, pos: number, len: number): number { |
19 | | - let a: number, |
20 | | - b: number, |
21 | | - c: number, |
22 | | - d: number, |
23 | | - e: number, |
24 | | - f: number, |
25 | | - g: number, |
26 | | - h: number, |
27 | | - u: number, |
28 | | - i: number, |
29 | | - j: number, |
30 | | - t1: number, |
31 | | - t2: number; |
32 | | - while (len >= 64) { |
33 | | - a = v[0]; |
34 | | - b = v[1]; |
35 | | - c = v[2]; |
36 | | - d = v[3]; |
37 | | - e = v[4]; |
38 | | - f = v[5]; |
39 | | - g = v[6]; |
40 | | - h = v[7]; |
41 | | - |
42 | | - for (i = 0; i < 16; i++) { |
43 | | - j = pos + i * 4; |
44 | | - w[i] = |
45 | | - ((p[j] & 0xff) << 24) | |
46 | | - ((p[j + 1] & 0xff) << 16) | |
47 | | - ((p[j + 2] & 0xff) << 8) | |
48 | | - (p[j + 3] & 0xff); |
49 | | - } |
50 | | - |
51 | | - for (i = 16; i < 64; i++) { |
52 | | - u = w[i - 2]; |
53 | | - t1 = ((u >>> 17) | (u << (32 - 17))) ^ ((u >>> 19) | (u << (32 - 19))) ^ (u >>> 10); |
54 | | - |
55 | | - u = w[i - 15]; |
56 | | - t2 = ((u >>> 7) | (u << (32 - 7))) ^ ((u >>> 18) | (u << (32 - 18))) ^ (u >>> 3); |
57 | | - |
58 | | - w[i] = ((t1 + w[i - 7]) | 0) + ((t2 + w[i - 16]) | 0); |
59 | | - } |
60 | | - |
61 | | - for (i = 0; i < 64; i++) { |
62 | | - t1 = |
63 | | - ((((((e >>> 6) | (e << (32 - 6))) ^ |
64 | | - ((e >>> 11) | (e << (32 - 11))) ^ |
65 | | - ((e >>> 25) | (e << (32 - 25)))) + |
66 | | - ((e & f) ^ (~e & g))) | |
67 | | - 0) + |
68 | | - ((h + ((K[i] + w[i]) | 0)) | 0)) | |
69 | | - 0; |
70 | | - |
71 | | - t2 = |
72 | | - ((((a >>> 2) | (a << (32 - 2))) ^ |
73 | | - ((a >>> 13) | (a << (32 - 13))) ^ |
74 | | - ((a >>> 22) | (a << (32 - 22)))) + |
75 | | - ((a & b) ^ (a & c) ^ (b & c))) | |
76 | | - 0; |
77 | | - |
78 | | - h = g; |
79 | | - g = f; |
80 | | - f = e; |
81 | | - e = (d + t1) | 0; |
82 | | - d = c; |
83 | | - c = b; |
84 | | - b = a; |
85 | | - a = (t1 + t2) | 0; |
86 | | - } |
87 | | - |
88 | | - v[0] += a; |
89 | | - v[1] += b; |
90 | | - v[2] += c; |
91 | | - v[3] += d; |
92 | | - v[4] += e; |
93 | | - v[5] += f; |
94 | | - v[6] += g; |
95 | | - v[7] += h; |
96 | | - |
97 | | - pos += 64; |
98 | | - len -= 64; |
99 | | - } |
100 | | - return pos; |
101 | | -} |
102 | | - |
103 | | -// Hash implements SHA256 hash algorithm. |
104 | | -export class Hash { |
105 | | - digestLength: number = digestLength; |
106 | | - blockSize: number = blockSize; |
107 | | - |
108 | | - // Note: Int32Array is used instead of Uint32Array for performance reasons. |
109 | | - private state: Int32Array = new Int32Array(8); // hash state |
110 | | - private temp: Int32Array = new Int32Array(64); // temporary state |
111 | | - private buffer: Uint8Array = new Uint8Array(128); // buffer for data to hash |
112 | | - private bufferLength = 0; // number of bytes in buffer |
113 | | - private bytesHashed = 0; // number of total bytes hashed |
114 | | - |
115 | | - finished = false; // indicates whether the hash was finalized |
116 | | - |
117 | | - constructor() { |
118 | | - this.reset(); |
119 | | - } |
120 | | - |
121 | | - // Resets hash state making it possible |
122 | | - // to re-use this instance to hash other data. |
123 | | - reset(): this { |
124 | | - this.state[0] = 0x6a09e667; |
125 | | - this.state[1] = 0xbb67ae85; |
126 | | - this.state[2] = 0x3c6ef372; |
127 | | - this.state[3] = 0xa54ff53a; |
128 | | - this.state[4] = 0x510e527f; |
129 | | - this.state[5] = 0x9b05688c; |
130 | | - this.state[6] = 0x1f83d9ab; |
131 | | - this.state[7] = 0x5be0cd19; |
132 | | - this.bufferLength = 0; |
133 | | - this.bytesHashed = 0; |
134 | | - this.finished = false; |
135 | | - return this; |
136 | | - } |
137 | | - |
138 | | - // Cleans internal buffers and re-initializes hash state. |
139 | | - clean() { |
140 | | - for (let i = 0; i < this.buffer.length; i++) { |
141 | | - this.buffer[i] = 0; |
142 | | - } |
143 | | - for (let i = 0; i < this.temp.length; i++) { |
144 | | - this.temp[i] = 0; |
145 | | - } |
146 | | - this.reset(); |
147 | | - } |
148 | | - |
149 | | - // Updates hash state with the given data. |
150 | | - // |
151 | | - // Optionally, length of the data can be specified to hash |
152 | | - // fewer bytes than data.length. |
153 | | - // |
154 | | - // Throws error when trying to update already finalized hash: |
155 | | - // instance must be reset to use it again. |
156 | | - update(data: Uint8Array, dataLength: number = data.length): this { |
157 | | - if (this.finished) { |
158 | | - throw new Error("SHA256: can't update because hash was finished."); |
159 | | - } |
160 | | - let dataPos = 0; |
161 | | - this.bytesHashed += dataLength; |
162 | | - if (this.bufferLength > 0) { |
163 | | - while (this.bufferLength < 64 && dataLength > 0) { |
164 | | - this.buffer[this.bufferLength++] = data[dataPos++]; |
165 | | - dataLength--; |
166 | | - } |
167 | | - if (this.bufferLength === 64) { |
168 | | - hashBlocks(this.temp, this.state, this.buffer, 0, 64); |
169 | | - this.bufferLength = 0; |
170 | | - } |
171 | | - } |
172 | | - if (dataLength >= 64) { |
173 | | - dataPos = hashBlocks(this.temp, this.state, data, dataPos, dataLength); |
174 | | - dataLength %= 64; |
175 | | - } |
176 | | - while (dataLength > 0) { |
177 | | - this.buffer[this.bufferLength++] = data[dataPos++]; |
178 | | - dataLength--; |
179 | | - } |
180 | | - return this; |
181 | | - } |
182 | | - |
183 | | - // Finalizes hash state and puts hash into out. |
184 | | - // |
185 | | - // If hash was already finalized, puts the same value. |
186 | | - finish(out: Uint8Array): this { |
187 | | - if (!this.finished) { |
188 | | - const bytesHashed = this.bytesHashed; |
189 | | - const left = this.bufferLength; |
190 | | - const bitLenHi = (bytesHashed / 0x20000000) | 0; |
191 | | - const bitLenLo = bytesHashed << 3; |
192 | | - const padLength = bytesHashed % 64 < 56 ? 64 : 128; |
193 | | - |
194 | | - this.buffer[left] = 0x80; |
195 | | - for (let i = left + 1; i < padLength - 8; i++) { |
196 | | - this.buffer[i] = 0; |
197 | | - } |
198 | | - this.buffer[padLength - 8] = (bitLenHi >>> 24) & 0xff; |
199 | | - this.buffer[padLength - 7] = (bitLenHi >>> 16) & 0xff; |
200 | | - this.buffer[padLength - 6] = (bitLenHi >>> 8) & 0xff; |
201 | | - this.buffer[padLength - 5] = (bitLenHi >>> 0) & 0xff; |
202 | | - this.buffer[padLength - 4] = (bitLenLo >>> 24) & 0xff; |
203 | | - this.buffer[padLength - 3] = (bitLenLo >>> 16) & 0xff; |
204 | | - this.buffer[padLength - 2] = (bitLenLo >>> 8) & 0xff; |
205 | | - this.buffer[padLength - 1] = (bitLenLo >>> 0) & 0xff; |
206 | | - |
207 | | - hashBlocks(this.temp, this.state, this.buffer, 0, padLength); |
208 | | - |
209 | | - this.finished = true; |
210 | | - } |
211 | | - |
212 | | - for (let i = 0; i < 8; i++) { |
213 | | - out[i * 4 + 0] = (this.state[i] >>> 24) & 0xff; |
214 | | - out[i * 4 + 1] = (this.state[i] >>> 16) & 0xff; |
215 | | - out[i * 4 + 2] = (this.state[i] >>> 8) & 0xff; |
216 | | - out[i * 4 + 3] = (this.state[i] >>> 0) & 0xff; |
217 | | - } |
218 | | - |
219 | | - return this; |
220 | | - } |
221 | | - |
222 | | - // Returns the final hash digest. |
223 | | - digest(): Uint8Array { |
224 | | - const out = new Uint8Array(this.digestLength); |
225 | | - this.finish(out); |
226 | | - return out; |
227 | | - } |
228 | | - |
229 | | - // Internal function for use in HMAC for optimization. |
230 | | - _saveState(out: Uint32Array) { |
231 | | - for (let i = 0; i < this.state.length; i++) { |
232 | | - out[i] = this.state[i]; |
233 | | - } |
234 | | - } |
235 | | - |
236 | | - // Internal function for use in HMAC for optimization. |
237 | | - _restoreState(from: Uint32Array, bytesHashed: number) { |
238 | | - for (let i = 0; i < this.state.length; i++) { |
239 | | - this.state[i] = from[i]; |
240 | | - } |
241 | | - this.bytesHashed = bytesHashed; |
242 | | - this.finished = false; |
243 | | - this.bufferLength = 0; |
244 | | - } |
245 | | -} |
| 1 | +import * as sha2 from '@noble/hashes/sha2'; |
246 | 2 |
|
247 | 3 | export function sha256(data: Uint8Array): Uint8Array { |
248 | | - const h = new Hash().update(data); |
249 | | - const digest = h.digest(); |
250 | | - h.clean(); |
251 | | - return digest; |
| 4 | + return sha2.sha256(data); |
252 | 5 | } |
0 commit comments