1 | import {
|
2 | BLOCK_SIZE,
|
3 | DIGEST_LENGTH,
|
4 | INIT,
|
5 | KEY,
|
6 | MAX_HASHABLE_LENGTH
|
7 | } from "./constants";
|
8 |
|
9 |
|
10 |
|
11 |
|
12 | export class RawSha256 {
|
13 | private state: Int32Array = Int32Array.from(INIT);
|
14 | private temp: Int32Array = new Int32Array(64);
|
15 | private buffer: Uint8Array = new Uint8Array(64);
|
16 | private bufferLength: number = 0;
|
17 | private bytesHashed: number = 0;
|
18 |
|
19 | |
20 |
|
21 |
|
22 | finished: boolean = false;
|
23 |
|
24 | update(data: Uint8Array): void {
|
25 | if (this.finished) {
|
26 | throw new Error("Attempted to update an already finished hash.");
|
27 | }
|
28 |
|
29 | let position = 0;
|
30 | let { byteLength } = data;
|
31 | this.bytesHashed += byteLength;
|
32 |
|
33 | if (this.bytesHashed * 8 > MAX_HASHABLE_LENGTH) {
|
34 | throw new Error("Cannot hash more than 2^53 - 1 bits");
|
35 | }
|
36 |
|
37 | while (byteLength > 0) {
|
38 | this.buffer[this.bufferLength++] = data[position++];
|
39 | byteLength--;
|
40 |
|
41 | if (this.bufferLength === BLOCK_SIZE) {
|
42 | this.hashBuffer();
|
43 | this.bufferLength = 0;
|
44 | }
|
45 | }
|
46 | }
|
47 |
|
48 | digest(): Uint8Array {
|
49 | if (!this.finished) {
|
50 | const bitsHashed = this.bytesHashed * 8;
|
51 | const bufferView = new DataView(
|
52 | this.buffer.buffer,
|
53 | this.buffer.byteOffset,
|
54 | this.buffer.byteLength
|
55 | );
|
56 |
|
57 | const undecoratedLength = this.bufferLength;
|
58 | bufferView.setUint8(this.bufferLength++, 0x80);
|
59 |
|
60 |
|
61 | if (undecoratedLength % BLOCK_SIZE >= BLOCK_SIZE - 8) {
|
62 | for (let i = this.bufferLength; i < BLOCK_SIZE; i++) {
|
63 | bufferView.setUint8(i, 0);
|
64 | }
|
65 | this.hashBuffer();
|
66 | this.bufferLength = 0;
|
67 | }
|
68 |
|
69 | for (let i = this.bufferLength; i < BLOCK_SIZE - 8; i++) {
|
70 | bufferView.setUint8(i, 0);
|
71 | }
|
72 | bufferView.setUint32(
|
73 | BLOCK_SIZE - 8,
|
74 | Math.floor(bitsHashed / 0x100000000),
|
75 | true
|
76 | );
|
77 | bufferView.setUint32(BLOCK_SIZE - 4, bitsHashed);
|
78 |
|
79 | this.hashBuffer();
|
80 |
|
81 | this.finished = true;
|
82 | }
|
83 |
|
84 |
|
85 |
|
86 | const out = new Uint8Array(DIGEST_LENGTH);
|
87 | for (let i = 0; i < 8; i++) {
|
88 | out[i * 4] = (this.state[i] >>> 24) & 0xff;
|
89 | out[i * 4 + 1] = (this.state[i] >>> 16) & 0xff;
|
90 | out[i * 4 + 2] = (this.state[i] >>> 8) & 0xff;
|
91 | out[i * 4 + 3] = (this.state[i] >>> 0) & 0xff;
|
92 | }
|
93 |
|
94 | return out;
|
95 | }
|
96 |
|
97 | private hashBuffer(): void {
|
98 | const { buffer, state } = this;
|
99 |
|
100 | let state0 = state[0],
|
101 | state1 = state[1],
|
102 | state2 = state[2],
|
103 | state3 = state[3],
|
104 | state4 = state[4],
|
105 | state5 = state[5],
|
106 | state6 = state[6],
|
107 | state7 = state[7];
|
108 |
|
109 | for (let i = 0; i < BLOCK_SIZE; i++) {
|
110 | if (i < 16) {
|
111 | this.temp[i] =
|
112 | ((buffer[i * 4] & 0xff) << 24) |
|
113 | ((buffer[i * 4 + 1] & 0xff) << 16) |
|
114 | ((buffer[i * 4 + 2] & 0xff) << 8) |
|
115 | (buffer[i * 4 + 3] & 0xff);
|
116 | } else {
|
117 | let u = this.temp[i - 2];
|
118 | const t1 =
|
119 | ((u >>> 17) | (u << 15)) ^ ((u >>> 19) | (u << 13)) ^ (u >>> 10);
|
120 |
|
121 | u = this.temp[i - 15];
|
122 | const t2 =
|
123 | ((u >>> 7) | (u << 25)) ^ ((u >>> 18) | (u << 14)) ^ (u >>> 3);
|
124 |
|
125 | this.temp[i] =
|
126 | ((t1 + this.temp[i - 7]) | 0) + ((t2 + this.temp[i - 16]) | 0);
|
127 | }
|
128 |
|
129 | const t1 =
|
130 | ((((((state4 >>> 6) | (state4 << 26)) ^
|
131 | ((state4 >>> 11) | (state4 << 21)) ^
|
132 | ((state4 >>> 25) | (state4 << 7))) +
|
133 | ((state4 & state5) ^ (~state4 & state6))) |
|
134 | 0) +
|
135 | ((state7 + ((KEY[i] + this.temp[i]) | 0)) | 0)) |
|
136 | 0;
|
137 |
|
138 | const t2 =
|
139 | ((((state0 >>> 2) | (state0 << 30)) ^
|
140 | ((state0 >>> 13) | (state0 << 19)) ^
|
141 | ((state0 >>> 22) | (state0 << 10))) +
|
142 | ((state0 & state1) ^ (state0 & state2) ^ (state1 & state2))) |
|
143 | 0;
|
144 |
|
145 | state7 = state6;
|
146 | state6 = state5;
|
147 | state5 = state4;
|
148 | state4 = (state3 + t1) | 0;
|
149 | state3 = state2;
|
150 | state2 = state1;
|
151 | state1 = state0;
|
152 | state0 = (t1 + t2) | 0;
|
153 | }
|
154 |
|
155 | state[0] += state0;
|
156 | state[1] += state1;
|
157 | state[2] += state2;
|
158 | state[3] += state3;
|
159 | state[4] += state4;
|
160 | state[5] += state5;
|
161 | state[6] += state6;
|
162 | state[7] += state7;
|
163 | }
|
164 | }
|