@amritk/nish-x86_64-linux 0.16.0 → 0.18.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/INSTALL.md +43 -34
- package/bin/nish +0 -0
- package/package.json +1 -1
- package/runtime/nish.d.ts +117 -8
- package/runtime/nish.h +50 -13
- package/runtime/nish.mjs +71 -7
- package/runtime/runtime-host.c +43 -24
- package/runtime/runtime-net.c +57 -10
- package/runtime/runtime-os.c +62 -20
- package/runtime/runtime-simd.c +203 -0
- package/runtime/runtime-wasm.c +12 -0
- package/runtime/runtime.c +66 -18
- package/runtime/shim.mjs +114 -5
- package/scripts/build.sh +14 -12
- package/std/README.md +168 -36
- package/std/crypto/aes.ts +51 -8
- package/std/crypto/base64url.ts +25 -12
- package/std/crypto/chacha20poly1305.ts +43 -29
- package/std/crypto/ct.ts +6 -1
- package/std/crypto/hkdf.ts +364 -3
- package/std/crypto/hmac.ts +307 -7
- package/std/crypto/p256.ts +618 -34
- package/std/crypto/sha1.ts +147 -0
- package/std/crypto/sha256.ts +3 -2
- package/std/crypto/x25519.ts +88 -36
- package/std/crypto/x509.ts +130 -47
- package/std/json.ts +297 -41
- package/std/net/hpack.ts +1094 -0
- package/std/net/http-fields.ts +604 -0
- package/std/net/http1-server.ts +1389 -0
- package/std/net/http1.ts +1492 -0
- package/std/net/http2-frame.ts +745 -0
- package/std/net/http2-tls.ts +216 -0
- package/std/net/http2.ts +1433 -0
- package/std/net/http3-frame.ts +457 -0
- package/std/net/http3-server.ts +911 -0
- package/std/net/http3.ts +2145 -0
- package/std/net/qpack.ts +1163 -0
- package/std/net/quic-conn-ack.ts +206 -0
- package/std/net/quic-conn-cid.ts +425 -0
- package/std/net/quic-conn-params.ts +462 -0
- package/std/net/quic-datagram.ts +130 -0
- package/std/net/quic-frame.ts +1206 -0
- package/std/net/quic-listener.ts +929 -0
- package/std/net/quic-packet.ts +1698 -0
- package/std/net/quic-recovery.ts +849 -0
- package/std/net/quic-stream.ts +1609 -0
- package/std/net/quic.ts +3578 -0
- package/std/net/tls/codec.ts +1089 -0
- package/std/net/tls/record-server.ts +1173 -0
- package/std/net/tls/record.ts +621 -0
- package/std/net/tls/schedule.ts +429 -0
- package/std/net/tls-tcp.ts +414 -0
- package/std/net/tls.ts +1437 -0
- package/std/net/websocket.ts +823 -0
- package/std/net/webtransport.ts +1334 -0
- package/std/secret.ts +62 -0
- package/std/text.ts +77 -0
package/std/secret.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `nish:secret` — key material, and the rules that keep it in
|
|
3
|
+
* (docs/LANGUAGE.md, "Secrets").
|
|
4
|
+
*
|
|
5
|
+
* import { Secret, expose, secret, wipe } from "nish:secret"
|
|
6
|
+
*
|
|
7
|
+
* const key: Secret<u8[]> = secret(readKey())
|
|
8
|
+
* const tag: u8[] = expose(key, (k: u8[]): u8[] => hmacSha256(k, message))
|
|
9
|
+
* wipe(key)
|
|
10
|
+
*
|
|
11
|
+
* This file is the source behind the builtin module, and it is imported only
|
|
12
|
+
* by that name: `nish/secret` is refused, so there is one spelling for the
|
|
13
|
+
* checker's rules to be read under. What is written here is the meaning; what
|
|
14
|
+
* makes a `Secret` worth having is in `src/secret.ts`, which knows this module
|
|
15
|
+
* by its path and package:
|
|
16
|
+
*
|
|
17
|
+
* - a `Secret` is opaque. Nothing outside this file reads its field, builds
|
|
18
|
+
* one with `new`, prints it, interpolates it, compares it with anything but
|
|
19
|
+
* another `Secret` or `null`, branches on it, indexes it, stores it in a
|
|
20
|
+
* field, an array or a `Result`, or hands it to a builtin;
|
|
21
|
+
* - a `Secret` a function makes leaves it returned or wiped, on every path;
|
|
22
|
+
* - `expose` is the one way in, and the function it runs may reach no I/O and
|
|
23
|
+
* no C, may not keep the value, may not write the argument `exposeWith`
|
|
24
|
+
* hands it, and returns a declared type that holds no `Secret`;
|
|
25
|
+
* - `wipe` is a volatile store of zeros over the value's whole storage,
|
|
26
|
+
* which no optimiser may remove (`src/emit-secret.ts`).
|
|
27
|
+
*
|
|
28
|
+
* Under Node the module is answered by `runtime/shim.mjs`, where a `Secret` is
|
|
29
|
+
* a plain wrapper and `wipe` zero-fills it.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Key material: an array of integers (`u8[]`, `u32[]`, ...) or a record whose
|
|
34
|
+
* every field is an integer. Made by `secret`, read only through `expose`.
|
|
35
|
+
*/
|
|
36
|
+
export class Secret<T> {
|
|
37
|
+
/** The wrapped value. Only this module reads or writes it (`src/secret.ts`). */
|
|
38
|
+
value: T
|
|
39
|
+
|
|
40
|
+
constructor(value: T) {
|
|
41
|
+
this.value = value
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** `value`, wrapped. The argument is moved: a local handed in is not read again. */
|
|
46
|
+
export const secret = <T>(value: T): Secret<T> => new Secret<T>(value)
|
|
47
|
+
|
|
48
|
+
/** `f(value)`: the one way to compute with what a `Secret` holds. */
|
|
49
|
+
export const expose = <T, R>(s: Secret<T>, f: (value: T) => R): R => f(s.value)
|
|
50
|
+
|
|
51
|
+
/** `f(value, arg)`: `expose` with one more argument, because an arrow captures nothing. */
|
|
52
|
+
export const exposeWith = <T, A, R>(s: Secret<T>, arg: A, f: (value: T, arg: A) => R): R => f(s.value, arg)
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Zero every byte of `target`'s storage: a `Secret`'s value, or an array or
|
|
56
|
+
* record of integers that `expose`'s function holds. Natively the compiler
|
|
57
|
+
* gives each instance a body of its own, one volatile `llvm.memset`
|
|
58
|
+
* (`src/emit-secret.ts`); this one is never emitted.
|
|
59
|
+
*/
|
|
60
|
+
export const wipe = <T>(_target: T): void => {
|
|
61
|
+
// Lowered by the compiler: see above.
|
|
62
|
+
}
|
package/std/text.ts
CHANGED
|
@@ -191,3 +191,80 @@ export const firstDifference = (left: string[], right: string[]): i32 => {
|
|
|
191
191
|
}
|
|
192
192
|
return leftLength === rightLength ? -1 : i
|
|
193
193
|
}
|
|
194
|
+
|
|
195
|
+
/** The most bytes `indexOfAny` takes in its set: what one 16-byte vector of the runtime kernel compares. */
|
|
196
|
+
const INDEX_OF_ANY_MAX_SET: i32 = 16
|
|
197
|
+
|
|
198
|
+
/** The first byte that is not ASCII; `indexOfAny`'s set must stay below it. */
|
|
199
|
+
const NON_ASCII: i32 = 128
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* The first index at or after `from` whose byte is one of `bytes`, or -1.
|
|
203
|
+
*
|
|
204
|
+
* `bytes` is a set of 1 to 16 ASCII bytes, and anything else panics: an empty
|
|
205
|
+
* set matches nothing, more than 16 is more than one vector of the runtime
|
|
206
|
+
* kernel compares, and an ASCII set is what keeps the answer the same under Node,
|
|
207
|
+
* where `charCodeAt` reads a UTF-16 unit rather than a byte. An ASCII byte
|
|
208
|
+
* never occurs inside a multi-byte UTF-8 sequence, so a non-ASCII `text`
|
|
209
|
+
* passes through and only its ASCII bytes can match — as in `splitLines`, the
|
|
210
|
+
* index is a byte offset natively. `from` is clamped to `[0, text.length]`,
|
|
211
|
+
* as `substring` clamps, so a negative `from` searches from the start and one
|
|
212
|
+
* past the end answers -1.
|
|
213
|
+
*
|
|
214
|
+
* Natively the search is the runtime's `nish_str_index_of_any`, which reads
|
|
215
|
+
* 16 or 32 bytes at a time (docs/LANGUAGE.md, "Byte search"). It is
|
|
216
|
+
* **variable-time**: how long it takes says where the first match is, so it is
|
|
217
|
+
* never for secret data.
|
|
218
|
+
*/
|
|
219
|
+
export const indexOfAny = (text: string, bytes: string, from: i32): i32 => {
|
|
220
|
+
const count: i32 = toI32(bytes.length)
|
|
221
|
+
if (count < 1 || count > INDEX_OF_ANY_MAX_SET) {
|
|
222
|
+
panic("indexOfAny: the set must hold 1 to 16 bytes")
|
|
223
|
+
}
|
|
224
|
+
let j: i32 = 0
|
|
225
|
+
while (j < count) {
|
|
226
|
+
if (toI32(bytes.charCodeAt(j)) >= NON_ASCII) {
|
|
227
|
+
panic("indexOfAny: every byte of the set must be ASCII")
|
|
228
|
+
}
|
|
229
|
+
j += 1
|
|
230
|
+
}
|
|
231
|
+
const length: i32 = toI32(text.length)
|
|
232
|
+
let start: i32 = from
|
|
233
|
+
if (start < 0) {
|
|
234
|
+
start = 0
|
|
235
|
+
}
|
|
236
|
+
if (start > length) {
|
|
237
|
+
start = length
|
|
238
|
+
}
|
|
239
|
+
return indexOfAnyFrom(text, bytes, start)
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* `indexOfAny`'s walk, once its arguments are checked: the first index at or
|
|
244
|
+
* after `from` whose byte is in `bytes`, or -1.
|
|
245
|
+
*
|
|
246
|
+
* This loop is what runs under Node. Natively the compiler recognises the one
|
|
247
|
+
* call `indexOfAny` makes to it and calls the runtime kernel instead
|
|
248
|
+
* (`src/kernels.ts`), so the loop is the kernel's meaning written in the
|
|
249
|
+
* language rather than its implementation. The name is long for the reason
|
|
250
|
+
* `isTextBlankByte`'s is.
|
|
251
|
+
*/
|
|
252
|
+
const indexOfAnyFrom = (text: string, bytes: string, from: i32): i32 => {
|
|
253
|
+
const length: i32 = toI32(text.length)
|
|
254
|
+
const count: i32 = toI32(bytes.length)
|
|
255
|
+
let i: i32 = from
|
|
256
|
+
// `from` is never negative, because `indexOfAny` clamped it; the test is
|
|
257
|
+
// written because it is what proves `i` within `text`, as in `splitLines`.
|
|
258
|
+
while (i >= 0 && i < length) {
|
|
259
|
+
const code: i32 = toI32(text.charCodeAt(i))
|
|
260
|
+
let j: i32 = 0
|
|
261
|
+
while (j < count) {
|
|
262
|
+
if (toI32(bytes.charCodeAt(j)) === code) {
|
|
263
|
+
return i
|
|
264
|
+
}
|
|
265
|
+
j += 1
|
|
266
|
+
}
|
|
267
|
+
i += 1
|
|
268
|
+
}
|
|
269
|
+
return -1
|
|
270
|
+
}
|