@amritk/nish-x86_64-linux 0.18.0 → 0.21.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 +58 -28
- package/bin/nish +0 -0
- package/docs/AI.md +2759 -0
- package/package.json +3 -2
- package/runtime/browser.d.ts +14 -0
- package/runtime/browser.mjs +88 -0
- package/runtime/core/arrays.d.ts +18 -0
- package/runtime/core/arrays.mjs +125 -0
- package/runtime/core/checks.mjs +20 -0
- package/runtime/core/host.d.ts +70 -0
- package/runtime/core/host.mjs +311 -0
- package/runtime/core/numbers.d.ts +53 -0
- package/runtime/core/numbers.mjs +316 -0
- package/runtime/core/result.d.ts +41 -0
- package/runtime/core/result.mjs +127 -0
- package/runtime/core/strings.d.ts +14 -0
- package/runtime/core/strings.mjs +169 -0
- package/runtime/core.d.ts +9 -0
- package/runtime/core.mjs +55 -0
- package/runtime/host.d.ts +6 -0
- package/runtime/nish.d.ts +99 -5
- package/runtime/nish.h +289 -19
- package/runtime/nish.mjs +39 -3
- package/runtime/node.mjs +383 -0
- package/runtime/runtime-aes.c +490 -0
- package/runtime/runtime-bytes.c +401 -0
- package/runtime/runtime-cross.c +366 -0
- package/runtime/runtime-host.c +8 -7
- package/runtime/runtime-net.c +93 -34
- package/runtime/runtime-os.c +214 -16
- package/runtime/runtime-parallel.c +590 -107
- package/runtime/runtime-simd.c +235 -11
- package/runtime/runtime-term.c +504 -0
- package/runtime/runtime-wasm.c +5 -14
- package/runtime/runtime.c +257 -17
- package/runtime/shim.mjs +6 -915
- package/runtime/sqlite/LICENSE.md +85 -0
- package/runtime/sqlite/README.md +45 -0
- package/runtime/sqlite/nish-sqlite.c +359 -0
- package/runtime/sqlite/sqlite3.c +271131 -0
- package/runtime/sqlite/sqlite3.h +14447 -0
- package/scripts/build.sh +437 -28
- package/std/LICENSE-fast-float +23 -0
- package/std/LICENSE-fdlibm +8 -0
- package/std/README.md +108 -58
- package/std/base64.ts +116 -0
- package/std/bytes.ts +419 -0
- package/std/cli.ts +328 -0
- package/std/collections.ts +6 -5
- package/std/crypto/LICENSE-crypt_blowfish +26 -0
- package/std/crypto/LICENSE-libsecp256k1 +19 -0
- package/std/crypto/aes.ts +238 -76
- package/std/crypto/base64url.ts +125 -0
- package/std/crypto/bcrypt.ts +760 -0
- 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 +382 -54
- 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 +20 -131
- package/std/json-tokenizer.ts +4237 -0
- package/std/json-typed.ts +1014 -0
- package/std/json-value.ts +1182 -0
- package/std/json.ts +1202 -34
- package/std/math.ts +608 -0
- 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 +501 -62
- 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 +261 -43
- package/std/net/http3.ts +187 -28
- package/std/net/postgres.ts +1875 -0
- package/std/net/prefork.ts +412 -0
- package/std/net/quic-listener.ts +108 -11
- 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/regex.ts +4274 -0
- package/std/sqlite.ts +391 -0
- package/std/term-io.ts +978 -0
- package/std/term-pixels.ts +874 -0
- package/std/term-probe.ts +459 -0
- package/std/term-rate.ts +993 -0
- package/std/term.ts +2453 -0
- package/std/text.ts +90 -7
- package/std/threads.ts +438 -14
- package/std/yaml-lines.ts +141 -0
- package/std/yaml.ts +4675 -0
|
@@ -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
|
+
}
|