@amritk/nish-x86_64-linux 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.
@@ -0,0 +1,510 @@
1
+ /**
2
+ * `nish/crypto/sha512` — SHA-512 and SHA-384, written from FIPS 180-4.
3
+ *
4
+ * Both hashes are one compression function over eight 64-bit words: SHA-384
5
+ * starts from its own initial value (§5.3.4) and keeps the first 48 bytes of
6
+ * the result (§6.5), SHA-512 starts from §5.3.5 and keeps all 64. So one
7
+ * engine does the work, and `Sha512` and `Sha384` are the two ways to start it.
8
+ *
9
+ * A hasher streams: `update` any number of windows, `copy` to take an
10
+ * independent hasher at the same point (TLS 1.3 hashes its transcript and
11
+ * reads intermediate hashes of it), then `digest` once. The work depends on how
12
+ * many bytes arrive and never on their values: there is no branch and no table
13
+ * index on message data, so a secret message (an HMAC key, a transcript) is
14
+ * hashed in time that says nothing about it but its length.
15
+ *
16
+ * The constants are the fractional parts of the cube roots of the first eighty
17
+ * primes (§4.2.3) and of the square roots of the first sixteen (§5.3.4, §5.3.5),
18
+ * as FIPS 180-4 defines them. A literal past 2^53 cannot be written exactly, so
19
+ * each is spelled as its two 32-bit halves.
20
+ */
21
+
22
+ /** The length of a SHA-512 digest, in bytes. */
23
+ export const SHA512_SIZE: i32 = 64
24
+ /** The length of a SHA-384 digest, in bytes. */
25
+ export const SHA384_SIZE: i32 = 48
26
+ /** The block both hashes compress, in bytes. */
27
+ export const SHA512_BLOCK: i32 = 128
28
+
29
+ /** The block offset at which padding writes the 128-bit message length (§5.1.2). */
30
+ const LENGTH_AT: i32 = 112
31
+
32
+ /** SHA-512's rounds per block, and so the length of its message schedule (§6.4.2). */
33
+ const ROUNDS: i32 = 80
34
+
35
+ /** Offset zero, spelled as an `i32` so a method argument keeps that type in f64 mode (`reject_method_arg_literal`). */
36
+ const OFFSET_ZERO: i32 = 0
37
+
38
+ const w64 = (hi: u32, lo: u32): u64 => (toU64(hi) << 32) | toU64(lo)
39
+
40
+ /** ROTR^n (§3.2), for 0 < n < 64. */
41
+ const rotr = (x: u64, n: u64): u64 => (x >> n) | (x << (64 - n))
42
+
43
+ // The four functions of §4.1.3.
44
+ const bigSigma0 = (x: u64): u64 => rotr(x, 28) ^ rotr(x, 34) ^ rotr(x, 39)
45
+ const bigSigma1 = (x: u64): u64 => rotr(x, 14) ^ rotr(x, 18) ^ rotr(x, 41)
46
+ const smallSigma0 = (x: u64): u64 => rotr(x, 1) ^ rotr(x, 8) ^ (x >> 7)
47
+ const smallSigma1 = (x: u64): u64 => rotr(x, 19) ^ rotr(x, 61) ^ (x >> 6)
48
+
49
+ /**
50
+ * K{512}_t (§4.2.3): the first 64 bits of the fractional parts of the cube
51
+ * roots of the first eighty primes.
52
+ *
53
+ * A function over a `switch` rather than an array, because a module constant
54
+ * cannot be an array and building one per hasher costs eighty stores on every
55
+ * `new` and every `copy()`. Every arm is a constant once `w64` folds, and LLVM
56
+ * turns such a `switch` into one read-only table, so a round reads K with one
57
+ * load. `t` is the round number, never message data.
58
+ */
59
+ const roundConstant = (t: i32): u64 => {
60
+ switch (t) {
61
+ case 0:
62
+ return w64(0x428a2f98, 0xd728ae22)
63
+ case 1:
64
+ return w64(0x71374491, 0x23ef65cd)
65
+ case 2:
66
+ return w64(0xb5c0fbcf, 0xec4d3b2f)
67
+ case 3:
68
+ return w64(0xe9b5dba5, 0x8189dbbc)
69
+ case 4:
70
+ return w64(0x3956c25b, 0xf348b538)
71
+ case 5:
72
+ return w64(0x59f111f1, 0xb605d019)
73
+ case 6:
74
+ return w64(0x923f82a4, 0xaf194f9b)
75
+ case 7:
76
+ return w64(0xab1c5ed5, 0xda6d8118)
77
+ case 8:
78
+ return w64(0xd807aa98, 0xa3030242)
79
+ case 9:
80
+ return w64(0x12835b01, 0x45706fbe)
81
+ case 10:
82
+ return w64(0x243185be, 0x4ee4b28c)
83
+ case 11:
84
+ return w64(0x550c7dc3, 0xd5ffb4e2)
85
+ case 12:
86
+ return w64(0x72be5d74, 0xf27b896f)
87
+ case 13:
88
+ return w64(0x80deb1fe, 0x3b1696b1)
89
+ case 14:
90
+ return w64(0x9bdc06a7, 0x25c71235)
91
+ case 15:
92
+ return w64(0xc19bf174, 0xcf692694)
93
+ case 16:
94
+ return w64(0xe49b69c1, 0x9ef14ad2)
95
+ case 17:
96
+ return w64(0xefbe4786, 0x384f25e3)
97
+ case 18:
98
+ return w64(0x0fc19dc6, 0x8b8cd5b5)
99
+ case 19:
100
+ return w64(0x240ca1cc, 0x77ac9c65)
101
+ case 20:
102
+ return w64(0x2de92c6f, 0x592b0275)
103
+ case 21:
104
+ return w64(0x4a7484aa, 0x6ea6e483)
105
+ case 22:
106
+ return w64(0x5cb0a9dc, 0xbd41fbd4)
107
+ case 23:
108
+ return w64(0x76f988da, 0x831153b5)
109
+ case 24:
110
+ return w64(0x983e5152, 0xee66dfab)
111
+ case 25:
112
+ return w64(0xa831c66d, 0x2db43210)
113
+ case 26:
114
+ return w64(0xb00327c8, 0x98fb213f)
115
+ case 27:
116
+ return w64(0xbf597fc7, 0xbeef0ee4)
117
+ case 28:
118
+ return w64(0xc6e00bf3, 0x3da88fc2)
119
+ case 29:
120
+ return w64(0xd5a79147, 0x930aa725)
121
+ case 30:
122
+ return w64(0x06ca6351, 0xe003826f)
123
+ case 31:
124
+ return w64(0x14292967, 0x0a0e6e70)
125
+ case 32:
126
+ return w64(0x27b70a85, 0x46d22ffc)
127
+ case 33:
128
+ return w64(0x2e1b2138, 0x5c26c926)
129
+ case 34:
130
+ return w64(0x4d2c6dfc, 0x5ac42aed)
131
+ case 35:
132
+ return w64(0x53380d13, 0x9d95b3df)
133
+ case 36:
134
+ return w64(0x650a7354, 0x8baf63de)
135
+ case 37:
136
+ return w64(0x766a0abb, 0x3c77b2a8)
137
+ case 38:
138
+ return w64(0x81c2c92e, 0x47edaee6)
139
+ case 39:
140
+ return w64(0x92722c85, 0x1482353b)
141
+ case 40:
142
+ return w64(0xa2bfe8a1, 0x4cf10364)
143
+ case 41:
144
+ return w64(0xa81a664b, 0xbc423001)
145
+ case 42:
146
+ return w64(0xc24b8b70, 0xd0f89791)
147
+ case 43:
148
+ return w64(0xc76c51a3, 0x0654be30)
149
+ case 44:
150
+ return w64(0xd192e819, 0xd6ef5218)
151
+ case 45:
152
+ return w64(0xd6990624, 0x5565a910)
153
+ case 46:
154
+ return w64(0xf40e3585, 0x5771202a)
155
+ case 47:
156
+ return w64(0x106aa070, 0x32bbd1b8)
157
+ case 48:
158
+ return w64(0x19a4c116, 0xb8d2d0c8)
159
+ case 49:
160
+ return w64(0x1e376c08, 0x5141ab53)
161
+ case 50:
162
+ return w64(0x2748774c, 0xdf8eeb99)
163
+ case 51:
164
+ return w64(0x34b0bcb5, 0xe19b48a8)
165
+ case 52:
166
+ return w64(0x391c0cb3, 0xc5c95a63)
167
+ case 53:
168
+ return w64(0x4ed8aa4a, 0xe3418acb)
169
+ case 54:
170
+ return w64(0x5b9cca4f, 0x7763e373)
171
+ case 55:
172
+ return w64(0x682e6ff3, 0xd6b2b8a3)
173
+ case 56:
174
+ return w64(0x748f82ee, 0x5defb2fc)
175
+ case 57:
176
+ return w64(0x78a5636f, 0x43172f60)
177
+ case 58:
178
+ return w64(0x84c87814, 0xa1f0ab72)
179
+ case 59:
180
+ return w64(0x8cc70208, 0x1a6439ec)
181
+ case 60:
182
+ return w64(0x90befffa, 0x23631e28)
183
+ case 61:
184
+ return w64(0xa4506ceb, 0xde82bde9)
185
+ case 62:
186
+ return w64(0xbef9a3f7, 0xb2c67915)
187
+ case 63:
188
+ return w64(0xc67178f2, 0xe372532b)
189
+ case 64:
190
+ return w64(0xca273ece, 0xea26619c)
191
+ case 65:
192
+ return w64(0xd186b8c7, 0x21c0c207)
193
+ case 66:
194
+ return w64(0xeada7dd6, 0xcde0eb1e)
195
+ case 67:
196
+ return w64(0xf57d4f7f, 0xee6ed178)
197
+ case 68:
198
+ return w64(0x06f067aa, 0x72176fba)
199
+ case 69:
200
+ return w64(0x0a637dc5, 0xa2c898a6)
201
+ case 70:
202
+ return w64(0x113f9804, 0xbef90dae)
203
+ case 71:
204
+ return w64(0x1b710b35, 0x131c471b)
205
+ case 72:
206
+ return w64(0x28db77f5, 0x23047d84)
207
+ case 73:
208
+ return w64(0x32caab7b, 0x40c72493)
209
+ case 74:
210
+ return w64(0x3c9ebe0a, 0x15c9bebc)
211
+ case 75:
212
+ return w64(0x431d67c4, 0x9c100d4c)
213
+ case 76:
214
+ return w64(0x4cc5d4be, 0xcb3e42b6)
215
+ case 77:
216
+ return w64(0x597f299c, 0xfc657e2a)
217
+ case 78:
218
+ return w64(0x5fcb6fab, 0x3ad6faec)
219
+ case 79:
220
+ return w64(0x6c44198c, 0x4a475817)
221
+ // Unreachable: `t` is a round number, 0 to 79. A `default` of its own
222
+ // keeps K_79 inside the table, so the lookup needs no range test first.
223
+ default:
224
+ return 0
225
+ }
226
+ }
227
+
228
+ /** H(0) for SHA-512 (§5.3.5). */
229
+ const sha512Initial = (): u64[] => [
230
+ w64(0x6a09e667, 0xf3bcc908),
231
+ w64(0xbb67ae85, 0x84caa73b),
232
+ w64(0x3c6ef372, 0xfe94f82b),
233
+ w64(0xa54ff53a, 0x5f1d36f1),
234
+ w64(0x510e527f, 0xade682d1),
235
+ w64(0x9b05688c, 0x2b3e6c1f),
236
+ w64(0x1f83d9ab, 0xfb41bd6b),
237
+ w64(0x5be0cd19, 0x137e2179),
238
+ ]
239
+
240
+ /** H(0) for SHA-384 (§5.3.4). */
241
+ const sha384Initial = (): u64[] => [
242
+ w64(0xcbbb9d5d, 0xc1059ed8),
243
+ w64(0x629a292a, 0x367cd507),
244
+ w64(0x9159015a, 0x3070dd17),
245
+ w64(0x152fecd8, 0xf70e5939),
246
+ w64(0x67332667, 0xffc00b31),
247
+ w64(0x8eb44a87, 0x68581511),
248
+ w64(0xdb0c2e0d, 0x64f98fa7),
249
+ w64(0x47b5481d, 0xbefa4fa4),
250
+ ]
251
+
252
+ /** The big-endian 64-bit word at `buf[off]`. */
253
+ const loadWord = (buf: u8[], off: i32): u64 => {
254
+ let word: u64 = 0
255
+ for (let i: i32 = 0; i < 8; i++) {
256
+ word = (word << 8) | toU64(buf[off + i])
257
+ }
258
+ return word
259
+ }
260
+
261
+ /** Writes `word` big-endian into `buf[off]` .. `buf[off + 7]`. */
262
+ const storeWord = (buf: u8[], off: i32, word: u64): void => {
263
+ for (let i: i32 = 0; i < 8; i++) {
264
+ buf[off + i] = toU8(word >> toU64((7 - i) * 8))
265
+ }
266
+ }
267
+
268
+ /**
269
+ * The state both hashes share: the hash value, the partial block, and the
270
+ * message length in bytes. §5.1.2 appends the length in bits as 128 bits; a
271
+ * byte count in a `u64` shifted left by three fills those 128 bits for any
272
+ * message shorter than 2^64 bytes, which is every message there can be.
273
+ */
274
+ class Sha512Engine {
275
+ state: u64[]
276
+ block: u8[]
277
+ /** The message schedule W_0 .. W_79, kept so a block allocates nothing. */
278
+ schedule: u64[]
279
+ count: u64 = 0
280
+ filled: i32 = 0
281
+ finished: boolean = false
282
+
283
+ constructor(initial: u64[]) {
284
+ this.state = initial
285
+ this.block = new Array<u8>(SHA512_BLOCK)
286
+ this.schedule = new Array<u64>(ROUNDS)
287
+ }
288
+
289
+ /** One application of §6.4.2 to the block at `src[off]` .. `src[off + 127]`. */
290
+ compress(src: u8[], off: i32): void {
291
+ const w = this.schedule
292
+ const h = this.state
293
+ const wLen: i32 = toI32(w.length)
294
+ for (let t: i32 = 0; t < 16 && t < wLen; t++) {
295
+ w[t] = loadWord(src, off + 8 * t)
296
+ }
297
+ for (let t: i32 = 16; t < wLen; t++) {
298
+ // Named offsets rather than `w[t - 2]`, so the bounds prover sees each index.
299
+ const t2: i32 = t - 2
300
+ const t7: i32 = t - 7
301
+ const t15: i32 = t - 15
302
+ const t16: i32 = t - 16
303
+ w[t] = smallSigma1(w[t2]) + w[t7] + smallSigma0(w[t15]) + w[t16]
304
+ }
305
+ let a = h[0]
306
+ let b = h[1]
307
+ let c = h[2]
308
+ let d = h[3]
309
+ let e = h[4]
310
+ let f = h[5]
311
+ let g = h[6]
312
+ let hh = h[7]
313
+ // §6.4.2 step 4, eight rounds per pass. Rather than shift eight words down
314
+ // each round, the rounds rename them: T1 accumulates in the word that
315
+ // becomes the new `a`, and the word that becomes the new `e` is `d + T1`,
316
+ // so after eight rounds every word is back in its own name. Each index is
317
+ // `u` minus a constant, which the bounds prover can see; `u + 1` it cannot.
318
+ for (let u: i32 = 7; u < ROUNDS && u < wLen; u += 8) {
319
+ const r0: i32 = u - 7
320
+ const r1: i32 = u - 6
321
+ const r2: i32 = u - 5
322
+ const r3: i32 = u - 4
323
+ const r4: i32 = u - 3
324
+ const r5: i32 = u - 2
325
+ const r6: i32 = u - 1
326
+ hh = hh + bigSigma1(e) + ((e & f) ^ (~e & g)) + roundConstant(r0) + w[r0]
327
+ d = d + hh
328
+ hh = hh + bigSigma0(a) + ((a & b) ^ (a & c) ^ (b & c))
329
+ g = g + bigSigma1(d) + ((d & e) ^ (~d & f)) + roundConstant(r1) + w[r1]
330
+ c = c + g
331
+ g = g + bigSigma0(hh) + ((hh & a) ^ (hh & b) ^ (a & b))
332
+ f = f + bigSigma1(c) + ((c & d) ^ (~c & e)) + roundConstant(r2) + w[r2]
333
+ b = b + f
334
+ f = f + bigSigma0(g) + ((g & hh) ^ (g & a) ^ (hh & a))
335
+ e = e + bigSigma1(b) + ((b & c) ^ (~b & d)) + roundConstant(r3) + w[r3]
336
+ a = a + e
337
+ e = e + bigSigma0(f) + ((f & g) ^ (f & hh) ^ (g & hh))
338
+ d = d + bigSigma1(a) + ((a & b) ^ (~a & c)) + roundConstant(r4) + w[r4]
339
+ hh = hh + d
340
+ d = d + bigSigma0(e) + ((e & f) ^ (e & g) ^ (f & g))
341
+ c = c + bigSigma1(hh) + ((hh & a) ^ (~hh & b)) + roundConstant(r5) + w[r5]
342
+ g = g + c
343
+ c = c + bigSigma0(d) + ((d & e) ^ (d & f) ^ (e & f))
344
+ b = b + bigSigma1(g) + ((g & hh) ^ (~g & a)) + roundConstant(r6) + w[r6]
345
+ f = f + b
346
+ b = b + bigSigma0(c) + ((c & d) ^ (c & e) ^ (d & e))
347
+ a = a + bigSigma1(f) + ((f & g) ^ (~f & hh)) + roundConstant(u) + w[u]
348
+ e = e + a
349
+ a = a + bigSigma0(b) + ((b & c) ^ (b & d) ^ (c & d))
350
+ }
351
+ h[0] = h[0] + a
352
+ h[1] = h[1] + b
353
+ h[2] = h[2] + c
354
+ h[3] = h[3] + d
355
+ h[4] = h[4] + e
356
+ h[5] = h[5] + f
357
+ h[6] = h[6] + g
358
+ h[7] = h[7] + hh
359
+ }
360
+
361
+ absorb(data: u8[], off: i32, len: i32): void {
362
+ if (this.finished) {
363
+ panic("sha512: update after digest")
364
+ }
365
+ if (off < 0 || len < 0 || off > toI32(data.length) - len) {
366
+ panic("sha512: the window is outside the buffer")
367
+ }
368
+ this.count = this.count + toU64(len)
369
+ let at = off
370
+ let left = len
371
+ if (this.filled > 0) {
372
+ const room: i32 = SHA512_BLOCK - this.filled
373
+ const take: i32 = left < room ? left : room
374
+ for (let i: i32 = 0; i < take; i++) {
375
+ this.block[this.filled + i] = data[at + i]
376
+ }
377
+ this.filled = this.filled + take
378
+ at = at + take
379
+ left = left - take
380
+ if (this.filled < SHA512_BLOCK) {
381
+ return
382
+ }
383
+ this.compress(this.block, OFFSET_ZERO)
384
+ this.filled = 0
385
+ }
386
+ while (left >= SHA512_BLOCK) {
387
+ this.compress(data, at)
388
+ at = at + SHA512_BLOCK
389
+ left = left - SHA512_BLOCK
390
+ }
391
+ for (let i: i32 = 0; i < left; i++) {
392
+ this.block[i] = data[at + i]
393
+ }
394
+ this.filled = left
395
+ }
396
+
397
+ /**
398
+ * Makes `twin` this engine at the same point. `twin` is a fresh engine of the
399
+ * same hash, so its arrays are reused rather than allocated a second time.
400
+ */
401
+ copyInto(twin: Sha512Engine): void {
402
+ for (let i: i32 = 0; i < 8; i++) {
403
+ twin.state[i] = this.state[i]
404
+ }
405
+ for (let i: i32 = 0; i < this.filled; i++) {
406
+ twin.block[i] = this.block[i]
407
+ }
408
+ twin.filled = this.filled
409
+ twin.count = this.count
410
+ twin.finished = this.finished
411
+ }
412
+
413
+ /** Pads (§5.1.2), compresses what is left, and answers the first `size` bytes of H(N) (§6.4.2, §6.5). */
414
+ finish(size: i32): u8[] {
415
+ if (this.finished) {
416
+ panic("sha512: digest taken twice")
417
+ }
418
+ this.finished = true
419
+ const block = this.block
420
+ const blockLen: i32 = toI32(block.length)
421
+ block[this.filled] = 0x80
422
+ for (let i: i32 = this.filled + 1; i >= 0 && i < blockLen; i++) {
423
+ block[i] = 0
424
+ }
425
+ if (this.filled >= LENGTH_AT) {
426
+ this.compress(block, OFFSET_ZERO)
427
+ for (let i: i32 = 0; i < LENGTH_AT && i < blockLen; i++) {
428
+ block[i] = 0
429
+ }
430
+ }
431
+ storeWord(block, LENGTH_AT, this.count >> 61)
432
+ storeWord(block, LENGTH_AT + 8, this.count << 3)
433
+ this.compress(block, OFFSET_ZERO)
434
+ // Both sizes are whole words, so the digest is the first `size / 8` of them.
435
+ const out = new Array<u8>(size)
436
+ for (let i: i32 = 0; i < size / 8 && i < 8; i++) {
437
+ storeWord(out, 8 * i, this.state[i])
438
+ }
439
+ return out
440
+ }
441
+ }
442
+
443
+ /**
444
+ * A streaming SHA-512 hasher. `update` takes a window `(data, off, len)`;
445
+ * `digest` answers a fresh 64-byte array, after which the hasher is spent and
446
+ * another `update` or `digest` panics.
447
+ */
448
+ export class Sha512 {
449
+ engine: Sha512Engine
450
+
451
+ constructor() {
452
+ this.engine = new Sha512Engine(sha512Initial())
453
+ }
454
+
455
+ update(data: u8[], off: i32, len: i32): void {
456
+ this.engine.absorb(data, off, len)
457
+ }
458
+
459
+ /** An independent hasher at the same point: updating either leaves the other alone. */
460
+ copy(): Sha512 {
461
+ const twin = new Sha512()
462
+ this.engine.copyInto(twin.engine)
463
+ return twin
464
+ }
465
+
466
+ digest(): u8[] {
467
+ return this.engine.finish(SHA512_SIZE)
468
+ }
469
+ }
470
+
471
+ /**
472
+ * A streaming SHA-384 hasher, with `Sha512`'s methods. `digest` answers a
473
+ * fresh 48-byte array.
474
+ */
475
+ export class Sha384 {
476
+ engine: Sha512Engine
477
+
478
+ constructor() {
479
+ this.engine = new Sha512Engine(sha384Initial())
480
+ }
481
+
482
+ update(data: u8[], off: i32, len: i32): void {
483
+ this.engine.absorb(data, off, len)
484
+ }
485
+
486
+ /** An independent hasher at the same point: updating either leaves the other alone. */
487
+ copy(): Sha384 {
488
+ const twin = new Sha384()
489
+ this.engine.copyInto(twin.engine)
490
+ return twin
491
+ }
492
+
493
+ digest(): u8[] {
494
+ return this.engine.finish(SHA384_SIZE)
495
+ }
496
+ }
497
+
498
+ /** The SHA-512 digest of all of `data`, as a fresh 64-byte array. */
499
+ export const sha512 = (data: u8[]): u8[] => {
500
+ const hasher = new Sha512()
501
+ hasher.update(data, OFFSET_ZERO, toI32(data.length))
502
+ return hasher.digest()
503
+ }
504
+
505
+ /** The SHA-384 digest of all of `data`, as a fresh 48-byte array. */
506
+ export const sha384 = (data: u8[]): u8[] => {
507
+ const hasher = new Sha384()
508
+ hasher.update(data, OFFSET_ZERO, toI32(data.length))
509
+ return hasher.digest()
510
+ }