@amritk/nish-x86_64-linux 0.18.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.
- package/INSTALL.md +43 -25
- package/bin/nish +0 -0
- package/package.json +2 -2
- package/runtime/nish.d.ts +55 -5
- package/runtime/nish.h +215 -18
- package/runtime/nish.mjs +16 -0
- package/runtime/runtime-aes.c +490 -0
- package/runtime/runtime-cross.c +366 -0
- package/runtime/runtime-host.c +7 -6
- package/runtime/runtime-net.c +93 -34
- package/runtime/runtime-os.c +213 -15
- package/runtime/runtime-parallel.c +590 -107
- package/runtime/runtime-simd.c +4 -4
- package/runtime/runtime-wasm.c +5 -3
- package/runtime/runtime.c +69 -13
- package/runtime/shim.mjs +71 -1
- package/scripts/build.sh +223 -22
- package/std/README.md +81 -51
- package/std/bytes.ts +163 -0
- package/std/crypto/LICENSE-libsecp256k1 +19 -0
- package/std/crypto/aes.ts +238 -76
- package/std/crypto/chacha20poly1305.ts +43 -9
- package/std/crypto/ed25519.ts +840 -0
- package/std/crypto/hkdf.ts +304 -12
- package/std/crypto/hmac.ts +245 -53
- package/std/crypto/p256.ts +932 -61
- package/std/crypto/x25519.ts +55 -37
- package/std/crypto/x509-random.ts +71 -0
- package/std/crypto/x509.ts +9 -9
- package/std/json-tokenizer.ts +1296 -0
- package/std/json-typed.ts +1014 -0
- package/std/json-value.ts +1163 -0
- package/std/json.ts +1120 -34
- package/std/net/buffer-pool.ts +151 -0
- package/std/net/hpack.ts +416 -112
- package/std/net/http-fields.ts +93 -0
- package/std/net/http1-server.ts +417 -55
- package/std/net/http1.ts +31 -6
- package/std/net/http2-tls.ts +112 -24
- package/std/net/http2.ts +333 -75
- package/std/net/http3-server.ts +211 -31
- package/std/net/http3.ts +187 -28
- package/std/net/prefork.ts +412 -0
- package/std/net/quic-listener.ts +88 -7
- package/std/net/quic-packet.ts +243 -82
- package/std/net/quic-recovery.ts +361 -30
- package/std/net/quic-stream.ts +424 -24
- package/std/net/quic.ts +519 -167
- package/std/net/router.ts +676 -0
- package/std/net/tls/codec.ts +426 -27
- package/std/net/tls/record-server.ts +478 -132
- package/std/net/tls/record.ts +133 -42
- package/std/net/tls/schedule.ts +464 -55
- package/std/net/tls/ticket.ts +610 -0
- package/std/net/tls-tcp.ts +196 -53
- package/std/net/tls.ts +1018 -260
- package/std/net/url.ts +571 -0
- package/std/random.ts +94 -0
- package/std/threads.ts +438 -14
package/std/crypto/x25519.ts
CHANGED
|
@@ -64,7 +64,14 @@
|
|
|
64
64
|
* `exposeWith`, and the clamped copy and every ladder element are wiped before
|
|
65
65
|
* it returns (ECC-2, docs/security/crypto-ecc.md).
|
|
66
66
|
*
|
|
67
|
-
*
|
|
67
|
+
* **The field is shared with Ed25519.** `nish/crypto/ed25519` works over the
|
|
68
|
+
* same GF(p), so the `f25519` functions are exported for it to import rather
|
|
69
|
+
* than written twice; they are the module's internals, with the bounds each
|
|
70
|
+
* one states, not an API for programs. Ed25519's square root needs
|
|
71
|
+
* `z^(2^252 - 3)`, which shares its first 250 bits with the inversion's
|
|
72
|
+
* exponent, so that part of the chain is `f25519Pow250`, which both call.
|
|
73
|
+
*
|
|
74
|
+
* Names carry the `f25519` / `x25519` prefix because a `std/` module's
|
|
68
75
|
* private functions share the importing program's flat symbol namespace
|
|
69
76
|
* (`docs/wp26-stdlib.md` §3e).
|
|
70
77
|
*/
|
|
@@ -84,9 +91,9 @@ const X25519_A24: i64 = 121665
|
|
|
84
91
|
* because signed arithmetic is checked for an overflow, and a check is a
|
|
85
92
|
* branch on a secret limb. Each is one instruction once LLVM inlines it.
|
|
86
93
|
*/
|
|
87
|
-
const f25519Add64 = (a: i64, b: i64): i64 => toI64(toU64(a) + toU64(b))
|
|
88
|
-
const f25519Sub64 = (a: i64, b: i64): i64 => toI64(toU64(a) - toU64(b))
|
|
89
|
-
const f25519Mul64 = (a: i64, b: i64): i64 => toI64(toU64(a) * toU64(b))
|
|
94
|
+
export const f25519Add64 = (a: i64, b: i64): i64 => toI64(toU64(a) + toU64(b))
|
|
95
|
+
export const f25519Sub64 = (a: i64, b: i64): i64 => toI64(toU64(a) - toU64(b))
|
|
96
|
+
export const f25519Mul64 = (a: i64, b: i64): i64 => toI64(toU64(a) * toU64(b))
|
|
90
97
|
|
|
91
98
|
/** The width of limb `i`: 26 bits for an even limb, 25 for an odd one. */
|
|
92
99
|
const f25519Width = (i: i32): i64 => {
|
|
@@ -98,20 +105,20 @@ const f25519Width = (i: i32): i64 => {
|
|
|
98
105
|
const f25519LimbMask = (i: i32): i64 => f25519Sub64(toI64(1) << f25519Width(i), toI64(1))
|
|
99
106
|
|
|
100
107
|
/** A fresh field element, zero. */
|
|
101
|
-
const f25519Zero = (): i64[] => {
|
|
108
|
+
export const f25519Zero = (): i64[] => {
|
|
102
109
|
const f: i64[] = new Array<i64>(10)
|
|
103
110
|
return f
|
|
104
111
|
}
|
|
105
112
|
|
|
106
113
|
/** A fresh field element holding the small constant `n`. */
|
|
107
|
-
const f25519Small = (n: i64): i64[] => {
|
|
114
|
+
export const f25519Small = (n: i64): i64[] => {
|
|
108
115
|
const f: i64[] = f25519Zero()
|
|
109
116
|
f[0] = n
|
|
110
117
|
return f
|
|
111
118
|
}
|
|
112
119
|
|
|
113
120
|
/** `out = f`, limb by limb. */
|
|
114
|
-
const f25519Copy = (out: i64[], f: i64[]): void => {
|
|
121
|
+
export const f25519Copy = (out: i64[], f: i64[]): void => {
|
|
115
122
|
if (toI32(out.length) < 10 || toI32(f.length) < 10) {
|
|
116
123
|
return
|
|
117
124
|
}
|
|
@@ -152,7 +159,7 @@ const f25519CarryChain = (h: i64[]): void => {
|
|
|
152
159
|
* `h & (2^width - 1)`, which is the matching non-negative remainder for a
|
|
153
160
|
* negative limb too, without shifting a negative number left.
|
|
154
161
|
*/
|
|
155
|
-
const f25519Carry = (h: i64[]): void => {
|
|
162
|
+
export const f25519Carry = (h: i64[]): void => {
|
|
156
163
|
if (toI32(h.length) < 10) {
|
|
157
164
|
return
|
|
158
165
|
}
|
|
@@ -169,7 +176,7 @@ const f25519Carry = (h: i64[]): void => {
|
|
|
169
176
|
* `out = f + g`, not carried. With both reduced (limbs below 2^26 in
|
|
170
177
|
* magnitude) the sum's limbs are below 2^27, which `f25519Mul` accepts.
|
|
171
178
|
*/
|
|
172
|
-
const f25519Add = (out: i64[], f: i64[], g: i64[]): void => {
|
|
179
|
+
export const f25519Add = (out: i64[], f: i64[], g: i64[]): void => {
|
|
173
180
|
if (toI32(out.length) < 10 || toI32(f.length) < 10 || toI32(g.length) < 10) {
|
|
174
181
|
return
|
|
175
182
|
}
|
|
@@ -183,7 +190,7 @@ const f25519Add = (out: i64[], f: i64[], g: i64[]): void => {
|
|
|
183
190
|
* both reduced the difference's limbs are below 2^27 in magnitude, which
|
|
184
191
|
* `f25519Mul` accepts.
|
|
185
192
|
*/
|
|
186
|
-
const f25519Sub = (out: i64[], f: i64[], g: i64[]): void => {
|
|
193
|
+
export const f25519Sub = (out: i64[], f: i64[], g: i64[]): void => {
|
|
187
194
|
if (toI32(out.length) < 10 || toI32(f.length) < 10 || toI32(g.length) < 10) {
|
|
188
195
|
return
|
|
189
196
|
}
|
|
@@ -208,7 +215,7 @@ const f25519Sub = (out: i64[], f: i64[], g: i64[]): void => {
|
|
|
208
215
|
* sums added again, say — breaks this bound, which is why every caller carries
|
|
209
216
|
* or multiplies before it adds a second time.
|
|
210
217
|
*/
|
|
211
|
-
const f25519Mul = (out: i64[], f: i64[], g: i64[]): void => {
|
|
218
|
+
export const f25519Mul = (out: i64[], f: i64[], g: i64[]): void => {
|
|
212
219
|
if (toI32(f.length) < 10 || toI32(g.length) < 10) {
|
|
213
220
|
return
|
|
214
221
|
}
|
|
@@ -240,12 +247,12 @@ const f25519Mul = (out: i64[], f: i64[], g: i64[]): void => {
|
|
|
240
247
|
}
|
|
241
248
|
|
|
242
249
|
/** `out = f * f`, reduced; the same bounds as `f25519Mul`. */
|
|
243
|
-
const f25519Square = (out: i64[], f: i64[]): void => {
|
|
250
|
+
export const f25519Square = (out: i64[], f: i64[]): void => {
|
|
244
251
|
f25519Mul(out, f, f)
|
|
245
252
|
}
|
|
246
253
|
|
|
247
254
|
/** `out = f` squared `n` times in a row (`n` at least 1), reduced. */
|
|
248
|
-
const f25519SquareTimes = (out: i64[], f: i64[], n: i32): void => {
|
|
255
|
+
export const f25519SquareTimes = (out: i64[], f: i64[], n: i32): void => {
|
|
249
256
|
f25519Square(out, f)
|
|
250
257
|
for (let i: i32 = 1; i < n; i++) {
|
|
251
258
|
f25519Square(out, out)
|
|
@@ -268,25 +275,20 @@ const f25519MulA24 = (out: i64[], f: i64[]): void => {
|
|
|
268
275
|
}
|
|
269
276
|
|
|
270
277
|
/**
|
|
271
|
-
* `out = z^(
|
|
272
|
-
*
|
|
273
|
-
*
|
|
274
|
-
*
|
|
275
|
-
*
|
|
276
|
-
*
|
|
277
|
-
* `z^(2^(a+b) - 1) = (z^(2^a - 1))^(2^b) * z^(2^b - 1)`, then squares five
|
|
278
|
-
* times and multiplies by `z^11`: 254 squarings and 11 multiplications, the
|
|
279
|
-
* same for every `z`.
|
|
278
|
+
* `out = z^(2^250 - 1)` and `z11 = z^11`: the part of the exponent chain that
|
|
279
|
+
* `f25519Invert` and Ed25519's square root (`ed25519Pow22523`,
|
|
280
|
+
* `nish/crypto/ed25519`) share. The chain builds `z^(2^n - 1)` for n = 2, 4,
|
|
281
|
+
* 5, 10, 20, 40, 50, 100, 200 and 250 from the rule
|
|
282
|
+
* `z^(2^(a+b) - 1) = (z^(2^a - 1))^(2^b) * z^(2^b - 1)`: 251 squarings and 11
|
|
283
|
+
* multiplications, the same for every `z`. `out` and `z11` may not be `z`.
|
|
280
284
|
*/
|
|
281
|
-
const
|
|
285
|
+
export const f25519Pow250 = (out: i64[], z11: i64[], z: i64[]): void => {
|
|
282
286
|
const z2: i64[] = f25519Zero()
|
|
283
|
-
const z11: i64[] = f25519Zero()
|
|
284
287
|
const e2: i64[] = f25519Zero()
|
|
285
288
|
const e5: i64[] = f25519Zero()
|
|
286
289
|
const e10: i64[] = f25519Zero()
|
|
287
290
|
const e50: i64[] = f25519Zero()
|
|
288
291
|
const t: i64[] = f25519Zero()
|
|
289
|
-
const acc: i64[] = f25519Zero()
|
|
290
292
|
|
|
291
293
|
f25519Square(z2, z)
|
|
292
294
|
f25519Mul(e2, z2, z) // z^3 = z^(2^2 - 1)
|
|
@@ -300,17 +302,33 @@ const f25519Invert = (out: i64[], z: i64[]): void => {
|
|
|
300
302
|
f25519SquareTimes(t, e5, 5)
|
|
301
303
|
f25519Mul(e10, t, e5) // 2^10 - 1
|
|
302
304
|
f25519SquareTimes(t, e10, 10)
|
|
303
|
-
f25519Mul(
|
|
304
|
-
f25519SquareTimes(t,
|
|
305
|
-
f25519Mul(
|
|
306
|
-
f25519SquareTimes(t,
|
|
305
|
+
f25519Mul(out, t, e10) // 2^20 - 1
|
|
306
|
+
f25519SquareTimes(t, out, 20)
|
|
307
|
+
f25519Mul(out, t, out) // 2^40 - 1
|
|
308
|
+
f25519SquareTimes(t, out, 10)
|
|
307
309
|
f25519Mul(e50, t, e10) // 2^50 - 1
|
|
308
310
|
f25519SquareTimes(t, e50, 50)
|
|
309
|
-
f25519Mul(
|
|
310
|
-
f25519SquareTimes(t,
|
|
311
|
-
f25519Mul(
|
|
312
|
-
f25519SquareTimes(t,
|
|
313
|
-
f25519Mul(
|
|
311
|
+
f25519Mul(out, t, e50) // 2^100 - 1
|
|
312
|
+
f25519SquareTimes(t, out, 100)
|
|
313
|
+
f25519Mul(out, t, out) // 2^200 - 1
|
|
314
|
+
f25519SquareTimes(t, out, 50)
|
|
315
|
+
f25519Mul(out, t, e50) // 2^250 - 1
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* `out = z^(p - 2)`, which is `1 / z` by Fermat's little theorem, and zero for
|
|
320
|
+
* a zero `z` — what RFC 7748 §5 asks of the ladder's last step.
|
|
321
|
+
*
|
|
322
|
+
* p - 2 = 2^255 - 21 = (2^250 - 1) * 2^5 + 11, so the exponent is 250 ones
|
|
323
|
+
* followed by `01011`: `f25519Pow250`, then five squarings and a
|
|
324
|
+
* multiplication by `z^11` — 256 squarings and 12 multiplications, the same
|
|
325
|
+
* for every `z`.
|
|
326
|
+
*/
|
|
327
|
+
export const f25519Invert = (out: i64[], z: i64[]): void => {
|
|
328
|
+
const z11: i64[] = f25519Zero()
|
|
329
|
+
const acc: i64[] = f25519Zero()
|
|
330
|
+
const t: i64[] = f25519Zero()
|
|
331
|
+
f25519Pow250(acc, z11, z)
|
|
314
332
|
f25519SquareTimes(t, acc, 5)
|
|
315
333
|
f25519Mul(out, t, z11) // 2^255 - 21
|
|
316
334
|
}
|
|
@@ -320,7 +338,7 @@ const f25519Invert = (out: i64[], z: i64[]): void => {
|
|
|
320
338
|
* same instructions either way: the mask is all ones or all zeros, and the
|
|
321
339
|
* swap is the masked xor of the two.
|
|
322
340
|
*/
|
|
323
|
-
const f25519Swap = (f: i64[], g: i64[], bit: i64): void => {
|
|
341
|
+
export const f25519Swap = (f: i64[], g: i64[], bit: i64): void => {
|
|
324
342
|
if (toI32(f.length) < 10 || toI32(g.length) < 10) {
|
|
325
343
|
return
|
|
326
344
|
}
|
|
@@ -341,7 +359,7 @@ const f25519Swap = (f: i64[], g: i64[], bit: i64): void => {
|
|
|
341
359
|
* `[p, 2^255)` is neither refused nor adjusted: §5 has it processed as its
|
|
342
360
|
* residue, and the arithmetic does that by itself.
|
|
343
361
|
*/
|
|
344
|
-
const f25519Decode = (bytes: u8[]): i64[] => {
|
|
362
|
+
export const f25519Decode = (bytes: u8[]): i64[] => {
|
|
345
363
|
const f: i64[] = new Array<i64>(10)
|
|
346
364
|
if (toI32(bytes.length) < 32) {
|
|
347
365
|
return f
|
|
@@ -382,7 +400,7 @@ const f25519Decode = (bytes: u8[]): i64[] => {
|
|
|
382
400
|
* when the value is at least p — so the element adds `19 * q` and drops bit
|
|
383
401
|
* 255, which is subtracting `p * q`.
|
|
384
402
|
*/
|
|
385
|
-
const f25519Encode = (f: i64[]): u8[] => {
|
|
403
|
+
export const f25519Encode = (f: i64[]): u8[] => {
|
|
386
404
|
const h: i64[] = new Array<i64>(10)
|
|
387
405
|
f25519Copy(h, f)
|
|
388
406
|
f25519Carry(h)
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `nish/crypto/x509-random` — the private key and the serial number
|
|
3
|
+
* `nish/crypto/x509`'s `x509MintSelfSigned` needs, drawn from the operating
|
|
4
|
+
* system's CSPRNG, and the mint that draws its own serial.
|
|
5
|
+
*
|
|
6
|
+
* import { Secret, wipe } from "nish:secret";
|
|
7
|
+
* import { x509DrawP256Key, x509MintSelfSignedDrawn } from "nish/crypto/x509-random";
|
|
8
|
+
*
|
|
9
|
+
* const priv: Secret<u8[]> = x509DrawP256Key();
|
|
10
|
+
* const der: u8[] | null = x509MintSelfSignedDrawn(priv, "localhost", toI64(Date.now()), 14);
|
|
11
|
+
* // ... present `der` and sign the handshake with `priv` ...
|
|
12
|
+
* wipe(priv);
|
|
13
|
+
*
|
|
14
|
+
* **Native only.** Every function here reaches `crypto.getRandomValues`, so a
|
|
15
|
+
* program that imports this module does not compile for wasm32, which has no
|
|
16
|
+
* entropy to reach. That is why it is a module of its own: `nish/crypto/x509`
|
|
17
|
+
* takes the key and the serial as arguments and imports nothing from here, so
|
|
18
|
+
* a wasm32 program can still parse, verify and mint with bytes it was handed
|
|
19
|
+
* (X509-6, docs/security/crypto-x509.md).
|
|
20
|
+
*/
|
|
21
|
+
import { Secret, secret, wipe } from "nish:secret"
|
|
22
|
+
import { P256_SCALAR_SIZE, p256PublicKey } from "nish/crypto/p256"
|
|
23
|
+
import { X509_MAX_SERIAL, x509MintSelfSigned } from "nish/crypto/x509"
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* A fresh P-256 private key: `P256_SCALAR_SIZE` bytes from
|
|
27
|
+
* `crypto.getRandomValues`, drawn again until they hold a scalar in [1, n),
|
|
28
|
+
* which `p256PublicKey` is the test of. Rejection rather than reduction mod n,
|
|
29
|
+
* so every key is equally likely; a draw is refused with odds below 2^-32. A
|
|
30
|
+
* refused draw is wiped before the next, and the caller wipes the one
|
|
31
|
+
* returned.
|
|
32
|
+
*/
|
|
33
|
+
export const x509DrawP256Key = (): Secret<u8[]> => {
|
|
34
|
+
while (true) {
|
|
35
|
+
const drawn: u8[] = new Array<u8>(P256_SCALAR_SIZE)
|
|
36
|
+
crypto.getRandomValues(drawn)
|
|
37
|
+
const key: Secret<u8[]> = secret(drawn)
|
|
38
|
+
if (p256PublicKey(key) !== null) {
|
|
39
|
+
return key
|
|
40
|
+
}
|
|
41
|
+
wipe(key)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* A fresh serial number for `x509MintSelfSigned`: `X509_MAX_SERIAL` (20) bytes
|
|
47
|
+
* from `crypto.getRandomValues` with the first one's top two bits set to `01`,
|
|
48
|
+
* so the INTEGER is positive, never zero, and always twenty octets long — 158
|
|
49
|
+
* random bits, past the 64 the CA/Browser Forum asks of a serial. A serial is
|
|
50
|
+
* public, written into the certificate, so it is a plain array.
|
|
51
|
+
*/
|
|
52
|
+
export const x509DrawSerial = (): u8[] => {
|
|
53
|
+
const serial: u8[] = new Array<u8>(X509_MAX_SERIAL)
|
|
54
|
+
crypto.getRandomValues(serial)
|
|
55
|
+
serial[0] = (serial[0] & toU8(0x3f)) | toU8(0x40)
|
|
56
|
+
return serial
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* `x509MintSelfSigned(priv, commonName, notBeforeMs, days, x509DrawSerial())`:
|
|
61
|
+
* the self-signed certificate with a serial drawn here, `null` for everything
|
|
62
|
+
* the mint answers `null` for. The key stays the caller's, since the server
|
|
63
|
+
* that presents the certificate signs its handshakes with it; draw one with
|
|
64
|
+
* `x509DrawP256Key`.
|
|
65
|
+
*/
|
|
66
|
+
export const x509MintSelfSignedDrawn = (
|
|
67
|
+
priv: Secret<u8[]>,
|
|
68
|
+
commonName: string,
|
|
69
|
+
notBeforeMs: i64,
|
|
70
|
+
days: i32
|
|
71
|
+
): u8[] | null => x509MintSelfSigned(priv, commonName, notBeforeMs, days, x509DrawSerial())
|
package/std/crypto/x509.ts
CHANGED
|
@@ -5,15 +5,13 @@
|
|
|
5
5
|
* pins by its SHA-256.
|
|
6
6
|
*
|
|
7
7
|
* import { x509MintSelfSigned, x509CertificateHash, derToPem } from "nish/crypto/x509";
|
|
8
|
+
* // Native only: a program that imports this does not compile for wasm32, which has no entropy.
|
|
9
|
+
* import { x509DrawP256Key, x509DrawSerial } from "nish/crypto/x509-random";
|
|
8
10
|
*
|
|
9
|
-
* // Both
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* const
|
|
13
|
-
* const serial: u8[] = new Array<u8>(16);
|
|
14
|
-
* crypto.getRandomValues(serial);
|
|
15
|
-
* serial[0] = serial[0] & toU8(0x7f); // positive, so it stays 16 octets
|
|
16
|
-
* const der: u8[] | null = x509MintSelfSigned(priv, "localhost", toI64(Date.now()), 14, serial);
|
|
11
|
+
* // Both come from the kernel's CSPRNG; a predictable key or serial is the caller's bug.
|
|
12
|
+
* // A wasm32 program is handed them instead, and passes them in as they are passed here.
|
|
13
|
+
* const priv: Secret<u8[]> = x509DrawP256Key();
|
|
14
|
+
* const der: u8[] | null = x509MintSelfSigned(priv, "localhost", toI64(Date.now()), 14, x509DrawSerial());
|
|
17
15
|
* wipe(priv);
|
|
18
16
|
* // x509CertificateHash(der) is what serverCertificateHashes names;
|
|
19
17
|
* // derToPem(der, "CERTIFICATE") is the file a TLS stack loads.
|
|
@@ -68,7 +66,9 @@
|
|
|
68
66
|
* parameters so the golden certificate is deterministic; a caller passes
|
|
69
67
|
* `Date.now()` and, for the key and the serial, bytes from
|
|
70
68
|
* `crypto.getRandomValues`. This module does not draw them itself,
|
|
71
|
-
* because a call to the operating system would stop it compiling for wasm32
|
|
69
|
+
* because a call to the operating system would stop it compiling for wasm32;
|
|
70
|
+
* `nish/crypto/x509-random`, which this module does not import, draws both
|
|
71
|
+
* for a native program (X509-6).
|
|
72
72
|
*
|
|
73
73
|
* **Constant time.** A private key is the one secret that passes through here:
|
|
74
74
|
* it is base64-decoded from PEM, lifted out of its DER, and handed to
|