@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.
Files changed (59) 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 +215 -18
  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 +4 -4
  14. package/runtime/runtime-wasm.c +5 -3
  15. package/runtime/runtime.c +69 -13
  16. package/runtime/shim.mjs +71 -1
  17. package/scripts/build.sh +223 -22
  18. package/std/README.md +81 -51
  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 +932 -61
  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 +1120 -34
  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 +211 -31
  42. package/std/net/http3.ts +187 -28
  43. package/std/net/prefork.ts +412 -0
  44. package/std/net/quic-listener.ts +88 -7
  45. package/std/net/quic-packet.ts +243 -82
  46. package/std/net/quic-recovery.ts +361 -30
  47. package/std/net/quic-stream.ts +424 -24
  48. package/std/net/quic.ts +519 -167
  49. package/std/net/router.ts +676 -0
  50. package/std/net/tls/codec.ts +426 -27
  51. package/std/net/tls/record-server.ts +478 -132
  52. package/std/net/tls/record.ts +133 -42
  53. package/std/net/tls/schedule.ts +464 -55
  54. package/std/net/tls/ticket.ts +610 -0
  55. package/std/net/tls-tcp.ts +196 -53
  56. package/std/net/tls.ts +1018 -260
  57. package/std/net/url.ts +571 -0
  58. package/std/random.ts +94 -0
  59. package/std/threads.ts +438 -14
@@ -0,0 +1,840 @@
1
+ /**
2
+ * `nish/crypto/ed25519` — the Ed25519 signature scheme of RFC 8032 (§5.1).
3
+ *
4
+ * Written from the specification (RFC 8032 §5.1.1 to §5.1.7), in this
5
+ * module's own structure: nothing here is ported from another implementation.
6
+ * The field is `nish/crypto/x25519`'s GF(2^255 - 19), imported rather than
7
+ * written twice, and SHA-512 is `nish/crypto/sha512`'s. The point formulas are
8
+ * the extended twisted Edwards ones of Hisil, Wong, Carter and Dawson,
9
+ * "Twisted Edwards Curves Revisited" (ASIACRYPT 2008), for a = -1; the code is
10
+ * this module's.
11
+ *
12
+ * **The curve.** -x^2 + y^2 = 1 + d x^2 y^2 over GF(p), d = -121665/121666. A
13
+ * point is held in extended coordinates (X : Y : Z : T), x = X/Z, y = Y/Z and
14
+ * x y = T/Z. The addition is complete — it is right for every pair of points,
15
+ * the identity and a point added to itself included, because -1 is a square
16
+ * and d is not — so no input steers it down another path. A point about to be
17
+ * added is first put in the "cached" form (Y + X, Y - X, 2 d T, 2 Z) the
18
+ * addition reads.
19
+ *
20
+ * **Bounds.** `f25519Mul` accepts limbs below 2^27 in magnitude: a reduced
21
+ * element, or one sum or difference of two. Every product below is given one
22
+ * of those; a value two sums away from reduced (`F` and `E` in the doubling)
23
+ * is carried first, and so is every cached coordinate. The field functions
24
+ * state their own bounds (`nish/crypto/x25519`).
25
+ *
26
+ * **Constant time, by construction.** Signing and the public key multiply
27
+ * the base point by a secret scalar, and that multiplication branches on and
28
+ * indexes by nothing the scalar reaches. The scalar is recoded into 64 signed
29
+ * radix-16 digits in [-8, 8]; each step doubles four times and adds the table
30
+ * entry for the digit, which is chosen by reading all eight entries and
31
+ * keeping one under a mask, and negated with a masked swap and a masked
32
+ * select. The digit arithmetic and the masks use `f25519Add64`, `f25519Sub64`
33
+ * and `f25519Mul64`, because signed overflow is undefined and a checked
34
+ * operation branches. The reductions mod L run a fixed 512 steps of a
35
+ * shift and a masked conditional subtraction over 32-bit limbs in `u64`,
36
+ * whose subtraction wraps. Every `if` and every loop bound is on a public
37
+ * quantity: a digit position, a limb number, a bit position or a length.
38
+ * This is discipline, checked by reading, not by a disassembly fixture as
39
+ * `f25519Mul` and the X25519 ladder are (ECC-5, docs/security/crypto-ecc.md).
40
+ *
41
+ * **Verification is variable time.** Every value `ed25519Verify` handles is
42
+ * public — the key, the message and the signature — so it may branch on them:
43
+ * it refuses early, and compares the final encoding byte by byte. It uses the
44
+ * same multiplication as signing all the same.
45
+ *
46
+ * **What is refused.** `ed25519Verify` is RFC 8032 §5.1.7 with the cofactorless
47
+ * equation [S]B = R + [k]A: an S of L or more, a public key whose y is not
48
+ * below p or that is not on the curve, and an x of zero with the sign bit set
49
+ * are all refused (§5.1.3). R is not decoded: [S]B - [k]A is encoded and
50
+ * compared with R's bytes, and since the encoding is canonical, an R that is
51
+ * not the canonical encoding of a point never matches. A public key of small
52
+ * order is not refused, as RFC 8032 does not ask it to be: under such a key,
53
+ * some signatures verify for messages its owner never signed, so a protocol
54
+ * that needs a signature to bind one key checks the key itself.
55
+ *
56
+ * **The seed is a `Secret`** (`nish:secret`, docs/LANGUAGE.md "Secrets").
57
+ * `ed25519PublicKey` and `ed25519Sign` take the 32-byte seed as a
58
+ * `Secret<u8[]>` and run inside `expose` / `exposeWith`; the seed's hash, the
59
+ * clamped scalar and the prefix, the nonce and its hash, the digits, the
60
+ * accumulator, the selected table entry and the formula temporaries are all
61
+ * wiped before they return, and so are both SHA-512 states (ECC-5).
62
+ *
63
+ * **Loop bounds are literals.** As in `nish/crypto/x25519`, each function that
64
+ * indexes an array opens with an early `return` for a shorter one, which
65
+ * cannot happen but lets the compiler drop the loops' bounds checks.
66
+ *
67
+ * Private names carry the `ed25519` / `Ed25519` prefix because a `std/`
68
+ * module's private functions share the importing program's flat symbol
69
+ * namespace (`docs/wp26-stdlib.md` §3e).
70
+ */
71
+
72
+ import { Secret, expose, exposeWith, wipe } from "nish:secret"
73
+ import { SHA512_SIZE, Sha512 } from "nish/crypto/sha512"
74
+ import {
75
+ f25519Add,
76
+ f25519Add64,
77
+ f25519Carry,
78
+ f25519Copy,
79
+ f25519Decode,
80
+ f25519Encode,
81
+ f25519Invert,
82
+ f25519Mul,
83
+ f25519Mul64,
84
+ f25519Pow250,
85
+ f25519Small,
86
+ f25519Square,
87
+ f25519SquareTimes,
88
+ f25519Sub,
89
+ f25519Sub64,
90
+ f25519Swap,
91
+ f25519Zero,
92
+ } from "nish/crypto/x25519"
93
+
94
+ /** The length in bytes of a seed (the private key), RFC 8032 §5.1.5. */
95
+ export const ED25519_SEED_SIZE: i32 = 32
96
+
97
+ /** The length in bytes of an encoded public key. */
98
+ export const ED25519_PUBLIC_KEY_SIZE: i32 = 32
99
+
100
+ /** The length in bytes of a signature, `R || S`. */
101
+ export const ED25519_SIGNATURE_SIZE: i32 = 64
102
+
103
+ /** Where a method call starts reading an array: its first byte. */
104
+ const ED25519_FROM: i32 = 0
105
+
106
+ /** Where the prefix starts in the seed's hash, and how long R, A and a scalar are. */
107
+ const ED25519_HALF: i32 = 32
108
+
109
+ /** The limbs of one table entry: four field elements of ten. */
110
+ const ED25519_ENTRY: i32 = 40
111
+
112
+ /** d = -121665/121666, the curve's constant, little-endian (RFC 8032 §5.1). */
113
+ const ed25519D = (): i64[] => {
114
+ const bytes: u8[] = [
115
+ 0xa3, 0x78, 0x59, 0x13, 0xca, 0x4d, 0xeb, 0x75, 0xab, 0xd8, 0x41, 0x41, 0x4d, 0x0a, 0x70, 0x00, 0x98,
116
+ 0xe8, 0x79, 0x77, 0x79, 0x40, 0xc7, 0x8c, 0x73, 0xfe, 0x6f, 0x2b, 0xee, 0x6c, 0x03, 0x52,
117
+ ]
118
+ return f25519Decode(bytes)
119
+ }
120
+
121
+ /** sqrt(-1) = 2^((p - 1) / 4), which §5.1.3 multiplies a candidate x by. */
122
+ const ed25519SqrtM1 = (): i64[] => {
123
+ const bytes: u8[] = [
124
+ 0xb0, 0xa0, 0x0e, 0x4a, 0x27, 0x1b, 0xee, 0xc4, 0x78, 0xe4, 0x2f, 0xad, 0x06, 0x18, 0x43, 0x2f, 0xa7,
125
+ 0xd7, 0xfb, 0x3d, 0x99, 0x00, 0x4d, 0x2b, 0x0b, 0xdf, 0xc1, 0x4f, 0x80, 0x24, 0x83, 0x2b,
126
+ ]
127
+ return f25519Decode(bytes)
128
+ }
129
+
130
+ /** The base point B's x (RFC 8032 §5.1). */
131
+ const ed25519BaseX = (): i64[] => {
132
+ const bytes: u8[] = [
133
+ 0x1a, 0xd5, 0x25, 0x8f, 0x60, 0x2d, 0x56, 0xc9, 0xb2, 0xa7, 0x25, 0x95, 0x60, 0xc7, 0x2c, 0x69, 0x5c,
134
+ 0xdc, 0xd6, 0xfd, 0x31, 0xe2, 0xa4, 0xc0, 0xfe, 0x53, 0x6e, 0xcd, 0xd3, 0x36, 0x69, 0x21,
135
+ ]
136
+ return f25519Decode(bytes)
137
+ }
138
+
139
+ /** The base point B's y, 4/5 (RFC 8032 §5.1). */
140
+ const ed25519BaseY = (): i64[] => {
141
+ const bytes: u8[] = [
142
+ 0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
143
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
144
+ ]
145
+ return f25519Decode(bytes)
146
+ }
147
+
148
+ /** L = 2^252 + 27742317777372353535851937790883648493, the group order, as eight 32-bit limbs. */
149
+ const ed25519Order = (): u64[] => [
150
+ 0x5cf5d3ed, 0x5812631a, 0xa2f79cd6, 0x14def9de, 0x00000000, 0x00000000, 0x00000000, 0x10000000,
151
+ ]
152
+
153
+ /** A point (X : Y : Z : T) in extended coordinates. */
154
+ class Ed25519Point {
155
+ x: i64[]
156
+ y: i64[]
157
+ z: i64[]
158
+ t: i64[]
159
+
160
+ /** The identity, (0 : 1 : 1 : 0). */
161
+ constructor() {
162
+ this.x = f25519Zero()
163
+ this.y = f25519Small(toI64(1))
164
+ this.z = f25519Small(toI64(1))
165
+ this.t = f25519Zero()
166
+ }
167
+ }
168
+
169
+ /** A point in the form the addition reads: (Y + X, Y - X, 2 d T, 2 Z), each carried. */
170
+ class Ed25519Cached {
171
+ ypx: i64[]
172
+ ymx: i64[]
173
+ t2d: i64[]
174
+ z2: i64[]
175
+
176
+ /** The identity, (1, 1, 0, 2). */
177
+ constructor() {
178
+ this.ypx = f25519Small(toI64(1))
179
+ this.ymx = f25519Small(toI64(1))
180
+ this.t2d = f25519Zero()
181
+ this.z2 = f25519Small(toI64(2))
182
+ }
183
+ }
184
+
185
+ /**
186
+ * The temporaries of the point formulas, allocated once per operation rather
187
+ * than once per step; the entry a multiplication selects; the point a table
188
+ * is built in; and 2 d, which the cached form multiplies by.
189
+ */
190
+ class Ed25519Scratch {
191
+ a: i64[]
192
+ b: i64[]
193
+ c: i64[]
194
+ d: i64[]
195
+ e: i64[]
196
+ f: i64[]
197
+ g: i64[]
198
+ h: i64[]
199
+ entry: Ed25519Cached
200
+ sum: Ed25519Point
201
+ d2: i64[]
202
+
203
+ constructor() {
204
+ this.a = f25519Zero()
205
+ this.b = f25519Zero()
206
+ this.c = f25519Zero()
207
+ this.d = f25519Zero()
208
+ this.e = f25519Zero()
209
+ this.f = f25519Zero()
210
+ this.g = f25519Zero()
211
+ this.h = f25519Zero()
212
+ this.entry = new Ed25519Cached()
213
+ this.sum = new Ed25519Point()
214
+ this.d2 = ed25519D()
215
+ f25519Add(this.d2, this.d2, this.d2)
216
+ f25519Carry(this.d2)
217
+ }
218
+ }
219
+
220
+ /** Zero `p`'s four coordinates, with the store `nish:secret` keeps from the optimiser (ECC-5). */
221
+ const ed25519WipePoint = (p: Ed25519Point): void => {
222
+ wipe(p.x)
223
+ wipe(p.y)
224
+ wipe(p.z)
225
+ wipe(p.t)
226
+ }
227
+
228
+ /** Zero every temporary a point operation left in `s`; `d2` is the curve's public constant. */
229
+ const ed25519WipeScratch = (s: Ed25519Scratch): void => {
230
+ wipe(s.a)
231
+ wipe(s.b)
232
+ wipe(s.c)
233
+ wipe(s.d)
234
+ wipe(s.e)
235
+ wipe(s.f)
236
+ wipe(s.g)
237
+ wipe(s.h)
238
+ wipe(s.entry.ypx)
239
+ wipe(s.entry.ymx)
240
+ wipe(s.entry.t2d)
241
+ wipe(s.entry.z2)
242
+ ed25519WipePoint(s.sum)
243
+ }
244
+
245
+ /**
246
+ * Zero what a SHA-512 hasher holds of what it was fed — its hash value, its
247
+ * pending block and its message schedule — as `nish/crypto/hmac` does.
248
+ */
249
+ const ed25519WipeHasher = (h: Sha512): void => {
250
+ wipe(h.engine.state)
251
+ wipe(h.engine.block)
252
+ wipe(h.engine.schedule)
253
+ }
254
+
255
+ /** `out = p` in the cached form. */
256
+ const ed25519ToCached = (out: Ed25519Cached, p: Ed25519Point, s: Ed25519Scratch): void => {
257
+ f25519Add(out.ypx, p.y, p.x)
258
+ f25519Carry(out.ypx)
259
+ f25519Sub(out.ymx, p.y, p.x)
260
+ f25519Carry(out.ymx)
261
+ f25519Mul(out.t2d, p.t, s.d2)
262
+ f25519Add(out.z2, p.z, p.z)
263
+ f25519Carry(out.z2)
264
+ }
265
+
266
+ /**
267
+ * `out = p + q` ("add-2008-hwcd-3" for a = -1, with q cached). `out` may be
268
+ * `p`: `p` is read only into the temporaries, before `out` is written.
269
+ * `A`, `B`, `C` and `D` are products, so reduced, and `E`, `F`, `G` and `H`
270
+ * are one sum or difference of two of them.
271
+ */
272
+ const ed25519Add = (out: Ed25519Point, p: Ed25519Point, q: Ed25519Cached, s: Ed25519Scratch): void => {
273
+ f25519Sub(s.a, p.y, p.x)
274
+ f25519Mul(s.a, s.a, q.ymx)
275
+ f25519Add(s.b, p.y, p.x)
276
+ f25519Mul(s.b, s.b, q.ypx)
277
+ f25519Mul(s.c, p.t, q.t2d)
278
+ f25519Mul(s.d, p.z, q.z2)
279
+ f25519Sub(s.e, s.b, s.a)
280
+ f25519Sub(s.f, s.d, s.c)
281
+ f25519Add(s.g, s.d, s.c)
282
+ f25519Add(s.h, s.b, s.a)
283
+ f25519Mul(out.x, s.e, s.f)
284
+ f25519Mul(out.y, s.g, s.h)
285
+ f25519Mul(out.t, s.e, s.h)
286
+ f25519Mul(out.z, s.f, s.g)
287
+ }
288
+
289
+ /**
290
+ * `out = 2 p` ("dbl-2008-hwcd" for a = -1, with `E`, `F`, `G` and `H` all
291
+ * negated, which leaves every product the same and saves a negation). `out`
292
+ * may be `p`. `C = 2 Z^2` and `H = A + B` are one sum away from reduced;
293
+ * `E = H - (X + Y)^2` and `F = C + G` are two, so they are carried.
294
+ */
295
+ const ed25519Double = (out: Ed25519Point, p: Ed25519Point, s: Ed25519Scratch): void => {
296
+ f25519Square(s.a, p.x)
297
+ f25519Square(s.b, p.y)
298
+ f25519Square(s.c, p.z)
299
+ f25519Add(s.c, s.c, s.c)
300
+ f25519Add(s.d, p.x, p.y)
301
+ f25519Square(s.d, s.d)
302
+ f25519Add(s.h, s.a, s.b)
303
+ f25519Sub(s.e, s.h, s.d)
304
+ f25519Carry(s.e)
305
+ f25519Sub(s.g, s.a, s.b)
306
+ f25519Add(s.f, s.c, s.g)
307
+ f25519Carry(s.f)
308
+ f25519Mul(out.x, s.e, s.f)
309
+ f25519Mul(out.y, s.g, s.h)
310
+ f25519Mul(out.t, s.e, s.h)
311
+ f25519Mul(out.z, s.f, s.g)
312
+ }
313
+
314
+ /** `out = (0 : 1 : 1 : 0)`, the identity, in place. */
315
+ const ed25519SetIdentity = (out: Ed25519Point): void => {
316
+ f25519Copy(out.x, f25519Zero())
317
+ f25519Copy(out.y, f25519Small(toI64(1)))
318
+ f25519Copy(out.z, f25519Small(toI64(1)))
319
+ f25519Copy(out.t, f25519Zero())
320
+ }
321
+
322
+ /** Stores the cached `q` as entry `i` of `table`. */
323
+ const ed25519TableStore = (table: i64[], i: i32, q: Ed25519Cached): void => {
324
+ if (toI32(table.length) < 8 * ED25519_ENTRY || i < 0 || i >= 8 || toI32(q.ypx.length) < 10) {
325
+ return
326
+ }
327
+ const at: i32 = i * ED25519_ENTRY
328
+ for (let j: i32 = 0; j < 10; j++) {
329
+ table[at + j] = q.ypx[j]
330
+ table[at + 10 + j] = q.ymx[j]
331
+ table[at + 20 + j] = q.t2d[j]
332
+ table[at + 30 + j] = q.z2[j]
333
+ }
334
+ }
335
+
336
+ /** `1 p` to `8 p`, cached, as eight entries of forty limbs. */
337
+ const ed25519Table = (p: Ed25519Point, s: Ed25519Scratch): i64[] => {
338
+ const table: i64[] = new Array<i64>(8 * ED25519_ENTRY)
339
+ const one = new Ed25519Cached()
340
+ ed25519ToCached(one, p, s)
341
+ ed25519TableStore(table, 0, one)
342
+ ed25519Double(s.sum, p, s)
343
+ for (let i: i32 = 1; i < 8; i++) {
344
+ if (i > 1) {
345
+ ed25519Add(s.sum, s.sum, one, s)
346
+ }
347
+ ed25519ToCached(s.entry, s.sum, s)
348
+ ed25519TableStore(table, i, s.entry)
349
+ }
350
+ return table
351
+ }
352
+
353
+ /**
354
+ * The scalar `k` (32 bytes, little-endian, below 2^255) as 64 signed radix-16
355
+ * digits in [-8, 8], least significant first: each nibble, plus the carry
356
+ * from the one below, is moved into [-8, 8) by carrying 16 out of it when it
357
+ * is 8 or more. The top nibble is at most 7, so the last digit, with its
358
+ * carry, is at most 8. Every operation is the same for every `k`.
359
+ */
360
+ const ed25519Digits = (k: u8[]): i64[] => {
361
+ const e: i64[] = new Array<i64>(64)
362
+ if (toI32(k.length) < 32) {
363
+ return e
364
+ }
365
+ for (let i: i32 = 0; i < 32; i++) {
366
+ e[2 * i] = toI64(k[i] & toU8(15))
367
+ e[2 * i + 1] = toI64(k[i] >> toU8(4))
368
+ }
369
+ let carry: i64 = 0
370
+ for (let i: i32 = 0; i < 63; i++) {
371
+ const v: i64 = f25519Add64(e[i], carry)
372
+ carry = f25519Add64(v, toI64(8)) >> toI64(4)
373
+ e[i] = f25519Sub64(v, f25519Mul64(carry, toI64(16)))
374
+ }
375
+ e[63] = f25519Add64(e[63], carry)
376
+ return e
377
+ }
378
+
379
+ /**
380
+ * `out = digit * p`, from the table of `1 p` to `8 p`, for a digit in
381
+ * [-8, 8]. Every entry is read; the one whose index is the digit's magnitude
382
+ * is kept under an all-ones mask and the rest under a zero one, and a zero
383
+ * digit keeps none and leaves the identity. A negative digit then negates the
384
+ * entry: -(x, y) = (-x, y), so Y + X and Y - X swap and 2 d T changes sign,
385
+ * by a masked swap and a masked select of the negation.
386
+ */
387
+ const ed25519Select = (out: Ed25519Cached, table: i64[], digit: i64, s: Ed25519Scratch): void => {
388
+ if (toI32(table.length) < 8 * ED25519_ENTRY || toI32(out.ypx.length) < 10 || toI32(s.a.length) < 10) {
389
+ return
390
+ }
391
+ const sign: i64 = digit >> toI64(63)
392
+ const magnitude: i64 = f25519Sub64(digit ^ sign, sign)
393
+ f25519Copy(out.ypx, f25519Small(toI64(1)))
394
+ f25519Copy(out.ymx, f25519Small(toI64(1)))
395
+ f25519Copy(out.t2d, f25519Zero())
396
+ f25519Copy(out.z2, f25519Small(toI64(2)))
397
+ for (let i: i32 = 0; i < 8; i++) {
398
+ // All ones when `magnitude` is `i + 1`: the xor is then 0, and 0 - 1 is
399
+ // the only difference here whose sign bit is set.
400
+ const hit: i64 = f25519Sub64(magnitude ^ toI64(i + 1), toI64(1)) >> toI64(63)
401
+ const at: i32 = i * ED25519_ENTRY
402
+ for (let j: i32 = 0; j < 10; j++) {
403
+ out.ypx[j] = out.ypx[j] ^ (hit & (out.ypx[j] ^ table[at + j]))
404
+ out.ymx[j] = out.ymx[j] ^ (hit & (out.ymx[j] ^ table[at + 10 + j]))
405
+ out.t2d[j] = out.t2d[j] ^ (hit & (out.t2d[j] ^ table[at + 20 + j]))
406
+ out.z2[j] = out.z2[j] ^ (hit & (out.z2[j] ^ table[at + 30 + j]))
407
+ }
408
+ }
409
+ f25519Swap(out.ypx, out.ymx, sign & toI64(1))
410
+ for (let j: i32 = 0; j < 10; j++) {
411
+ s.a[j] = f25519Sub64(toI64(0), out.t2d[j])
412
+ out.t2d[j] = out.t2d[j] ^ (sign & (out.t2d[j] ^ s.a[j]))
413
+ }
414
+ }
415
+
416
+ /**
417
+ * `out = k * p` for a 32-byte little-endian `k` below 2^255, in constant time:
418
+ * from the top digit down, four doublings (none before the first add, a
419
+ * public position) and the addition of the selected entry. The table holds
420
+ * multiples of `p`, which is public in every use here (the base point, or a
421
+ * public key), and is not wiped; the digits are, and the caller wipes `s`.
422
+ */
423
+ const ed25519ScalarMult = (out: Ed25519Point, k: u8[], p: Ed25519Point, s: Ed25519Scratch): void => {
424
+ const digits: i64[] = ed25519Digits(k)
425
+ const table: i64[] = ed25519Table(p, s)
426
+ ed25519SetIdentity(out)
427
+ for (let i: i32 = 63; i >= 0; i--) {
428
+ if (i < 63) {
429
+ ed25519Double(out, out, s)
430
+ ed25519Double(out, out, s)
431
+ ed25519Double(out, out, s)
432
+ ed25519Double(out, out, s)
433
+ }
434
+ ed25519Select(s.entry, table, digits[i], s)
435
+ ed25519Add(out, out, s.entry, s)
436
+ }
437
+ wipe(digits)
438
+ }
439
+
440
+ /** B, the base point, with T = x y and Z = 1. */
441
+ const ed25519Base = (): Ed25519Point => {
442
+ const b = new Ed25519Point()
443
+ f25519Copy(b.x, ed25519BaseX())
444
+ f25519Copy(b.y, ed25519BaseY())
445
+ f25519Mul(b.t, b.x, b.y)
446
+ return b
447
+ }
448
+
449
+ /** `out = k * B`. */
450
+ const ed25519BaseMult = (out: Ed25519Point, k: u8[], s: Ed25519Scratch): void => {
451
+ ed25519ScalarMult(out, k, ed25519Base(), s)
452
+ }
453
+
454
+ /**
455
+ * The 32-byte encoding of `p` (§5.1.2): y, with the low bit of x in the top
456
+ * bit of the last byte. The affine coordinates are left in `s.b` and `s.c`,
457
+ * which the caller wipes with the rest of the scratch, and x's encoding is
458
+ * wiped here.
459
+ */
460
+ const ed25519Encode = (p: Ed25519Point, s: Ed25519Scratch): u8[] => {
461
+ f25519Invert(s.a, p.z)
462
+ f25519Mul(s.b, p.x, s.a)
463
+ f25519Mul(s.c, p.y, s.a)
464
+ const out: u8[] = f25519Encode(s.c)
465
+ const x: u8[] = f25519Encode(s.b)
466
+ if (toI32(out.length) < 32 || toI32(x.length) < 32) {
467
+ return out
468
+ }
469
+ out[31] = out[31] | ((x[0] & toU8(1)) << toU8(7))
470
+ wipe(x)
471
+ return out
472
+ }
473
+
474
+ /** Whether the first `n` bytes of `a` and `b` are the same; variable time, for public values. */
475
+ const ed25519SameBytes = (a: u8[], b: u8[], n: i32): boolean => {
476
+ if (toI32(a.length) < n || toI32(b.length) < n) {
477
+ return false
478
+ }
479
+ for (let i: i32 = 0; i < n; i++) {
480
+ if (a[i] !== b[i]) {
481
+ return false
482
+ }
483
+ }
484
+ return true
485
+ }
486
+
487
+ /** Whether the field elements `f` and `g` are equal, by their canonical encodings; variable time. */
488
+ const ed25519FieldEqual = (f: i64[], g: i64[]): boolean =>
489
+ ed25519SameBytes(f25519Encode(f), f25519Encode(g), ED25519_HALF)
490
+
491
+ /** `out = z^((p - 5) / 8) = z^(2^252 - 3)`: `f25519Pow250`, two squarings and a multiplication by `z`. */
492
+ const ed25519Pow22523 = (out: i64[], z: i64[]): void => {
493
+ const z11: i64[] = f25519Zero()
494
+ const acc: i64[] = f25519Zero()
495
+ f25519Pow250(acc, z11, z)
496
+ f25519SquareTimes(acc, acc, 2)
497
+ f25519Mul(out, acc, z)
498
+ }
499
+
500
+ /** `f = -f`, carried. */
501
+ const ed25519Negate = (f: i64[]): void => {
502
+ f25519Sub(f, f25519Zero(), f)
503
+ f25519Carry(f)
504
+ }
505
+
506
+ /**
507
+ * The point that the 32 bytes `bytes` encode (§5.1.3), or `null` for none:
508
+ * a y that is not below p, a y with no x on the curve, or x = 0 with the sign
509
+ * bit set. Variable time — it decodes public keys only.
510
+ *
511
+ * x^2 = u / v with u = y^2 - 1 and v = d y^2 + 1, and the candidate root is
512
+ * x = u v^3 (u v^7)^((p - 5) / 8). If v x^2 is u it is a root; if it is -u,
513
+ * x sqrt(-1) is; otherwise there is none. x then takes the sign bit's parity.
514
+ */
515
+ const ed25519Decode = (bytes: u8[], s: Ed25519Scratch): Ed25519Point | null => {
516
+ if (toI32(bytes.length) !== 32) {
517
+ return null
518
+ }
519
+ const y: i64[] = f25519Decode(bytes)
520
+ // f25519Decode takes y modulo p; re-encoding refuses every y of p or more.
521
+ const canonical: u8[] = f25519Encode(y)
522
+ canonical[31] = canonical[31] | (bytes[31] & toU8(0x80))
523
+ if (!ed25519SameBytes(canonical, bytes, ED25519_HALF)) {
524
+ return null
525
+ }
526
+ const sign: u8 = bytes[31] >> toU8(7)
527
+ const one: i64[] = f25519Small(toI64(1))
528
+
529
+ f25519Square(s.a, y)
530
+ f25519Sub(s.b, s.a, one)
531
+ f25519Carry(s.b) // u
532
+ f25519Mul(s.c, s.a, ed25519D())
533
+ f25519Add(s.c, s.c, one)
534
+ f25519Carry(s.c) // v
535
+ f25519Square(s.d, s.c)
536
+ f25519Mul(s.d, s.d, s.c) // v^3
537
+ f25519Square(s.e, s.d)
538
+ f25519Mul(s.e, s.e, s.c) // v^7
539
+ f25519Mul(s.e, s.e, s.b) // u v^7
540
+ ed25519Pow22523(s.e, s.e)
541
+ f25519Mul(s.f, s.d, s.b) // u v^3
542
+ const x: i64[] = f25519Zero()
543
+ f25519Mul(x, s.f, s.e)
544
+
545
+ f25519Square(s.g, x)
546
+ f25519Mul(s.g, s.g, s.c) // v x^2
547
+ f25519Copy(s.h, s.b)
548
+ ed25519Negate(s.h) // -u
549
+ if (!ed25519FieldEqual(s.g, s.b)) {
550
+ if (!ed25519FieldEqual(s.g, s.h)) {
551
+ return null
552
+ }
553
+ f25519Mul(x, x, ed25519SqrtM1())
554
+ }
555
+
556
+ const xBytes: u8[] = f25519Encode(x)
557
+ if ((xBytes[0] & toU8(1)) !== sign) {
558
+ if (ed25519SameBytes(xBytes, new Array<u8>(32), ED25519_HALF)) {
559
+ return null
560
+ }
561
+ ed25519Negate(x)
562
+ }
563
+ const p = new Ed25519Point()
564
+ f25519Copy(p.x, x)
565
+ f25519Copy(p.y, y)
566
+ f25519Mul(p.t, x, y)
567
+ return p
568
+ }
569
+
570
+ /**
571
+ * `out = x mod L` for the 64-byte little-endian `x`, in constant time: from
572
+ * bit 511 down, `acc = 2 acc + bit`, then `acc - L` replaces `acc` under a
573
+ * mask when it did not borrow. `acc` stays below L, so `2 acc + 1` is below
574
+ * 2^254 and the eight 32-bit limbs never carry out. The limbs are `u64`,
575
+ * whose subtraction wraps, so a borrow is the top bit of the difference.
576
+ * `acc` and the difference are wiped.
577
+ */
578
+ const ed25519Reduce = (out: u8[], x: u8[]): void => {
579
+ if (toI32(out.length) < 32 || toI32(x.length) < 64) {
580
+ return
581
+ }
582
+ const l: u64[] = ed25519Order()
583
+ const acc: u64[] = new Array<u64>(8)
584
+ const diff: u64[] = new Array<u64>(8)
585
+ if (toI32(l.length) < 8) {
586
+ return
587
+ }
588
+ const low: u64 = 0xffffffff
589
+ for (let i: i32 = 511; i >= 0; i--) {
590
+ const byte: i32 = i >> 3
591
+ let carry: u64 = toU64(x[byte] >> toU8(i & 7)) & toU64(1)
592
+ for (let j: i32 = 0; j < 8; j++) {
593
+ const v: u64 = (acc[j] << toU64(1)) | carry
594
+ acc[j] = v & low
595
+ carry = v >> toU64(32)
596
+ }
597
+ let borrow: u64 = 0
598
+ for (let j: i32 = 0; j < 8; j++) {
599
+ const v: u64 = acc[j] - l[j] - borrow
600
+ diff[j] = v & low
601
+ borrow = v >> toU64(63)
602
+ }
603
+ const keep: u64 = borrow - toU64(1)
604
+ const stay: u64 = toU64(0) - borrow
605
+ for (let j: i32 = 0; j < 8; j++) {
606
+ acc[j] = (diff[j] & keep) | (acc[j] & stay)
607
+ }
608
+ }
609
+ for (let j: i32 = 0; j < 8; j++) {
610
+ for (let b: i32 = 0; b < 4; b++) {
611
+ out[4 * j + b] = toU8((acc[j] >> toU64(8 * b)) & toU64(0xff))
612
+ }
613
+ }
614
+ wipe(acc)
615
+ wipe(diff)
616
+ }
617
+
618
+ /** The 32 little-endian bytes of `a` as sixteen 16-bit limbs. */
619
+ const ed25519Limbs16 = (a: u8[]): u64[] => {
620
+ const out: u64[] = new Array<u64>(16)
621
+ if (toI32(a.length) < 32) {
622
+ return out
623
+ }
624
+ for (let i: i32 = 0; i < 16; i++) {
625
+ out[i] = toU64(a[2 * i]) | (toU64(a[2 * i + 1]) << toU64(8))
626
+ }
627
+ return out
628
+ }
629
+
630
+ /**
631
+ * `out = (r + k a) mod L` (§5.1.6 step 5), each a 32-byte little-endian
632
+ * scalar, in constant time: the schoolbook product of sixteen 16-bit limbs,
633
+ * whose column sums stay below 2^37, plus `r`, carried into 64 bytes and
634
+ * reduced by `ed25519Reduce`. Every intermediate is wiped.
635
+ */
636
+ const ed25519MulAdd = (out: u8[], k: u8[], a: u8[], r: u8[]): void => {
637
+ const k16: u64[] = ed25519Limbs16(k)
638
+ const a16: u64[] = ed25519Limbs16(a)
639
+ const r16: u64[] = ed25519Limbs16(r)
640
+ const wide: u64[] = new Array<u64>(32)
641
+ const bytes: u8[] = new Array<u8>(64)
642
+ if (toI32(k16.length) < 16 || toI32(a16.length) < 16 || toI32(r16.length) < 16) {
643
+ return
644
+ }
645
+ for (let i: i32 = 0; i < 16; i++) {
646
+ wide[i] = r16[i]
647
+ }
648
+ for (let i: i32 = 0; i < 16; i++) {
649
+ for (let j: i32 = 0; j < 16; j++) {
650
+ wide[i + j] = wide[i + j] + k16[i] * a16[j]
651
+ }
652
+ }
653
+ let carry: u64 = 0
654
+ for (let i: i32 = 0; i < 32; i++) {
655
+ const v: u64 = wide[i] + carry
656
+ bytes[2 * i] = toU8(v & toU64(0xff))
657
+ bytes[2 * i + 1] = toU8((v >> toU64(8)) & toU64(0xff))
658
+ carry = v >> toU64(16)
659
+ }
660
+ ed25519Reduce(out, bytes)
661
+ wipe(k16)
662
+ wipe(a16)
663
+ wipe(r16)
664
+ wipe(wide)
665
+ wipe(bytes)
666
+ }
667
+
668
+ /** Whether the 32-byte little-endian `s` is below L (§5.1.7 step 1); variable time, for a public S. */
669
+ const ed25519ScalarCanonical = (s: u8[]): boolean => {
670
+ const l: u64[] = ed25519Order()
671
+ if (toI32(s.length) < 32 || toI32(l.length) < 8) {
672
+ return false
673
+ }
674
+ for (let j: i32 = 7; j >= 0; j--) {
675
+ const v: u64 =
676
+ toU64(s[4 * j]) |
677
+ (toU64(s[4 * j + 1]) << toU64(8)) |
678
+ (toU64(s[4 * j + 2]) << toU64(16)) |
679
+ (toU64(s[4 * j + 3]) << toU64(24))
680
+ if (v !== l[j]) {
681
+ return v < l[j]
682
+ }
683
+ }
684
+ return false
685
+ }
686
+
687
+ /**
688
+ * The seed's SHA-512 (§5.1.5 steps 1 and 2), its first half clamped into the
689
+ * secret scalar `a` — bits 0, 1, 2 and 255 cleared, bit 254 set — and its
690
+ * second half the prefix. The hasher is wiped; the caller wipes the answer.
691
+ */
692
+ const ed25519Expand = (seed: u8[]): u8[] => {
693
+ const hasher = new Sha512()
694
+ hasher.update(seed, ED25519_FROM, ED25519_SEED_SIZE)
695
+ const h: u8[] = hasher.digest()
696
+ ed25519WipeHasher(hasher)
697
+ if (toI32(h.length) < SHA512_SIZE) {
698
+ return h
699
+ }
700
+ h[0] = h[0] & toU8(248)
701
+ h[31] = (h[31] & toU8(127)) | toU8(64)
702
+ return h
703
+ }
704
+
705
+ /** k = SHA-512(R || A || M) mod L (§5.1.6 step 4, §5.1.7 step 2); public. */
706
+ const ed25519Challenge = (r: u8[], pub: u8[], msg: u8[]): u8[] => {
707
+ const hasher = new Sha512()
708
+ hasher.update(r, ED25519_FROM, ED25519_HALF)
709
+ hasher.update(pub, ED25519_FROM, ED25519_HALF)
710
+ hasher.update(msg, ED25519_FROM, toI32(msg.length))
711
+ const k: u8[] = new Array<u8>(32)
712
+ ed25519Reduce(k, hasher.digest())
713
+ return k
714
+ }
715
+
716
+ /**
717
+ * The public key of `seed` (RFC 8032 §5.1.5): the encoding of `a * B`, as 32
718
+ * plain bytes. Answers `null` unless `seed` is `ED25519_SEED_SIZE` bytes.
719
+ */
720
+ export const ed25519PublicKey = (seed: Secret<u8[]>): u8[] | null => expose(seed, ed25519PublicKeyExposed)
721
+
722
+ /** `ed25519PublicKey` on the plain seed, for `expose` to run: the hash, the point and the scratch are wiped. */
723
+ const ed25519PublicKeyExposed = (seed: u8[]): u8[] | null => {
724
+ if (toI32(seed.length) !== 32) {
725
+ return null
726
+ }
727
+ const h: u8[] = ed25519Expand(seed)
728
+ const s = new Ed25519Scratch()
729
+ const point = new Ed25519Point()
730
+ ed25519BaseMult(point, h, s)
731
+ const pub: u8[] = ed25519Encode(point, s)
732
+ wipe(h)
733
+ ed25519WipePoint(point)
734
+ ed25519WipeScratch(s)
735
+ return pub
736
+ }
737
+
738
+ /**
739
+ * The Ed25519 signature of `msg` under `seed` (RFC 8032 §5.1.6), `R || S`,
740
+ * 64 bytes. Signing is deterministic: the same seed and message always give
741
+ * the same signature. Answers `null` unless `seed` is `ED25519_SEED_SIZE`
742
+ * bytes. The public key is derived from the seed again on every call. A
743
+ * message longer than 2^31 - 1 bytes panics, as in `sha512`: its length does
744
+ * not survive `toI32`, and the signature would be of a prefix.
745
+ */
746
+ export const ed25519Sign = (seed: Secret<u8[]>, msg: u8[]): u8[] | null => {
747
+ if (msg.length > 2147483647) {
748
+ panic("ed25519Sign: a message longer than 2^31 - 1 bytes")
749
+ }
750
+ return exposeWith(seed, msg, ed25519SignExposed)
751
+ }
752
+
753
+ /**
754
+ * `ed25519Sign` on the plain seed, for `exposeWith` to run. The seed's hash
755
+ * (the scalar and the prefix), the nonce's hash, the nonce, the point, the
756
+ * scratch and both hashers are wiped; R, A and S are the public output.
757
+ */
758
+ const ed25519SignExposed = (seed: u8[], msg: u8[]): u8[] | null => {
759
+ if (toI32(seed.length) !== 32) {
760
+ return null
761
+ }
762
+ const h: u8[] = ed25519Expand(seed)
763
+ const s = new Ed25519Scratch()
764
+ const point = new Ed25519Point()
765
+ ed25519BaseMult(point, h, s)
766
+ const pub: u8[] = ed25519Encode(point, s)
767
+
768
+ const nonceHasher = new Sha512()
769
+ nonceHasher.update(h, ED25519_HALF, ED25519_HALF)
770
+ nonceHasher.update(msg, ED25519_FROM, toI32(msg.length))
771
+ const nonceWide: u8[] = nonceHasher.digest()
772
+ ed25519WipeHasher(nonceHasher)
773
+ const nonce: u8[] = new Array<u8>(32)
774
+ ed25519Reduce(nonce, nonceWide)
775
+ wipe(nonceWide)
776
+
777
+ ed25519BaseMult(point, nonce, s)
778
+ const r: u8[] = ed25519Encode(point, s)
779
+ const k: u8[] = ed25519Challenge(r, pub, msg)
780
+ const sBytes: u8[] = new Array<u8>(32)
781
+ ed25519MulAdd(sBytes, k, h, nonce)
782
+
783
+ wipe(h)
784
+ wipe(nonce)
785
+ ed25519WipePoint(point)
786
+ ed25519WipeScratch(s)
787
+
788
+ const sig: u8[] = new Array<u8>(64)
789
+ if (toI32(r.length) < 32 || toI32(sBytes.length) < 32) {
790
+ return null
791
+ }
792
+ for (let i: i32 = 0; i < 32; i++) {
793
+ sig[i] = r[i]
794
+ sig[i + 32] = sBytes[i]
795
+ }
796
+ return sig
797
+ }
798
+
799
+ /**
800
+ * Whether `sig` is a valid Ed25519 signature of `msg` under the public key
801
+ * `pub` (RFC 8032 §5.1.7): [S]B = R + [k]A with k = SHA-512(R || A || M)
802
+ * mod L, checked as the encoding of [S]B + [k](-A) against R's bytes.
803
+ * Answers `false` for a key or signature of the wrong length, an S of L or
804
+ * more, and a key that does not decode. A message longer than 2^31 - 1
805
+ * bytes panics, as in `ed25519Sign`: a check of a prefix would accept the
806
+ * signature for any longer message that shares it. Every value here is
807
+ * public, so the answer may be reached by branches.
808
+ */
809
+ export const ed25519Verify = (pub: u8[], msg: u8[], sig: u8[]): boolean => {
810
+ if (msg.length > 2147483647) {
811
+ panic("ed25519Verify: a message longer than 2^31 - 1 bytes")
812
+ }
813
+ if (toI32(pub.length) !== 32 || toI32(sig.length) !== 64) {
814
+ return false
815
+ }
816
+ const r: u8[] = new Array<u8>(32)
817
+ const sBytes: u8[] = new Array<u8>(32)
818
+ for (let i: i32 = 0; i < 32; i++) {
819
+ r[i] = sig[i]
820
+ sBytes[i] = sig[i + 32]
821
+ }
822
+ if (!ed25519ScalarCanonical(sBytes)) {
823
+ return false
824
+ }
825
+ const s = new Ed25519Scratch()
826
+ const a: Ed25519Point | null = ed25519Decode(pub, s)
827
+ if (a === null) {
828
+ return false
829
+ }
830
+ const k: u8[] = ed25519Challenge(r, pub, msg)
831
+ ed25519Negate(a.x)
832
+ ed25519Negate(a.t)
833
+ const sum = new Ed25519Point()
834
+ ed25519BaseMult(sum, sBytes, s)
835
+ const other = new Ed25519Point()
836
+ ed25519ScalarMult(other, k, a, s)
837
+ ed25519ToCached(s.entry, other, s)
838
+ ed25519Add(sum, sum, s.entry, s)
839
+ return ed25519SameBytes(ed25519Encode(sum, s), r, ED25519_HALF)
840
+ }