@amritk/nish-x86_64-linux 0.17.0 → 0.20.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.
Files changed (61) hide show
  1. package/INSTALL.md +43 -25
  2. package/bin/nish +0 -0
  3. package/package.json +2 -2
  4. package/runtime/nish.d.ts +55 -5
  5. package/runtime/nish.h +231 -20
  6. package/runtime/nish.mjs +16 -0
  7. package/runtime/runtime-aes.c +490 -0
  8. package/runtime/runtime-cross.c +366 -0
  9. package/runtime/runtime-host.c +7 -6
  10. package/runtime/runtime-net.c +93 -34
  11. package/runtime/runtime-os.c +213 -15
  12. package/runtime/runtime-parallel.c +590 -107
  13. package/runtime/runtime-simd.c +203 -0
  14. package/runtime/runtime-wasm.c +16 -3
  15. package/runtime/runtime.c +89 -23
  16. package/runtime/shim.mjs +71 -1
  17. package/scripts/build.sh +225 -20
  18. package/std/README.md +86 -55
  19. package/std/bytes.ts +163 -0
  20. package/std/crypto/LICENSE-libsecp256k1 +19 -0
  21. package/std/crypto/aes.ts +238 -76
  22. package/std/crypto/chacha20poly1305.ts +43 -9
  23. package/std/crypto/ed25519.ts +840 -0
  24. package/std/crypto/hkdf.ts +304 -12
  25. package/std/crypto/hmac.ts +245 -53
  26. package/std/crypto/p256.ts +1376 -42
  27. package/std/crypto/x25519.ts +55 -37
  28. package/std/crypto/x509-random.ts +71 -0
  29. package/std/crypto/x509.ts +9 -9
  30. package/std/json-tokenizer.ts +1296 -0
  31. package/std/json-typed.ts +1014 -0
  32. package/std/json-value.ts +1163 -0
  33. package/std/json.ts +1412 -70
  34. package/std/net/buffer-pool.ts +151 -0
  35. package/std/net/hpack.ts +416 -112
  36. package/std/net/http-fields.ts +93 -0
  37. package/std/net/http1-server.ts +417 -55
  38. package/std/net/http1.ts +31 -6
  39. package/std/net/http2-tls.ts +112 -24
  40. package/std/net/http2.ts +333 -75
  41. package/std/net/http3-server.ts +231 -45
  42. package/std/net/http3.ts +187 -28
  43. package/std/net/prefork.ts +412 -0
  44. package/std/net/quic-conn-params.ts +86 -16
  45. package/std/net/quic-listener.ts +576 -219
  46. package/std/net/quic-packet.ts +443 -58
  47. package/std/net/quic-recovery.ts +361 -30
  48. package/std/net/quic-stream.ts +434 -28
  49. package/std/net/quic.ts +922 -206
  50. package/std/net/router.ts +676 -0
  51. package/std/net/tls/codec.ts +426 -27
  52. package/std/net/tls/record-server.ts +478 -132
  53. package/std/net/tls/record.ts +133 -42
  54. package/std/net/tls/schedule.ts +464 -55
  55. package/std/net/tls/ticket.ts +610 -0
  56. package/std/net/tls-tcp.ts +204 -57
  57. package/std/net/tls.ts +1132 -305
  58. package/std/net/url.ts +571 -0
  59. package/std/random.ts +94 -0
  60. package/std/text.ts +77 -0
  61. package/std/threads.ts +438 -14
@@ -1,5 +1,6 @@
1
1
  /**
2
- * `nish/crypto/hmac` — HMAC as RFC 2104 defines it, over SHA-256 and SHA-384.
2
+ * `nish/crypto/hmac` — HMAC as RFC 2104 defines it, over SHA-256, SHA-384 and
3
+ * SHA-512.
3
4
  *
4
5
  * H(K XOR opad, H(K XOR ipad, text))
5
6
  *
@@ -24,6 +25,21 @@
24
25
  * which HMAC does not keep secret; a received tag is compared with
25
26
  * `timingSafeEqual`, never `===`.
26
27
  *
28
+ * **What the key reaches is wiped** (CLAUDE.md, "Security"). The key block
29
+ * is wiped once both hashers have absorbed it, and so is the hash
30
+ * of a key longer than a block and the hasher that made it. `digest` wipes
31
+ * the inner digest and both keyed hashers (chaining value, pending block and
32
+ * message schedule) before it answers, so a finished `HmacSha256` holds
33
+ * nothing of the key. The wipes are `wipe`'s volatile stores, which `-O2`
34
+ * keeps (`tests/wipes/crypto.js`, "crypto_hmac crypto_hkdf: the wipes survive -O2").
35
+ * What no wipe here reaches is the caller's own key array, and an
36
+ * `HmacSha256` that is keyed and then dropped without a `digest` keeps its
37
+ * keyed hashers (docs/security/crypto-k1.md, K1-7).
38
+ *
39
+ * A caller that holds its key as a `Secret<u8[]>` (`nish:secret`) MACs with
40
+ * `hmacSha256Secret`, `hmacSha384Secret` or `hmacSha512Secret`, which read the
41
+ * key only inside `exposeWith`; the tag they answer is public and plain.
42
+ *
27
43
  * `HmacSha256Scratch` and `HmacSha384Scratch` are the same computation in
28
44
  * hashers the caller allocates once: `begin` keys them again in place and
29
45
  * `finishInto` writes the tag into the caller's array, so a loop of them
@@ -32,9 +48,10 @@
32
48
  *
33
49
  * Written from RFC 2104, not ported from another implementation.
34
50
  */
35
- import { SHA256_BLOCK, SHA256_SIZE, Sha256, sha256 } from "nish/crypto/sha256"
36
- import { SHA384_SIZE, SHA512_BLOCK, Sha384, sha384 } from "nish/crypto/sha512"
51
+ import { SHA256_BLOCK, SHA256_SIZE, Sha256 } from "nish/crypto/sha256"
52
+ import { SHA384_SIZE, SHA512_BLOCK, SHA512_SIZE, Sha384, Sha512 } from "nish/crypto/sha512"
37
53
  import { timingSafeEqual } from "nish/crypto/ct"
54
+ import { Secret, exposeWith, wipe } from "nish:secret"
38
55
 
39
56
  /** RFC 2104 §2's `ipad`, the byte XORed into the key for the inner hash. */
40
57
  const HMAC_IPAD: i32 = 0x36
@@ -76,6 +93,141 @@ const hmacPadBlock = (key: u8[], blockSize: i32, pad: i32): u8[] => {
76
93
  return out
77
94
  }
78
95
 
96
+ /**
97
+ * Zeroes everything `h` holds of the key and the message it was fed: its hash
98
+ * value, its pending block and its message schedule, with `wipe`'s volatile
99
+ * stores, which no optimiser removes however dead the hasher is about to be.
100
+ * The hasher is left finished, so that feeding it before it is started again
101
+ * panics, as feeding a spent one always has.
102
+ */
103
+ const hmacWipeSha256 = (h: Sha256): void => {
104
+ wipe(h.state)
105
+ wipe(h.block)
106
+ wipe(h.schedule)
107
+ h.fill = 0
108
+ h.total = 0
109
+ h.finished = true
110
+ }
111
+
112
+ /** `hmacWipeSha256` for SHA-384. */
113
+ const hmacWipeSha384 = (h: Sha384): void => {
114
+ wipe(h.engine.state)
115
+ wipe(h.engine.block)
116
+ wipe(h.engine.schedule)
117
+ h.engine.filled = 0
118
+ h.engine.count = toU64(0)
119
+ h.engine.finished = true
120
+ }
121
+
122
+ /** `hmacWipeSha256` for SHA-512. */
123
+ const hmacWipeSha512 = (h: Sha512): void => {
124
+ wipe(h.engine.state)
125
+ wipe(h.engine.block)
126
+ wipe(h.engine.schedule)
127
+ h.engine.filled = 0
128
+ h.engine.count = toU64(0)
129
+ h.engine.finished = true
130
+ }
131
+
132
+ /**
133
+ * Panics on a key longer than 2^31 - 1 bytes, before any `toI32` of its
134
+ * length: under `--number-mode f64` that would saturate, and the key hashed
135
+ * would be a prefix, so two keys sharing it would MAC alike (K1-1).
136
+ */
137
+ const hmacCheckKey = (key: u8[]): void => {
138
+ if (key.length > 2147483647) {
139
+ panic("hmac: a key longer than 2^31 - 1 bytes")
140
+ }
141
+ }
142
+
143
+ /**
144
+ * Keys `inner` with `k XOR ipad` and `outer` with `k XOR opad`, `k` no longer
145
+ * than SHA-256's block, in one block that is rewritten between the two and
146
+ * wiped once both have absorbed it.
147
+ */
148
+ const hmacPadsSha256 = (inner: Sha256, outer: Sha256, k: u8[]): void => {
149
+ const pad: u8[] = hmacPadBlock(k, SHA256_BLOCK, HMAC_IPAD)
150
+ inner.update(pad, HMAC_FROM, SHA256_BLOCK)
151
+ hmacPadInto(pad, k, HMAC_FROM, toI32(k.length), HMAC_OPAD)
152
+ outer.update(pad, HMAC_FROM, SHA256_BLOCK)
153
+ wipe(pad)
154
+ }
155
+
156
+ /**
157
+ * Keys `inner` and `outer` with `key` as RFC 2104 §2 says: a key longer than
158
+ * the block is replaced by its hash, in a hasher of its own, and that hash
159
+ * and that hasher are wiped once the key blocks are absorbed.
160
+ */
161
+ const hmacKeySha256 = (inner: Sha256, outer: Sha256, key: u8[]): void => {
162
+ hmacCheckKey(key)
163
+ if (toI32(key.length) <= SHA256_BLOCK) {
164
+ hmacPadsSha256(inner, outer, key)
165
+ return
166
+ }
167
+ const hasher = new Sha256()
168
+ hasher.update(key, HMAC_FROM, toI32(key.length))
169
+ const hashed: u8[] = hasher.digest()
170
+ hmacWipeSha256(hasher)
171
+ hmacPadsSha256(inner, outer, hashed)
172
+ wipe(hashed)
173
+ }
174
+
175
+ /** `hmacPadsSha256` for SHA-384's 128-byte block. */
176
+ const hmacPadsSha384 = (inner: Sha384, outer: Sha384, k: u8[]): void => {
177
+ const pad: u8[] = hmacPadBlock(k, SHA512_BLOCK, HMAC_IPAD)
178
+ inner.update(pad, HMAC_FROM, SHA512_BLOCK)
179
+ hmacPadInto(pad, k, HMAC_FROM, toI32(k.length), HMAC_OPAD)
180
+ outer.update(pad, HMAC_FROM, SHA512_BLOCK)
181
+ wipe(pad)
182
+ }
183
+
184
+ /**
185
+ * Keys `inner` and `outer` with `key` as RFC 2104 §2 says: a key longer than
186
+ * the block is replaced by its hash, in a hasher of its own, and that hash
187
+ * and that hasher are wiped once the key blocks are absorbed.
188
+ */
189
+ const hmacKeySha384 = (inner: Sha384, outer: Sha384, key: u8[]): void => {
190
+ hmacCheckKey(key)
191
+ if (toI32(key.length) <= SHA512_BLOCK) {
192
+ hmacPadsSha384(inner, outer, key)
193
+ return
194
+ }
195
+ const hasher = new Sha384()
196
+ hasher.update(key, HMAC_FROM, toI32(key.length))
197
+ const hashed: u8[] = hasher.digest()
198
+ hmacWipeSha384(hasher)
199
+ hmacPadsSha384(inner, outer, hashed)
200
+ wipe(hashed)
201
+ }
202
+
203
+ /** `hmacPadsSha256` for SHA-512's 128-byte block. */
204
+ const hmacPadsSha512 = (inner: Sha512, outer: Sha512, k: u8[]): void => {
205
+ const pad: u8[] = hmacPadBlock(k, SHA512_BLOCK, HMAC_IPAD)
206
+ inner.update(pad, HMAC_FROM, SHA512_BLOCK)
207
+ hmacPadInto(pad, k, HMAC_FROM, toI32(k.length), HMAC_OPAD)
208
+ outer.update(pad, HMAC_FROM, SHA512_BLOCK)
209
+ wipe(pad)
210
+ }
211
+
212
+ /**
213
+ * Keys `inner` and `outer` with `key` as RFC 2104 §2 says: a key longer than
214
+ * the block is replaced by its hash, in a hasher of its own, and that hash
215
+ * and that hasher are wiped once the key blocks are absorbed.
216
+ */
217
+ const hmacKeySha512 = (inner: Sha512, outer: Sha512, key: u8[]): void => {
218
+ hmacCheckKey(key)
219
+ if (toI32(key.length) <= SHA512_BLOCK) {
220
+ hmacPadsSha512(inner, outer, key)
221
+ return
222
+ }
223
+ const hasher = new Sha512()
224
+ hasher.update(key, HMAC_FROM, toI32(key.length))
225
+ const hashed: u8[] = hasher.digest()
226
+ hmacWipeSha512(hasher)
227
+ hmacPadsSha512(inner, outer, hashed)
228
+ wipe(hashed)
229
+ }
230
+
79
231
  /**
80
232
  * HMAC-SHA-256 in progress (RFC 2104 with RFC 4231's SHA-256): feed the
81
233
  * message with `update`, as many windows as it takes, and take the 32-byte
@@ -87,13 +239,14 @@ export class HmacSha256 {
87
239
  /** H(K XOR opad, …), fed the key block in the constructor and the inner digest last. */
88
240
  outer: Sha256
89
241
 
90
- /** Keys the computation. A key longer than 64 bytes is replaced by its SHA-256 (RFC 2104 §2). */
242
+ /**
243
+ * Keys the computation. A key longer than 64 bytes is replaced by its
244
+ * SHA-256 (RFC 2104 §2), which is wiped once used (`hmacKeySha256`).
245
+ */
91
246
  constructor(key: u8[]) {
92
- const k: u8[] = toI32(key.length) > SHA256_BLOCK ? sha256(key) : key
93
247
  this.inner = new Sha256()
94
- this.inner.update(hmacPadBlock(k, SHA256_BLOCK, HMAC_IPAD), HMAC_FROM, SHA256_BLOCK)
95
248
  this.outer = new Sha256()
96
- this.outer.update(hmacPadBlock(k, SHA256_BLOCK, HMAC_OPAD), HMAC_FROM, SHA256_BLOCK)
249
+ hmacKeySha256(this.inner, this.outer, key)
97
250
  }
98
251
 
99
252
  /** Absorbs `data[off .. off + len)`; a window outside `data` panics in `Sha256.update`. */
@@ -101,11 +254,15 @@ export class HmacSha256 {
101
254
  this.inner.update(data, off, len)
102
255
  }
103
256
 
104
- /** The 32-byte tag, in a fresh array. Ends the computation. */
257
+ /** The 32-byte tag, in a fresh array. Ends the computation, and wipes both hashers. */
105
258
  digest(): u8[] {
106
259
  const innerDigest: u8[] = this.inner.digest()
107
260
  this.outer.update(innerDigest, HMAC_FROM, SHA256_SIZE)
108
- return this.outer.digest()
261
+ wipe(innerDigest)
262
+ const tag: u8[] = this.outer.digest()
263
+ hmacWipeSha256(this.inner)
264
+ hmacWipeSha256(this.outer)
265
+ return tag
109
266
  }
110
267
  }
111
268
 
@@ -121,11 +278,9 @@ export class HmacSha384 {
121
278
 
122
279
  /** Keys the computation. A key longer than 128 bytes is replaced by its SHA-384 (RFC 2104 §2). */
123
280
  constructor(key: u8[]) {
124
- const k: u8[] = toI32(key.length) > SHA512_BLOCK ? sha384(key) : key
125
281
  this.inner = new Sha384()
126
- this.inner.update(hmacPadBlock(k, SHA512_BLOCK, HMAC_IPAD), HMAC_FROM, SHA512_BLOCK)
127
282
  this.outer = new Sha384()
128
- this.outer.update(hmacPadBlock(k, SHA512_BLOCK, HMAC_OPAD), HMAC_FROM, SHA512_BLOCK)
283
+ hmacKeySha384(this.inner, this.outer, key)
129
284
  }
130
285
 
131
286
  /** Absorbs `data[off .. off + len)`; a window outside `data` panics in `Sha384.update`. */
@@ -133,11 +288,49 @@ export class HmacSha384 {
133
288
  this.inner.update(data, off, len)
134
289
  }
135
290
 
136
- /** The 48-byte tag, in a fresh array. Ends the computation. */
291
+ /** The 48-byte tag, in a fresh array. Ends the computation, and wipes both hashers. */
137
292
  digest(): u8[] {
138
293
  const innerDigest: u8[] = this.inner.digest()
139
294
  this.outer.update(innerDigest, HMAC_FROM, SHA384_SIZE)
140
- return this.outer.digest()
295
+ wipe(innerDigest)
296
+ const tag: u8[] = this.outer.digest()
297
+ hmacWipeSha384(this.inner)
298
+ hmacWipeSha384(this.outer)
299
+ return tag
300
+ }
301
+ }
302
+
303
+ /**
304
+ * HMAC-SHA-512 in progress (RFC 2104 with RFC 4231's SHA-512), with
305
+ * `HmacSha256`'s methods. The block is SHA-512's 128 bytes and the tag 64.
306
+ */
307
+ export class HmacSha512 {
308
+ /** H(K XOR ipad, …), fed the key block in the constructor and the message after. */
309
+ inner: Sha512
310
+ /** H(K XOR opad, …), fed the key block in the constructor and the inner digest last. */
311
+ outer: Sha512
312
+
313
+ /** Keys the computation. A key longer than 128 bytes is replaced by its SHA-512 (RFC 2104 §2). */
314
+ constructor(key: u8[]) {
315
+ this.inner = new Sha512()
316
+ this.outer = new Sha512()
317
+ hmacKeySha512(this.inner, this.outer, key)
318
+ }
319
+
320
+ /** Absorbs `data[off .. off + len)`; a window outside `data` panics in `Sha512.update`. */
321
+ update(data: u8[], off: i32, len: i32): void {
322
+ this.inner.update(data, off, len)
323
+ }
324
+
325
+ /** The 64-byte tag, in a fresh array. Ends the computation, and wipes both hashers. */
326
+ digest(): u8[] {
327
+ const innerDigest: u8[] = this.inner.digest()
328
+ this.outer.update(innerDigest, HMAC_FROM, SHA512_SIZE)
329
+ wipe(innerDigest)
330
+ const tag: u8[] = this.outer.digest()
331
+ hmacWipeSha512(this.inner)
332
+ hmacWipeSha512(this.outer)
333
+ return tag
141
334
  }
142
335
  }
143
336
 
@@ -147,7 +340,7 @@ export class HmacSha384 {
147
340
  * `data` longer than 2^31 - 1 bytes panics, as `sha256` does and for its
148
341
  * reason: under `--number-mode f64` the tag would be of a prefix, and a tag
149
342
  * that verifies every message sharing that prefix is a forgery. A key that
150
- * long reaches `sha256` in the constructor and panics there.
343
+ * long panics in the constructor for the same reason.
151
344
  */
152
345
  export const hmacSha256 = (key: u8[], data: u8[]): u8[] => {
153
346
  if (data.length > 2147483647) {
@@ -171,6 +364,31 @@ export const hmacSha384 = (key: u8[], data: u8[]): u8[] => {
171
364
  return mac.digest()
172
365
  }
173
366
 
367
+ /**
368
+ * The HMAC-SHA-512 of all of `data` under `key`, as a fresh 64-byte array.
369
+ * `data` longer than 2^31 - 1 bytes panics, as in `hmacSha256`.
370
+ */
371
+ export const hmacSha512 = (key: u8[], data: u8[]): u8[] => {
372
+ if (data.length > 2147483647) {
373
+ panic("hmacSha512: a message longer than 2^31 - 1 bytes")
374
+ }
375
+ const mac = new HmacSha512(key)
376
+ mac.update(data, HMAC_FROM, toI32(data.length))
377
+ return mac.digest()
378
+ }
379
+
380
+ /**
381
+ * `hmacSha256` under a key held as a `Secret`, read only inside `exposeWith`.
382
+ * The tag is public, so it is answered plain; the caller still wipes the key.
383
+ */
384
+ export const hmacSha256Secret = (key: Secret<u8[]>, data: u8[]): u8[] => exposeWith(key, data, hmacSha256)
385
+
386
+ /** `hmacSha384` under a key held as a `Secret`, as `hmacSha256Secret` is. */
387
+ export const hmacSha384Secret = (key: Secret<u8[]>, data: u8[]): u8[] => exposeWith(key, data, hmacSha384)
388
+
389
+ /** `hmacSha512` under a key held as a `Secret`, as `hmacSha256Secret` is. */
390
+ export const hmacSha512Secret = (key: Secret<u8[]>, data: u8[]): u8[] => exposeWith(key, data, hmacSha512)
391
+
174
392
  /**
175
393
  * Whether `tag` is the HMAC-SHA-256 of `data` under `key`, compared by
176
394
  * `timingSafeEqual`. A tag that is not 32 bytes answers `false` without a
@@ -184,6 +402,10 @@ export const hmacSha256Verify = (key: u8[], data: u8[], tag: u8[]): boolean =>
184
402
  export const hmacSha384Verify = (key: u8[], data: u8[], tag: u8[]): boolean =>
185
403
  timingSafeEqual(hmacSha384(key, data), tag)
186
404
 
405
+ /** Whether `tag` is the HMAC-SHA-512 of `data` under `key`, compared as `hmacSha256Verify` does. */
406
+ export const hmacSha512Verify = (key: u8[], data: u8[], tag: u8[]): boolean =>
407
+ timingSafeEqual(hmacSha512(key, data), tag)
408
+
187
409
  // ---- Caller-owned scratch --------------------------------------------------
188
410
  //
189
411
  // `HmacSha256` makes its two hashers in its constructor, and the one-shot
@@ -241,44 +463,6 @@ export const hmacCopySha384 = (from: Sha384, to: Sha384): void => {
241
463
  to.engine.finished = from.engine.finished
242
464
  }
243
465
 
244
- /**
245
- * Zeroes everything `h` holds of the message it was fed: the pending block
246
- * with `secureZero`, and the hash value and message schedule, which are words
247
- * `secureZero` does not take, with ordinary stores. Those stand because the
248
- * hasher stays reachable for the next `begin`. The hasher is left finished, so
249
- * that feeding it before it is started again panics.
250
- */
251
- const hmacWipeSha256 = (h: Sha256): void => {
252
- secureZero(h.block)
253
- const state: u32[] = h.state
254
- for (let i: i32 = 0; i < toI32(state.length); i += 1) {
255
- state[i] = toU32(0)
256
- }
257
- const schedule: u32[] = h.schedule
258
- for (let i: i32 = 0; i < toI32(schedule.length); i += 1) {
259
- schedule[i] = toU32(0)
260
- }
261
- h.fill = 0
262
- h.total = 0
263
- h.finished = true
264
- }
265
-
266
- /** `hmacWipeSha256` for SHA-384. */
267
- const hmacWipeSha384 = (h: Sha384): void => {
268
- secureZero(h.engine.block)
269
- const state: u64[] = h.engine.state
270
- for (let i: i32 = 0; i < toI32(state.length); i += 1) {
271
- state[i] = toU64(0)
272
- }
273
- const schedule: u64[] = h.engine.schedule
274
- for (let i: i32 = 0; i < toI32(schedule.length); i += 1) {
275
- schedule[i] = toU64(0)
276
- }
277
- h.engine.filled = 0
278
- h.engine.count = toU64(0)
279
- h.engine.finished = true
280
- }
281
-
282
466
  /** Whether `[off, off + len)` is a window inside an array of `length` elements. */
283
467
  const hmacWindowFits = (length: i32, off: i32, len: i32): boolean =>
284
468
  off >= 0 && len >= 0 && off <= length - len
@@ -346,6 +530,10 @@ export class HmacSha256Scratch {
346
530
  * stored to the arena analysis.
347
531
  */
348
532
  keyBlocks(key: u8[], off: i32, len: i32): void {
533
+ // Starting a hasher again copies only the live part of `fresh`, so the
534
+ // last computation's block and schedule are wiped first (K1-7).
535
+ hmacWipeSha256(this.inner)
536
+ hmacWipeSha256(this.outer)
349
537
  hmacPadInto(this.pad, key, off, len, HMAC_IPAD)
350
538
  hmacCopySha256(this.fresh, this.inner)
351
539
  this.inner.update(this.pad, HMAC_FROM, SHA256_BLOCK)
@@ -434,6 +622,10 @@ export class HmacSha384Scratch {
434
622
  * stored to the arena analysis.
435
623
  */
436
624
  keyBlocks(key: u8[], off: i32, len: i32): void {
625
+ // Starting a hasher again copies only the live part of `fresh`, so the
626
+ // last computation's block and schedule are wiped first (K1-7).
627
+ hmacWipeSha384(this.inner)
628
+ hmacWipeSha384(this.outer)
437
629
  hmacPadInto(this.pad, key, off, len, HMAC_IPAD)
438
630
  hmacCopySha384(this.fresh, this.inner)
439
631
  this.inner.update(this.pad, HMAC_FROM, SHA512_BLOCK)