@amritk/nish 0.12.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -23
- package/bin/launcher.js +45 -41
- package/bin/packaging.js +39 -33
- package/docs/AI.md +157 -35
- package/docs/INSTALL.md +13 -13
- package/llms.txt +1 -1
- package/package.json +9 -6
- package/runtime/nish.d.ts +85 -1
- package/runtime/nish.h +62 -11
- package/runtime/nish.mjs +38 -3
- package/runtime/runtime-host.c +178 -0
- package/runtime/{runtime_os.c → runtime-os.c} +16 -1
- package/runtime/{runtime_parallel.c → runtime-parallel.c} +112 -4
- package/runtime/{runtime_wasm.c → runtime-wasm.c} +6 -1
- package/runtime/runtime.c +5 -5
- package/runtime/shim.mjs +128 -6
- package/scripts/bootstrap.sh +29 -29
- package/scripts/build.sh +19 -13
- package/scripts/changelog-gen.mjs +260 -192
- package/scripts/ci-profile.mjs +80 -68
- package/scripts/codes-registry.js +25 -13
- package/scripts/gen-diagnostic-codes.mjs +124 -85
- package/scripts/nish-compiler.sh +2 -0
- package/scripts/platform-package.mjs +26 -26
- package/scripts/postinstall.mjs +46 -36
- package/scripts/size-report.sh +3 -3
- package/scripts/smoke.sh +1 -1
- package/std/README.md +42 -2
- package/std/collections.ts +194 -188
- package/std/crypto/base64url.ts +145 -0
- package/std/crypto/ct.ts +64 -0
- package/std/crypto/hkdf.ts +118 -0
- package/std/crypto/hmac.ts +155 -0
- package/std/crypto/sha256.ts +444 -0
- package/std/crypto/sha512.ts +510 -0
- package/std/crypto/x25519.ts +494 -0
- package/std/json.ts +136 -136
- package/std/map.ts +9 -7
- package/std/pair.ts +2 -2
- package/std/testing.ts +67 -67
- package/std/text.ts +54 -54
- package/std/threads.ts +126 -38
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `nish/crypto/sha256` — SHA-256 as FIPS 180-4 §6.2 defines it, in pure Nish.
|
|
3
|
+
*
|
|
4
|
+
* Two shapes, because they answer two different callers. `sha256(data)` is the
|
|
5
|
+
* one-shot form for a message that is already in one buffer. `Sha256` is the
|
|
6
|
+
* streaming form, and it exists for TLS 1.3: a handshake hashes its transcript
|
|
7
|
+
* as the messages arrive and needs the hash of the transcript *so far* at
|
|
8
|
+
* several points, which is what `copy()` is for — take a copy, digest the copy,
|
|
9
|
+
* and keep feeding the original.
|
|
10
|
+
*
|
|
11
|
+
* import { sha256, Sha256 } from "nish/crypto/sha256";
|
|
12
|
+
*
|
|
13
|
+
* const whole: u8[] = sha256(message);
|
|
14
|
+
*
|
|
15
|
+
* const h = new Sha256();
|
|
16
|
+
* h.update(first, 0, toI32(first.length));
|
|
17
|
+
* const soFar: u8[] = h.copy().digest();
|
|
18
|
+
* h.update(second, 0, toI32(second.length));
|
|
19
|
+
* const all: u8[] = h.digest();
|
|
20
|
+
*
|
|
21
|
+
* Input is a window `(buf, off, len)` over a `u8[]`, so a caller hashing one
|
|
22
|
+
* record out of a larger receive buffer does not copy it out first. A digest is
|
|
23
|
+
* always a fresh 32-byte `u8[]`.
|
|
24
|
+
*
|
|
25
|
+
* Every word is a `u32`, whose arithmetic is defined to wrap, so the additions
|
|
26
|
+
* modulo 2^32 that the specification asks for are plain `+` with no masking.
|
|
27
|
+
* Nothing here branches or indexes on the message: the only branches are on
|
|
28
|
+
* lengths and loop counters, which a hash does not keep secret.
|
|
29
|
+
*
|
|
30
|
+
* Written from the specification, not ported from another implementation.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/** The length of a digest in bytes (FIPS 180-4 §1, "Message Digest Size"). */
|
|
34
|
+
export const SHA256_SIZE: i32 = 32
|
|
35
|
+
|
|
36
|
+
/** The length of a message block in bytes (FIPS 180-4 §1, "Block Size"). */
|
|
37
|
+
export const SHA256_BLOCK: i32 = 64
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* The round constant K_t of FIPS 180-4 §4.2.2: the first 32 bits of the
|
|
41
|
+
* fractional parts of the cube roots of the first sixty-four primes.
|
|
42
|
+
*
|
|
43
|
+
* A function over a `switch` rather than a table, because a module constant
|
|
44
|
+
* cannot be an array ([LANGUAGE.md](../../docs/LANGUAGE.md#module-constants))
|
|
45
|
+
* and building one per hasher would be sixty-four stores for every `new`. LLVM's
|
|
46
|
+
* code generator turns a `switch` whose every arm returns a constant into a
|
|
47
|
+
* read-only lookup table, so in the binary this is one load. `t` is the round
|
|
48
|
+
* number, never message data.
|
|
49
|
+
*/
|
|
50
|
+
const sha256RoundConstant = (t: i32): u32 => {
|
|
51
|
+
switch (t) {
|
|
52
|
+
case 0:
|
|
53
|
+
return 0x428a2f98
|
|
54
|
+
case 1:
|
|
55
|
+
return 0x71374491
|
|
56
|
+
case 2:
|
|
57
|
+
return 0xb5c0fbcf
|
|
58
|
+
case 3:
|
|
59
|
+
return 0xe9b5dba5
|
|
60
|
+
case 4:
|
|
61
|
+
return 0x3956c25b
|
|
62
|
+
case 5:
|
|
63
|
+
return 0x59f111f1
|
|
64
|
+
case 6:
|
|
65
|
+
return 0x923f82a4
|
|
66
|
+
case 7:
|
|
67
|
+
return 0xab1c5ed5
|
|
68
|
+
case 8:
|
|
69
|
+
return 0xd807aa98
|
|
70
|
+
case 9:
|
|
71
|
+
return 0x12835b01
|
|
72
|
+
case 10:
|
|
73
|
+
return 0x243185be
|
|
74
|
+
case 11:
|
|
75
|
+
return 0x550c7dc3
|
|
76
|
+
case 12:
|
|
77
|
+
return 0x72be5d74
|
|
78
|
+
case 13:
|
|
79
|
+
return 0x80deb1fe
|
|
80
|
+
case 14:
|
|
81
|
+
return 0x9bdc06a7
|
|
82
|
+
case 15:
|
|
83
|
+
return 0xc19bf174
|
|
84
|
+
case 16:
|
|
85
|
+
return 0xe49b69c1
|
|
86
|
+
case 17:
|
|
87
|
+
return 0xefbe4786
|
|
88
|
+
case 18:
|
|
89
|
+
return 0x0fc19dc6
|
|
90
|
+
case 19:
|
|
91
|
+
return 0x240ca1cc
|
|
92
|
+
case 20:
|
|
93
|
+
return 0x2de92c6f
|
|
94
|
+
case 21:
|
|
95
|
+
return 0x4a7484aa
|
|
96
|
+
case 22:
|
|
97
|
+
return 0x5cb0a9dc
|
|
98
|
+
case 23:
|
|
99
|
+
return 0x76f988da
|
|
100
|
+
case 24:
|
|
101
|
+
return 0x983e5152
|
|
102
|
+
case 25:
|
|
103
|
+
return 0xa831c66d
|
|
104
|
+
case 26:
|
|
105
|
+
return 0xb00327c8
|
|
106
|
+
case 27:
|
|
107
|
+
return 0xbf597fc7
|
|
108
|
+
case 28:
|
|
109
|
+
return 0xc6e00bf3
|
|
110
|
+
case 29:
|
|
111
|
+
return 0xd5a79147
|
|
112
|
+
case 30:
|
|
113
|
+
return 0x06ca6351
|
|
114
|
+
case 31:
|
|
115
|
+
return 0x14292967
|
|
116
|
+
case 32:
|
|
117
|
+
return 0x27b70a85
|
|
118
|
+
case 33:
|
|
119
|
+
return 0x2e1b2138
|
|
120
|
+
case 34:
|
|
121
|
+
return 0x4d2c6dfc
|
|
122
|
+
case 35:
|
|
123
|
+
return 0x53380d13
|
|
124
|
+
case 36:
|
|
125
|
+
return 0x650a7354
|
|
126
|
+
case 37:
|
|
127
|
+
return 0x766a0abb
|
|
128
|
+
case 38:
|
|
129
|
+
return 0x81c2c92e
|
|
130
|
+
case 39:
|
|
131
|
+
return 0x92722c85
|
|
132
|
+
case 40:
|
|
133
|
+
return 0xa2bfe8a1
|
|
134
|
+
case 41:
|
|
135
|
+
return 0xa81a664b
|
|
136
|
+
case 42:
|
|
137
|
+
return 0xc24b8b70
|
|
138
|
+
case 43:
|
|
139
|
+
return 0xc76c51a3
|
|
140
|
+
case 44:
|
|
141
|
+
return 0xd192e819
|
|
142
|
+
case 45:
|
|
143
|
+
return 0xd6990624
|
|
144
|
+
case 46:
|
|
145
|
+
return 0xf40e3585
|
|
146
|
+
case 47:
|
|
147
|
+
return 0x106aa070
|
|
148
|
+
case 48:
|
|
149
|
+
return 0x19a4c116
|
|
150
|
+
case 49:
|
|
151
|
+
return 0x1e376c08
|
|
152
|
+
case 50:
|
|
153
|
+
return 0x2748774c
|
|
154
|
+
case 51:
|
|
155
|
+
return 0x34b0bcb5
|
|
156
|
+
case 52:
|
|
157
|
+
return 0x391c0cb3
|
|
158
|
+
case 53:
|
|
159
|
+
return 0x4ed8aa4a
|
|
160
|
+
case 54:
|
|
161
|
+
return 0x5b9cca4f
|
|
162
|
+
case 55:
|
|
163
|
+
return 0x682e6ff3
|
|
164
|
+
case 56:
|
|
165
|
+
return 0x748f82ee
|
|
166
|
+
case 57:
|
|
167
|
+
return 0x78a5636f
|
|
168
|
+
case 58:
|
|
169
|
+
return 0x84c87814
|
|
170
|
+
case 59:
|
|
171
|
+
return 0x8cc70208
|
|
172
|
+
case 60:
|
|
173
|
+
return 0x90befffa
|
|
174
|
+
case 61:
|
|
175
|
+
return 0xa4506ceb
|
|
176
|
+
case 62:
|
|
177
|
+
return 0xbef9a3f7
|
|
178
|
+
case 63:
|
|
179
|
+
return 0xc67178f2
|
|
180
|
+
// Unreachable: `t` is a round number, 0 to 63. A `default` of its own
|
|
181
|
+
// keeps K_63 inside the table, so the lookup needs no range test first.
|
|
182
|
+
default:
|
|
183
|
+
return 0
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/** ROTR^n(x) of FIPS 180-4 §3.2: a right rotation of a 32-bit word, `0 < n < 32`. */
|
|
188
|
+
const sha256Rotr = (x: u32, n: u32): u32 => (x >>> n) | (x << (32 - n))
|
|
189
|
+
|
|
190
|
+
/** The big-endian word at `buf[at .. at + 4)`, as FIPS 180-4 §3.1 orders bytes in a word. */
|
|
191
|
+
const sha256LoadWord = (buf: u8[], at: i32): u32 =>
|
|
192
|
+
(toU32(buf[at]) << 24) | (toU32(buf[at + 1]) << 16) | (toU32(buf[at + 2]) << 8) | toU32(buf[at + 3])
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Copies `from[fromAt .. fromAt + n)` to `to[toAt .. toAt + n)`. Every caller
|
|
196
|
+
* has already checked both windows, so the indices here are in range; they
|
|
197
|
+
* are computed from `k` so the loop has one counter.
|
|
198
|
+
*/
|
|
199
|
+
const sha256CopyBytes = (from: u8[], fromAt: i32, to: u8[], toAt: i32, n: i32): void => {
|
|
200
|
+
for (let k: i32 = 0; k < n; k += 1) {
|
|
201
|
+
to[toAt + k] = from[fromAt + k]
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Folds the 64-byte block at `src[at .. at + 64)` into the hash value `h`: the
|
|
207
|
+
* computation of FIPS 180-4 §6.2.2, steps 1 to 4, for one block. `w` is the
|
|
208
|
+
* 64-word message schedule, passed in so that it is allocated once per hasher.
|
|
209
|
+
*
|
|
210
|
+
* A function over the arrays rather than a method, so that each array is a
|
|
211
|
+
* plain local whose length the guard below proves once for every loop.
|
|
212
|
+
*/
|
|
213
|
+
const sha256Compress = (h: u32[], w: u32[], src: u8[], at: i32): void => {
|
|
214
|
+
// The test is written as the condition the body runs under, not as an
|
|
215
|
+
// early exit, because that is the shape that proves the plain `w[t]` and
|
|
216
|
+
// `h[i]` indices in range and drops their bounds checks. The computed ones —
|
|
217
|
+
// the byte reads in `sha256LoadWord` and `w[t - 2]` and its kin — keep a
|
|
218
|
+
// check each; measured, removing every check with `--unchecked-indexing`
|
|
219
|
+
// moved the 1 MiB time by less than the run-to-run noise.
|
|
220
|
+
if (toI32(h.length) >= 8 && toI32(w.length) >= 64 && at >= 0 && at <= toI32(src.length) - SHA256_BLOCK) {
|
|
221
|
+
// Step 1: the message schedule.
|
|
222
|
+
for (let t: i32 = 0; t < 16; t += 1) {
|
|
223
|
+
w[t] = sha256LoadWord(src, at + 4 * t)
|
|
224
|
+
}
|
|
225
|
+
for (let t: i32 = 16; t < 64; t += 1) {
|
|
226
|
+
const w2: u32 = w[t - 2]
|
|
227
|
+
const w15: u32 = w[t - 15]
|
|
228
|
+
// σ1 and σ0 of §4.1.2, (4.7) and (4.6).
|
|
229
|
+
const sigma1: u32 = sha256Rotr(w2, 17) ^ sha256Rotr(w2, 19) ^ (w2 >>> 10)
|
|
230
|
+
const sigma0: u32 = sha256Rotr(w15, 7) ^ sha256Rotr(w15, 18) ^ (w15 >>> 3)
|
|
231
|
+
w[t] = sigma1 + w[t - 7] + sigma0 + w[t - 16]
|
|
232
|
+
}
|
|
233
|
+
// Step 2: the working variables start from the previous hash value.
|
|
234
|
+
let a: u32 = h[0]
|
|
235
|
+
let b: u32 = h[1]
|
|
236
|
+
let c: u32 = h[2]
|
|
237
|
+
let d: u32 = h[3]
|
|
238
|
+
let e: u32 = h[4]
|
|
239
|
+
let f: u32 = h[5]
|
|
240
|
+
let g: u32 = h[6]
|
|
241
|
+
let hh: u32 = h[7]
|
|
242
|
+
// Step 3: sixty-four rounds.
|
|
243
|
+
for (let t: i32 = 0; t < 64; t += 1) {
|
|
244
|
+
// Σ1 (4.5), Ch (4.2), Σ0 (4.4) and Maj (4.3) of §4.1.2.
|
|
245
|
+
const bigSigma1: u32 = sha256Rotr(e, 6) ^ sha256Rotr(e, 11) ^ sha256Rotr(e, 25)
|
|
246
|
+
const choose: u32 = (e & f) ^ (~e & g)
|
|
247
|
+
const t1: u32 = hh + bigSigma1 + choose + sha256RoundConstant(t) + w[t]
|
|
248
|
+
const bigSigma0: u32 = sha256Rotr(a, 2) ^ sha256Rotr(a, 13) ^ sha256Rotr(a, 22)
|
|
249
|
+
const majority: u32 = (a & b) ^ (a & c) ^ (b & c)
|
|
250
|
+
const t2: u32 = bigSigma0 + majority
|
|
251
|
+
hh = g
|
|
252
|
+
g = f
|
|
253
|
+
f = e
|
|
254
|
+
e = d + t1
|
|
255
|
+
d = c
|
|
256
|
+
c = b
|
|
257
|
+
b = a
|
|
258
|
+
a = t1 + t2
|
|
259
|
+
}
|
|
260
|
+
// Step 4: the next intermediate hash value.
|
|
261
|
+
h[0] += a
|
|
262
|
+
h[1] += b
|
|
263
|
+
h[2] += c
|
|
264
|
+
h[3] += d
|
|
265
|
+
h[4] += e
|
|
266
|
+
h[5] += f
|
|
267
|
+
h[6] += g
|
|
268
|
+
h[7] += hh
|
|
269
|
+
} else {
|
|
270
|
+
panic("Sha256: a block outside its buffer")
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* A SHA-256 computation in progress: the hash value H of FIPS 180-4 §6.2 after
|
|
276
|
+
* every whole block absorbed so far, and the bytes of the block not yet whole.
|
|
277
|
+
*
|
|
278
|
+
* `update` may be called any number of times with windows of any length, and
|
|
279
|
+
* the digest does not depend on where the message was split. `digest` pads the
|
|
280
|
+
* message (§5.1.1), runs the last block or two, and ends the computation: the
|
|
281
|
+
* padding is written into this hasher's own state, so a second `digest`, a
|
|
282
|
+
* later `update` or a `copy` would carry the padding as message, and all three
|
|
283
|
+
* panic instead of answering a wrong value. `copy` first when the computation
|
|
284
|
+
* has to go on.
|
|
285
|
+
*/
|
|
286
|
+
export class Sha256 {
|
|
287
|
+
/**
|
|
288
|
+
* The message length absorbed so far, in bytes. An `i64` because §5.1.1
|
|
289
|
+
* appends the length in bits as a 64-bit number, and a transcript can pass
|
|
290
|
+
* 2^31 bytes where an `i32` would wrap.
|
|
291
|
+
*/
|
|
292
|
+
total: i64 = 0
|
|
293
|
+
/** H_0 .. H_7, the eight words of the intermediate hash value (§6.2.2 step 4). */
|
|
294
|
+
state: u32[]
|
|
295
|
+
/** The pending bytes of the current block; the first `fill` of them are live. */
|
|
296
|
+
block: u8[]
|
|
297
|
+
/**
|
|
298
|
+
* W_0 .. W_63, the message schedule of §6.2.2 step 1. It carries nothing from
|
|
299
|
+
* one block to the next and is a field only so that a long message allocates
|
|
300
|
+
* it once rather than once per block.
|
|
301
|
+
*/
|
|
302
|
+
schedule: u32[]
|
|
303
|
+
/** How many bytes of `block` are live, always below `SHA256_BLOCK` between calls. */
|
|
304
|
+
fill: i32 = 0
|
|
305
|
+
finished: boolean = false
|
|
306
|
+
|
|
307
|
+
constructor() {
|
|
308
|
+
// H^(0) of FIPS 180-4 §5.3.3: the first 32 bits of the fractional parts
|
|
309
|
+
// of the square roots of the first eight primes.
|
|
310
|
+
const h: u32[] = new Array<u32>(8)
|
|
311
|
+
h[0] = 0x6a09e667
|
|
312
|
+
h[1] = 0xbb67ae85
|
|
313
|
+
h[2] = 0x3c6ef372
|
|
314
|
+
h[3] = 0xa54ff53a
|
|
315
|
+
h[4] = 0x510e527f
|
|
316
|
+
h[5] = 0x9b05688c
|
|
317
|
+
h[6] = 0x1f83d9ab
|
|
318
|
+
h[7] = 0x5be0cd19
|
|
319
|
+
this.state = h
|
|
320
|
+
this.block = new Array<u8>(SHA256_BLOCK)
|
|
321
|
+
this.schedule = new Array<u32>(64)
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Absorbs `data[off .. off + len)`. A window outside `data` panics rather
|
|
326
|
+
* than hashing a short read, since a digest over the wrong bytes looks
|
|
327
|
+
* exactly like a digest over the right ones.
|
|
328
|
+
*/
|
|
329
|
+
update(data: u8[], off: i32, len: i32): void {
|
|
330
|
+
if (this.finished) {
|
|
331
|
+
panic("Sha256: update after digest")
|
|
332
|
+
}
|
|
333
|
+
const size: i32 = toI32(data.length)
|
|
334
|
+
if (off < 0 || len < 0 || off > size || len > size - off) {
|
|
335
|
+
panic("Sha256: the window is outside the buffer")
|
|
336
|
+
}
|
|
337
|
+
this.total += toI64(len)
|
|
338
|
+
let at: i32 = off
|
|
339
|
+
const end: i32 = off + len
|
|
340
|
+
const block: u8[] = this.block
|
|
341
|
+
// Top up a partly filled block first, so that the loop below only ever
|
|
342
|
+
// starts at a block boundary.
|
|
343
|
+
if (this.fill > 0) {
|
|
344
|
+
const room: i32 = SHA256_BLOCK - this.fill
|
|
345
|
+
const take: i32 = len < room ? len : room
|
|
346
|
+
sha256CopyBytes(data, at, block, this.fill, take)
|
|
347
|
+
at += take
|
|
348
|
+
this.fill += take
|
|
349
|
+
if (this.fill < SHA256_BLOCK) {
|
|
350
|
+
return
|
|
351
|
+
}
|
|
352
|
+
sha256Compress(this.state, this.schedule, block, 0)
|
|
353
|
+
this.fill = 0
|
|
354
|
+
}
|
|
355
|
+
// Whole blocks are compressed straight out of the caller's buffer, with no
|
|
356
|
+
// copy through `block`.
|
|
357
|
+
while (end - at >= SHA256_BLOCK) {
|
|
358
|
+
sha256Compress(this.state, this.schedule, data, at)
|
|
359
|
+
at += SHA256_BLOCK
|
|
360
|
+
}
|
|
361
|
+
sha256CopyBytes(data, at, block, 0, end - at)
|
|
362
|
+
this.fill = end - at
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* An independent hasher at the same point in the same message: updating or
|
|
367
|
+
* digesting either one leaves the other as it was. This is how a caller
|
|
368
|
+
* takes the hash of a prefix and keeps going.
|
|
369
|
+
*/
|
|
370
|
+
copy(): Sha256 {
|
|
371
|
+
if (this.finished) {
|
|
372
|
+
panic("Sha256: copy after digest")
|
|
373
|
+
}
|
|
374
|
+
const twin: Sha256 = new Sha256()
|
|
375
|
+
const fromState: u32[] = this.state
|
|
376
|
+
const toState: u32[] = twin.state
|
|
377
|
+
// Both are always eight words; the test is what proves the indices below
|
|
378
|
+
// in range, as it does in `sha256Compress`.
|
|
379
|
+
if (toI32(fromState.length) >= 8 && toI32(toState.length) >= 8) {
|
|
380
|
+
for (let i: i32 = 0; i < 8; i += 1) {
|
|
381
|
+
toState[i] = fromState[i]
|
|
382
|
+
}
|
|
383
|
+
} else {
|
|
384
|
+
panic("Sha256: a hash value that is not eight words")
|
|
385
|
+
}
|
|
386
|
+
sha256CopyBytes(this.block, 0, twin.block, 0, this.fill)
|
|
387
|
+
twin.fill = this.fill
|
|
388
|
+
twin.total = this.total
|
|
389
|
+
return twin
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* The 32-byte message digest (FIPS 180-4 §6.2.2, the final H^(N) in
|
|
394
|
+
* big-endian order), in a fresh array. Ends the computation.
|
|
395
|
+
*/
|
|
396
|
+
digest(): u8[] {
|
|
397
|
+
if (this.finished) {
|
|
398
|
+
panic("Sha256: digest called twice")
|
|
399
|
+
}
|
|
400
|
+
this.finished = true
|
|
401
|
+
// §5.1.1: a single 1 bit, then zeros up to 56 bytes into a block, then the
|
|
402
|
+
// message length in bits as a big-endian 64-bit number. When fewer than
|
|
403
|
+
// eight bytes are left after the 1 bit, the zeros run into a second block.
|
|
404
|
+
// `block` is zero past `fill` only in a fresh hasher, so every zero is
|
|
405
|
+
// written rather than assumed.
|
|
406
|
+
const block: u8[] = this.block
|
|
407
|
+
const blockEnd: i32 = toI32(block.length)
|
|
408
|
+
const fill: i32 = this.fill
|
|
409
|
+
block[fill] = 0x80
|
|
410
|
+
for (let i: i32 = fill + 1; i < blockEnd; i += 1) {
|
|
411
|
+
block[i] = 0
|
|
412
|
+
}
|
|
413
|
+
if (fill >= SHA256_BLOCK - 8) {
|
|
414
|
+
sha256Compress(this.state, this.schedule, block, 0)
|
|
415
|
+
for (let i: i32 = 0; i < blockEnd; i += 1) {
|
|
416
|
+
block[i] = 0
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
const bits: u64 = toU64(this.total) << 3
|
|
420
|
+
for (let i: i32 = 0; i < 8; i += 1) {
|
|
421
|
+
block[SHA256_BLOCK - 1 - i] = toU8(bits >>> toU64(8 * i))
|
|
422
|
+
}
|
|
423
|
+
sha256Compress(this.state, this.schedule, block, 0)
|
|
424
|
+
const out: u8[] = new Array<u8>(SHA256_SIZE)
|
|
425
|
+
const state: u32[] = this.state
|
|
426
|
+
const words: i32 = toI32(state.length)
|
|
427
|
+
for (let i: i32 = 0; i < words; i += 1) {
|
|
428
|
+
const word: u32 = state[i]
|
|
429
|
+
out[4 * i] = toU8(word >>> 24)
|
|
430
|
+
out[4 * i + 1] = toU8(word >>> 16)
|
|
431
|
+
out[4 * i + 2] = toU8(word >>> 8)
|
|
432
|
+
out[4 * i + 3] = toU8(word)
|
|
433
|
+
}
|
|
434
|
+
return out
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/** The SHA-256 digest of all of `data`, as a fresh 32-byte array. */
|
|
439
|
+
export const sha256 = (data: u8[]): u8[] => {
|
|
440
|
+
const hasher: Sha256 = new Sha256()
|
|
441
|
+
const from: i32 = 0
|
|
442
|
+
hasher.update(data, from, toI32(data.length))
|
|
443
|
+
return hasher.digest()
|
|
444
|
+
}
|