@mnemom/mnemom 0.17.37 → 0.17.38-next.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/dist/commands/agent-run.d.ts +11 -0
- package/dist/commands/agent-run.js +37 -0
- package/dist/commands/agent-share-render.d.ts +5 -5
- package/dist/commands/agent-share-render.js +9 -7
- package/dist/commands/agent-share-test-issuer.d.ts +1 -1
- package/dist/commands/agent-share-test-issuer.js +1 -1
- package/dist/commands/agent.d.ts +8 -1
- package/dist/commands/agent.js +14 -3
- package/dist/commands/scan.d.ts +15 -2
- package/dist/commands/scan.js +48 -3
- package/dist/index.js +1 -1
- package/dist/lib/commit-report.d.ts +7 -13
- package/dist/lib/commit-report.js +12 -5
- package/dist/lib/conduct-receipt.d.ts +8 -3
- package/dist/lib/conduct-receipt.js +29 -7
- package/dist/lib/experimental.d.ts +1 -1
- package/dist/lib/experimental.js +1 -12
- package/dist/lib/runner/executor-client.d.ts +5 -0
- package/dist/lib/runner/executor-client.js +8 -0
- package/dist/lib/runner/job.d.ts +37 -0
- package/dist/lib/runner/job.js +74 -1
- package/dist/lib/runner/phases.d.ts +7 -2
- package/dist/lib/runner/phases.js +7 -2
- package/dist/lib/runner/proxy.d.ts +26 -2
- package/dist/lib/runner/proxy.js +33 -1
- package/dist/lib/runner/record-commit.d.ts +16 -0
- package/dist/lib/runner/record-commit.js +7 -0
- package/dist/lib/scan/spend/anthropic-usage.d.ts +20 -1
- package/dist/lib/scan/spend/anthropic-usage.js +32 -7
- package/dist/lib/scan/spend/anthropic-wif.d.ts +42 -0
- package/dist/lib/scan/spend/anthropic-wif.js +153 -0
- package/package.json +2 -5
- package/node_modules/@mnemom/aip-verifier/LICENSE +0 -190
- package/node_modules/@mnemom/aip-verifier/dist/claim-lint-CVITIRcU.d.cts +0 -478
- package/node_modules/@mnemom/aip-verifier/dist/claim-lint-CVITIRcU.d.ts +0 -478
- package/node_modules/@mnemom/aip-verifier/dist/index.cjs +0 -971
- package/node_modules/@mnemom/aip-verifier/dist/index.cjs.map +0 -1
- package/node_modules/@mnemom/aip-verifier/dist/index.d.cts +0 -330
- package/node_modules/@mnemom/aip-verifier/dist/index.d.ts +0 -330
- package/node_modules/@mnemom/aip-verifier/dist/index.js +0 -933
- package/node_modules/@mnemom/aip-verifier/dist/index.js.map +0 -1
- package/node_modules/@mnemom/aip-verifier/dist/render-lines.cjs +0 -879
- package/node_modules/@mnemom/aip-verifier/dist/render-lines.cjs.map +0 -1
- package/node_modules/@mnemom/aip-verifier/dist/render-lines.d.cts +0 -96
- package/node_modules/@mnemom/aip-verifier/dist/render-lines.d.ts +0 -96
- package/node_modules/@mnemom/aip-verifier/dist/render-lines.js +0 -875
- package/node_modules/@mnemom/aip-verifier/dist/render-lines.js.map +0 -1
- package/node_modules/@mnemom/aip-verifier/package.json +0 -86
- package/node_modules/@noble/ed25519/LICENSE +0 -21
- package/node_modules/@noble/ed25519/README.md +0 -371
- package/node_modules/@noble/ed25519/index.d.ts +0 -391
- package/node_modules/@noble/ed25519/index.js +0 -933
- package/node_modules/@noble/ed25519/index.ts +0 -1134
- package/node_modules/@noble/ed25519/package.json +0 -54
- package/node_modules/@noble/hashes/LICENSE +0 -21
- package/node_modules/@noble/hashes/README.md +0 -478
- package/node_modules/@noble/hashes/_blake.d.ts +0 -20
- package/node_modules/@noble/hashes/_blake.js +0 -59
- package/node_modules/@noble/hashes/_md.d.ts +0 -95
- package/node_modules/@noble/hashes/_md.js +0 -209
- package/node_modules/@noble/hashes/_u64.d.ts +0 -36
- package/node_modules/@noble/hashes/_u64.js +0 -77
- package/node_modules/@noble/hashes/argon2.d.ts +0 -148
- package/node_modules/@noble/hashes/argon2.js +0 -577
- package/node_modules/@noble/hashes/blake1.d.ts +0 -162
- package/node_modules/@noble/hashes/blake1.js +0 -630
- package/node_modules/@noble/hashes/blake2.d.ts +0 -203
- package/node_modules/@noble/hashes/blake2.js +0 -573
- package/node_modules/@noble/hashes/blake3.d.ts +0 -68
- package/node_modules/@noble/hashes/blake3.js +0 -310
- package/node_modules/@noble/hashes/eskdf.d.ts +0 -91
- package/node_modules/@noble/hashes/eskdf.js +0 -225
- package/node_modules/@noble/hashes/hkdf.d.ts +0 -70
- package/node_modules/@noble/hashes/hkdf.js +0 -152
- package/node_modules/@noble/hashes/hmac.d.ts +0 -50
- package/node_modules/@noble/hashes/hmac.js +0 -93
- package/node_modules/@noble/hashes/index.d.ts +0 -1
- package/node_modules/@noble/hashes/index.js +0 -34
- package/node_modules/@noble/hashes/legacy.d.ts +0 -107
- package/node_modules/@noble/hashes/legacy.js +0 -348
- package/node_modules/@noble/hashes/package.json +0 -91
- package/node_modules/@noble/hashes/pbkdf2.d.ts +0 -66
- package/node_modules/@noble/hashes/pbkdf2.js +0 -176
- package/node_modules/@noble/hashes/scrypt.d.ts +0 -98
- package/node_modules/@noble/hashes/scrypt.js +0 -304
- package/node_modules/@noble/hashes/sha2.d.ts +0 -176
- package/node_modules/@noble/hashes/sha2.js +0 -446
- package/node_modules/@noble/hashes/sha3-addons.d.ts +0 -533
- package/node_modules/@noble/hashes/sha3-addons.js +0 -973
- package/node_modules/@noble/hashes/sha3.d.ts +0 -208
- package/node_modules/@noble/hashes/sha3.js +0 -475
- package/node_modules/@noble/hashes/src/_blake.ts +0 -67
- package/node_modules/@noble/hashes/src/_md.ts +0 -227
- package/node_modules/@noble/hashes/src/_u64.ts +0 -111
- package/node_modules/@noble/hashes/src/argon2.ts +0 -693
- package/node_modules/@noble/hashes/src/blake1.ts +0 -677
- package/node_modules/@noble/hashes/src/blake2.ts +0 -648
- package/node_modules/@noble/hashes/src/blake3.ts +0 -344
- package/node_modules/@noble/hashes/src/eskdf.ts +0 -265
- package/node_modules/@noble/hashes/src/hkdf.ts +0 -161
- package/node_modules/@noble/hashes/src/hmac.ts +0 -130
- package/node_modules/@noble/hashes/src/index.ts +0 -33
- package/node_modules/@noble/hashes/src/legacy.ts +0 -361
- package/node_modules/@noble/hashes/src/pbkdf2.ts +0 -219
- package/node_modules/@noble/hashes/src/scrypt.ts +0 -375
- package/node_modules/@noble/hashes/src/sha2.ts +0 -486
- package/node_modules/@noble/hashes/src/sha3-addons.ts +0 -1157
- package/node_modules/@noble/hashes/src/sha3.ts +0 -525
- package/node_modules/@noble/hashes/src/utils.ts +0 -978
- package/node_modules/@noble/hashes/src/webcrypto.ts +0 -283
- package/node_modules/@noble/hashes/utils.d.ts +0 -560
- package/node_modules/@noble/hashes/utils.js +0 -687
- package/node_modules/@noble/hashes/webcrypto.d.ts +0 -121
- package/node_modules/@noble/hashes/webcrypto.js +0 -228
|
@@ -1,1134 +0,0 @@
|
|
|
1
|
-
/*! noble-ed25519 - MIT License (c) 2019 Paul Miller (paulmillr.com) */
|
|
2
|
-
/**
|
|
3
|
-
* 5KB JS implementation of ed25519 EdDSA signatures.
|
|
4
|
-
* Targets RFC8032, FIPS 186-5, and ZIP215 behavior.
|
|
5
|
-
* @module
|
|
6
|
-
* @example
|
|
7
|
-
* ```js
|
|
8
|
-
import * as ed from '@noble/ed25519';
|
|
9
|
-
(async () => {
|
|
10
|
-
const secretKey = ed.utils.randomSecretKey();
|
|
11
|
-
const message = Uint8Array.from([0xab, 0xbc, 0xcd, 0xde]);
|
|
12
|
-
const pubKey = await ed.getPublicKeyAsync(secretKey); // Sync methods are also present
|
|
13
|
-
const signature = await ed.signAsync(message, secretKey);
|
|
14
|
-
const isValid = await ed.verifyAsync(signature, message, pubKey);
|
|
15
|
-
})();
|
|
16
|
-
```
|
|
17
|
-
*/
|
|
18
|
-
/**
|
|
19
|
-
* Curve params. edwards25519 uses the RFC equation `-x² + y² = 1 + dx²y²`.
|
|
20
|
-
* The stored `a` literal below is `p - 1`, i.e. the field-element encoding of RFC `a = -1`.
|
|
21
|
-
* * P = `2n**255n - 19n` // field over which calculations are done
|
|
22
|
-
* * N = `2n**252n + 27742317777372353535851937790883648493n` // prime-order subgroup order
|
|
23
|
-
* * h = 8 // cofactor
|
|
24
|
-
* * a = `Fp.create(BigInt(-1))` // equation param, stored here as `p - 1`
|
|
25
|
-
* * d = -121665/121666 a.k.a. `Fp.neg(121665 * Fp.inv(121666))` // equation param
|
|
26
|
-
* * Gx, Gy are coordinates of Generator / base point
|
|
27
|
-
*
|
|
28
|
-
* Mirror noble-curves: Point.CURVE() exposes shared params, but callers must not be able to mutate
|
|
29
|
-
* that shared view and desynchronize it from the arithmetic constants captured below.
|
|
30
|
-
*/
|
|
31
|
-
const freeze = Object.freeze;
|
|
32
|
-
const P = 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffedn;
|
|
33
|
-
const N = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3edn;
|
|
34
|
-
const _d = 0x52036cee2b6ffe738cc740797779e89800700a4d4141d8ab75eb4dca135978a3n;
|
|
35
|
-
const Gx = 0x216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51an;
|
|
36
|
-
const Gy = 0x6666666666666666666666666666666666666666666666666666666666666658n;
|
|
37
|
-
const _a = P - 1n; // field-element encoding of RFC `a = -1`
|
|
38
|
-
const ed25519_CURVE: EdwardsOpts = freeze({
|
|
39
|
-
p: P,
|
|
40
|
-
n: N,
|
|
41
|
-
h: 8n,
|
|
42
|
-
a: _a,
|
|
43
|
-
d: _d,
|
|
44
|
-
Gx,
|
|
45
|
-
Gy,
|
|
46
|
-
});
|
|
47
|
-
// Shared 32-byte encoded width for Ed25519 points, scalars, signatures/2, and keys. Named LEN
|
|
48
|
-
// rather than RFC 8032's `L`, which names the group order (stored here as `N`).
|
|
49
|
-
const LEN = 32;
|
|
50
|
-
/** Alias to Uint8Array. */
|
|
51
|
-
export type Bytes = Uint8Array;
|
|
52
|
-
/** Edwards elliptic curve options. */
|
|
53
|
-
export type EdwardsOpts = Readonly<{
|
|
54
|
-
/** Prime field modulus. */
|
|
55
|
-
p: bigint;
|
|
56
|
-
/** Group order. */
|
|
57
|
-
n: bigint;
|
|
58
|
-
/** Curve cofactor. */
|
|
59
|
-
h: bigint;
|
|
60
|
-
/** Edwards curve parameter `a`. */
|
|
61
|
-
a: bigint;
|
|
62
|
-
/** Edwards curve parameter `d`. */
|
|
63
|
-
d: bigint;
|
|
64
|
-
/** Generator x coordinate. */
|
|
65
|
-
Gx: bigint;
|
|
66
|
-
/** Generator y coordinate. */
|
|
67
|
-
Gy: bigint;
|
|
68
|
-
}>;
|
|
69
|
-
|
|
70
|
-
// Helpers and Precomputes sections are reused between libraries
|
|
71
|
-
|
|
72
|
-
// ## Helpers
|
|
73
|
-
// ----------
|
|
74
|
-
/** Checks if something is Uint8Array. Be careful: nodejs Buffer will return true. */
|
|
75
|
-
const isBytes = (a: unknown): a is Uint8Array => {
|
|
76
|
-
// Plain `instanceof Uint8Array` is too strict for some Buffer / proxy / cross-realm cases.
|
|
77
|
-
// The fallback still requires a real ArrayBuffer view, so plain
|
|
78
|
-
// JSON-deserialized `{ constructor: ... }` spoofing is rejected, and
|
|
79
|
-
// `BYTES_PER_ELEMENT === 1` keeps the fallback on byte-oriented views.
|
|
80
|
-
return (
|
|
81
|
-
a instanceof Uint8Array ||
|
|
82
|
-
(ArrayBuffer.isView(a) &&
|
|
83
|
-
a.constructor.name === 'Uint8Array' &&
|
|
84
|
-
(a as Uint8Array).BYTES_PER_ELEMENT === 1)
|
|
85
|
-
);
|
|
86
|
-
};
|
|
87
|
-
/** Asserts something is Bytes. */
|
|
88
|
-
const abytes = (value: unknown, length?: number, title: string = ''): TRet<Uint8Array> => {
|
|
89
|
-
// Success path first: this runs at the start of every update() / digestInto(), and the
|
|
90
|
-
// common `abytes(data)` form must not pay for length handling it does not use.
|
|
91
|
-
if (isBytes(value) && (length === undefined || value.length === length))
|
|
92
|
-
return value as TRet<Uint8Array>;
|
|
93
|
-
// Error path: recompute freely to build the exact message.
|
|
94
|
-
const bytes = isBytes(value);
|
|
95
|
-
const ofLen = length !== undefined ? ` of length ${length}` : '';
|
|
96
|
-
const got = bytes ? `length=${value.length}` : `type=${typeof value}`;
|
|
97
|
-
const message = (title ? `"${title}" ` : '') + 'expected Uint8Array' + ofLen + ', got ' + got;
|
|
98
|
-
if (!bytes) throw new TypeError(message);
|
|
99
|
-
throw new RangeError(message);
|
|
100
|
-
};
|
|
101
|
-
// Validate, then take one owned copy, so later caller mutation cannot be observed — e.g. cannot
|
|
102
|
-
// make sign()'s nonce derivation and challenge derivation see different messages.
|
|
103
|
-
const snapshotBytes = (value: unknown, title: string = '', length?: number): TRet<Uint8Array> =>
|
|
104
|
-
Uint8Array.from(abytes(value, length, title));
|
|
105
|
-
// Callers keep values non-negative and within the requested width; padStart() won't truncate over-wide inputs.
|
|
106
|
-
const padh = (n: number | bigint, pad: number) => n.toString(16).padStart(pad, '0');
|
|
107
|
-
/** Convert byte array to hex string. */
|
|
108
|
-
const bytesToHex = (bytes: TArg<Uint8Array>): string => {
|
|
109
|
-
let hex = '';
|
|
110
|
-
for (const byte of abytes(bytes)) hex += padh(byte, 2);
|
|
111
|
-
return hex;
|
|
112
|
-
};
|
|
113
|
-
/** Convert hex string to byte array. */
|
|
114
|
-
const hexToBytes = (hex: string): TRet<Uint8Array> => {
|
|
115
|
-
const e = 'hex invalid'; // Strict ASCII hex only, with one generic error for parse failures.
|
|
116
|
-
if (typeof hex !== 'string') throw new TypeError(e);
|
|
117
|
-
if (hex.length % 2 || !/^[\da-f]*$/i.test(hex)) throw new RangeError(e);
|
|
118
|
-
const array = new Uint8Array(hex.length / 2);
|
|
119
|
-
for (let ai = 0, hi = 0; ai < array.length; ai++, hi += 2) {
|
|
120
|
-
const n1 = hex.charCodeAt(hi);
|
|
121
|
-
const n2 = hex.charCodeAt(hi + 1);
|
|
122
|
-
// Regex guarantees ASCII. For 0..9/A..F/a..f, this maps char codes to 0..15.
|
|
123
|
-
array[ai] = ((n1 & 15) + (n1 >> 6) * 9) * 16 + (n2 & 15) + (n2 >> 6) * 9;
|
|
124
|
-
}
|
|
125
|
-
return array as TRet<Uint8Array>;
|
|
126
|
-
};
|
|
127
|
-
declare const globalThis: Record<string, any> | undefined; // Typescript symbol present in browsers
|
|
128
|
-
// WebCrypto is available in all modern environments
|
|
129
|
-
/** Copies several Uint8Arrays into one. */
|
|
130
|
-
const concatBytes = (...arrays: TArg<Uint8Array[]>): TRet<Uint8Array> => {
|
|
131
|
-
let sum = 0;
|
|
132
|
-
for (const a of arrays) sum += abytes(a).length;
|
|
133
|
-
const res = new Uint8Array(sum);
|
|
134
|
-
let pad = 0;
|
|
135
|
-
for (const a of arrays) {
|
|
136
|
-
res.set(a, pad);
|
|
137
|
-
pad += a.length;
|
|
138
|
-
}
|
|
139
|
-
return res;
|
|
140
|
-
};
|
|
141
|
-
/**
|
|
142
|
-
* WebCrypto OS-level CSPRNG (random number generator).
|
|
143
|
-
* Will throw when not available; large-request ceilings are delegated to getRandomValues().
|
|
144
|
-
*/
|
|
145
|
-
const randomBytes = (len: number = LEN): TRet<Uint8Array> => {
|
|
146
|
-
const c = globalThis?.crypto;
|
|
147
|
-
if (typeof c?.getRandomValues !== 'function')
|
|
148
|
-
throw new Error('crypto.getRandomValues must be defined, consider polyfill');
|
|
149
|
-
return c.getRandomValues(new Uint8Array(len)) as TRet<Uint8Array>;
|
|
150
|
-
};
|
|
151
|
-
/** Inclusive-lower, exclusive-upper bigint range assertion. */
|
|
152
|
-
const arange = (n: bigint, min: bigint, max: bigint, msg = 'bad number: out of range'): bigint => {
|
|
153
|
-
if (typeof n !== 'bigint') throw new TypeError(msg);
|
|
154
|
-
if (min <= n && n < max) return n;
|
|
155
|
-
throw new RangeError(msg);
|
|
156
|
-
};
|
|
157
|
-
/** Canonical modular reduction. Callers must provide a positive modulus. */
|
|
158
|
-
const mod = (a: bigint, b: bigint = P) => ((a %= b) >= 0n ? a : b + a);
|
|
159
|
-
// Low-255-bit mask used by the `2^255 - 19` fast reduction in `modP(...)`.
|
|
160
|
-
const P_MASK = (1n << 255n) - 1n;
|
|
161
|
-
// Fast reduction for the special prime `2^255 - 19`. This path assumes nonnegative inputs; the
|
|
162
|
-
// generic fallback would simply be `mod(num, P)`.
|
|
163
|
-
const modP = (num: bigint): bigint => {
|
|
164
|
-
if (num < 0n) throw new RangeError('negative coordinate');
|
|
165
|
-
let r = (num >> 255n) * 19n + (num & P_MASK);
|
|
166
|
-
r = (r >> 255n) * 19n + (r & P_MASK);
|
|
167
|
-
return r % P;
|
|
168
|
-
};
|
|
169
|
-
// Reduce modulo the subgroup order stored in implementation constant `N` (RFC 8032's `L`).
|
|
170
|
-
const modN = (a: bigint) => mod(a, N);
|
|
171
|
-
/** Modular inversion using extended euclidean GCD. Variable-time (non-CT). */
|
|
172
|
-
const invert = (number: bigint, modulo: bigint): bigint => {
|
|
173
|
-
if (number === 0n) throw new Error('invert: expected non-zero number');
|
|
174
|
-
// modulo = 1 is the zero ring: gcd(x, 1) = 1 makes the loop below "succeed" and return the
|
|
175
|
-
// useless inverse 0. Reject it like pow() and invertCt() do.
|
|
176
|
-
if (modulo <= 1n) throw new Error('invert: expected modulus > 1, got ' + modulo);
|
|
177
|
-
// This is variable-time: the loop count depends on `number`.
|
|
178
|
-
let a = mod(number, modulo);
|
|
179
|
-
let b = modulo;
|
|
180
|
-
// Only the Bézout coefficient of `number` (x/u chain) is tracked; the coefficient of `modulo`
|
|
181
|
-
// never affects the output, so it is not computed.
|
|
182
|
-
// prettier-ignore
|
|
183
|
-
let x = 0n, u = 1n;
|
|
184
|
-
while (a !== 0n) {
|
|
185
|
-
const q = b / a;
|
|
186
|
-
const r = b - a * q;
|
|
187
|
-
const m = x - u * q;
|
|
188
|
-
// prettier-ignore
|
|
189
|
-
b = a, a = r, x = u, u = m;
|
|
190
|
-
}
|
|
191
|
-
const gcd = b;
|
|
192
|
-
if (gcd !== 1n) throw new Error('invert: does not exist');
|
|
193
|
-
return mod(x, modulo);
|
|
194
|
-
};
|
|
195
|
-
// Dynamic lookup keeps sync/async hash providers configurable at runtime. Both exported slots are
|
|
196
|
-
// caller-owned and may be unset; wrapper helpers use this lookup first and then enforce the digest
|
|
197
|
-
// contract instead of trusting provider output.
|
|
198
|
-
const _hash = (name: string) => {
|
|
199
|
-
// @ts-ignore
|
|
200
|
-
const fn = hashes[name];
|
|
201
|
-
if (typeof fn !== 'function') throw new Error('hashes.' + name + ' not set');
|
|
202
|
-
return fn;
|
|
203
|
-
};
|
|
204
|
-
// All exported provider slots are caller-configurable and may be unset or return arbitrary values,
|
|
205
|
-
// so wrapper helpers must enforce the exact 64-byte SHA-512 digest contract instead of trusting providers.
|
|
206
|
-
const callHash = (name: string, ...m: Uint8Array[]): TRet<Uint8Array> =>
|
|
207
|
-
abytes(_hash(name)(concatBytes(...m)), 64, 'digest');
|
|
208
|
-
const callHashAsync = async (name: string, ...m: Uint8Array[]): Promise<TRet<Uint8Array>> =>
|
|
209
|
-
abytes(await _hash(name)(concatBytes(...m)), 64, 'digest');
|
|
210
|
-
/**
|
|
211
|
-
* SHA-512 helper used by the synchronous API.
|
|
212
|
-
* @param msg - Message bytes to hash.
|
|
213
|
-
* @returns 64-byte SHA-512 digest.
|
|
214
|
-
* @example
|
|
215
|
-
* Hash message bytes after wiring the synchronous SHA-512 implementation.
|
|
216
|
-
*
|
|
217
|
-
* ```ts
|
|
218
|
-
* import * as ed from '@noble/ed25519';
|
|
219
|
-
* import { sha512 } from '@noble/hashes/sha2.js';
|
|
220
|
-
*
|
|
221
|
-
* ed.hashes.sha512 = sha512;
|
|
222
|
-
* const digest = ed.hash(new Uint8Array([1, 2, 3]));
|
|
223
|
-
* ```
|
|
224
|
-
*/
|
|
225
|
-
// Public helper validates the message boundary explicitly; the configured provider is still looked
|
|
226
|
-
// up dynamically and its output is checked with `callHash(...)`.
|
|
227
|
-
const hash = (msg: TArg<Uint8Array>): TRet<Uint8Array> =>
|
|
228
|
-
callHash('sha512', abytes(msg, undefined, 'message'));
|
|
229
|
-
// Runtime class guard: this is `instanceof Point`, so cross-realm / duplicate-bundle Point objects
|
|
230
|
-
// are rejected even if they are structurally identical.
|
|
231
|
-
const apoint = (p: unknown) => {
|
|
232
|
-
if (p instanceof Point) return p;
|
|
233
|
-
throw new TypeError('Point expected');
|
|
234
|
-
};
|
|
235
|
-
/** Point in 2d xy affine coordinates. */
|
|
236
|
-
export type AffinePoint = {
|
|
237
|
-
/** Affine x coordinate. */
|
|
238
|
-
x: bigint;
|
|
239
|
-
/** Affine y coordinate. */
|
|
240
|
-
y: bigint;
|
|
241
|
-
};
|
|
242
|
-
// ## End of Helpers
|
|
243
|
-
// -----------------
|
|
244
|
-
|
|
245
|
-
// Exclusive upper bound `2^256` used by 32-byte decode/serialization range checks.
|
|
246
|
-
const B256 = 2n ** 256n;
|
|
247
|
-
/**
|
|
248
|
-
* Point in XYZT extended coordinates.
|
|
249
|
-
* @param X - X coordinate.
|
|
250
|
-
* @param Y - Y coordinate.
|
|
251
|
-
* @param Z - Projective Z coordinate.
|
|
252
|
-
* @param T - Cached cross-product term.
|
|
253
|
-
* @example
|
|
254
|
-
* Do point arithmetic with the built-in base point and encode the result as hex.
|
|
255
|
-
*
|
|
256
|
-
* ```ts
|
|
257
|
-
* const hex = Point.BASE.double().toHex();
|
|
258
|
-
* ```
|
|
259
|
-
*/
|
|
260
|
-
class Point {
|
|
261
|
-
static BASE: Point;
|
|
262
|
-
static ZERO: Point;
|
|
263
|
-
readonly X: bigint;
|
|
264
|
-
readonly Y: bigint;
|
|
265
|
-
readonly Z: bigint;
|
|
266
|
-
readonly T: bigint;
|
|
267
|
-
// Constructor only bounds-checks and freezes XYZT coordinates; it does not prove the point is
|
|
268
|
-
// on-curve or that T matches X*Y/Z.
|
|
269
|
-
constructor(X: bigint, Y: bigint, Z: bigint, T: bigint) {
|
|
270
|
-
const max = B256;
|
|
271
|
-
this.X = arange(X, 0n, max);
|
|
272
|
-
this.Y = arange(Y, 0n, max);
|
|
273
|
-
this.Z = arange(Z, 1n, max);
|
|
274
|
-
this.T = arange(T, 0n, max);
|
|
275
|
-
freeze(this);
|
|
276
|
-
}
|
|
277
|
-
static CURVE(): EdwardsOpts {
|
|
278
|
-
return ed25519_CURVE;
|
|
279
|
-
}
|
|
280
|
-
static fromAffine(p: AffinePoint): Point {
|
|
281
|
-
return new Point(p.x, p.y, 1n, modP(p.x * p.y));
|
|
282
|
-
}
|
|
283
|
-
/** RFC8032 5.1.3: Uint8Array to Point. */
|
|
284
|
-
static fromBytes(bytes: TArg<Uint8Array>, zip215 = false): Point {
|
|
285
|
-
const normed = snapshotBytes(bytes, 'point', LEN); // owned copy: sign-bit mask below mutates it
|
|
286
|
-
// adjust first LE byte = last BE byte
|
|
287
|
-
const lastByte = normed[31];
|
|
288
|
-
normed[31] = lastByte & ~0x80;
|
|
289
|
-
const y = bytesToNumberLE(normed);
|
|
290
|
-
// After clearing the sign bit, parsed `y` is always < 2^255. ZIP-215 still accepts the full
|
|
291
|
-
// post-mask range here, while strict RFC8032 decoding further requires `y < p`.
|
|
292
|
-
if (!zip215) arange(y, 0n, P);
|
|
293
|
-
|
|
294
|
-
const y2 = modP(y * y); // y²
|
|
295
|
-
const u = mod(y2 - 1n); // u=y²-1
|
|
296
|
-
const v = modP(_d * y2 + 1n); // v=dy²+1
|
|
297
|
-
let { isValid, value: x } = uvRatio(u, v); // (uv³)(uv⁷)^(p-5)/8; square root
|
|
298
|
-
if (!isValid) throw new Error('bad point: y not sqrt'); // not square root: bad point
|
|
299
|
-
const isLastByteOdd = !!(lastByte & 0x80); // x_0, last bit
|
|
300
|
-
// ZIP-215-compatible decoding keeps the x=0 / sign-bit=1 encoding accepted; strict RFC 8032
|
|
301
|
-
// rejects it, but the vendored ZIP-215 compliance vectors include this form in A/R bytes.
|
|
302
|
-
if (!zip215 && x === 0n && isLastByteOdd) throw new Error('bad point: x==0, isLastByteOdd'); // x=0, x_0=1
|
|
303
|
-
if (isLastByteOdd !== !!(x & 1n)) x = mod(-x); // adjust sign of x coordinate
|
|
304
|
-
return new Point(x, y, 1n, modP(x * y)); // Z=1, T=xy
|
|
305
|
-
}
|
|
306
|
-
static fromHex(hex: string, zip215?: boolean): Point {
|
|
307
|
-
return Point.fromBytes(hexToBytes(hex), zip215);
|
|
308
|
-
}
|
|
309
|
-
get x(): bigint {
|
|
310
|
-
return this.toAffine().x;
|
|
311
|
-
}
|
|
312
|
-
get y(): bigint {
|
|
313
|
-
return this.toAffine().y;
|
|
314
|
-
}
|
|
315
|
-
/** Checks if the point is valid and on-curve. */
|
|
316
|
-
assertValidity(): this {
|
|
317
|
-
const a = _a;
|
|
318
|
-
const d = _d;
|
|
319
|
-
const p = this;
|
|
320
|
-
// Intentional stricter-than-on-curve policy: reject ZERO by default because many protocols
|
|
321
|
-
// require a non-zero point, and silently accepting identity points is a common caller mistake.
|
|
322
|
-
if (p.is0()) throw new Error('bad point: ZERO');
|
|
323
|
-
// Equation in affine coordinates: ax² + y² = 1 + dx²y²
|
|
324
|
-
// Equation in projective coordinates (X/Z, Y/Z, Z): (aX² + Y²)Z² = Z⁴ + dX²Y²
|
|
325
|
-
const { X, Y, Z, T } = p;
|
|
326
|
-
const X2 = modP(X * X); // X²
|
|
327
|
-
const Y2 = modP(Y * Y); // Y²
|
|
328
|
-
const Z2 = modP(Z * Z); // Z²
|
|
329
|
-
const Z4 = modP(Z2 * Z2); // Z⁴
|
|
330
|
-
const aX2 = modP(X2 * a); // aX²
|
|
331
|
-
const left = modP(Z2 * (aX2 + Y2)); // (aX² + Y²)Z²
|
|
332
|
-
const right = mod(Z4 + modP(d * modP(X2 * Y2))); // Z⁴ + dX²Y²
|
|
333
|
-
if (left !== right) throw new Error('bad point: equation left != right (1)');
|
|
334
|
-
// In Extended coordinates we also have T, which is x*y=T/Z: check X*Y == Z*T
|
|
335
|
-
const XY = modP(X * Y);
|
|
336
|
-
const ZT = modP(Z * T);
|
|
337
|
-
if (XY !== ZT) throw new Error('bad point: equation left != right (2)');
|
|
338
|
-
return this;
|
|
339
|
-
}
|
|
340
|
-
/** Equality check: compare points P&Q. */
|
|
341
|
-
equals(other: Point): boolean {
|
|
342
|
-
const { X: X1, Y: Y1, Z: Z1 } = this;
|
|
343
|
-
const { X: X2, Y: Y2, Z: Z2 } = apoint(other); // checks class equality
|
|
344
|
-
return modP(X1 * Z2) === modP(X2 * Z1) && modP(Y1 * Z2) === modP(Y2 * Z1);
|
|
345
|
-
}
|
|
346
|
-
is0(): boolean {
|
|
347
|
-
return this.equals(I);
|
|
348
|
-
}
|
|
349
|
-
/** Flip point over y coordinate. */
|
|
350
|
-
negate(): Point {
|
|
351
|
-
return new Point(mod(-this.X), this.Y, this.Z, mod(-this.T));
|
|
352
|
-
}
|
|
353
|
-
/** Point doubling. Complete formula. Cost: `4M + 4S + 1*a + 6add + 1*2`. */
|
|
354
|
-
double(): Point {
|
|
355
|
-
const { X: X1, Y: Y1, Z: Z1 } = this;
|
|
356
|
-
const a = _a;
|
|
357
|
-
// https://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html#doubling-dbl-2008-hwcd
|
|
358
|
-
const A = modP(X1 * X1);
|
|
359
|
-
const B = modP(Y1 * Y1);
|
|
360
|
-
const C = modP(2n * Z1 * Z1);
|
|
361
|
-
const D = modP(a * A);
|
|
362
|
-
const x1y1 = mod(X1 + Y1);
|
|
363
|
-
const E = mod(modP(x1y1 * x1y1) - A - B);
|
|
364
|
-
const G = mod(D + B);
|
|
365
|
-
const F = mod(G - C);
|
|
366
|
-
const H = mod(D - B);
|
|
367
|
-
const X3 = modP(E * F);
|
|
368
|
-
const Y3 = modP(G * H);
|
|
369
|
-
const T3 = modP(E * H);
|
|
370
|
-
const Z3 = modP(F * G);
|
|
371
|
-
return new Point(X3, Y3, Z3, T3);
|
|
372
|
-
}
|
|
373
|
-
/** Point addition. Complete formula. Cost: `9M + 1*a + 1*d + 7add`. */
|
|
374
|
-
add(other: Point): Point {
|
|
375
|
-
const { X: X1, Y: Y1, Z: Z1, T: T1 } = this;
|
|
376
|
-
const { X: X2, Y: Y2, Z: Z2, T: T2 } = apoint(other); // doesn't check if other on-curve
|
|
377
|
-
const a = _a;
|
|
378
|
-
const d = _d;
|
|
379
|
-
// https://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html#addition-add-2008-hwcd
|
|
380
|
-
const A = modP(X1 * X2);
|
|
381
|
-
const B = modP(Y1 * Y2);
|
|
382
|
-
const C = modP(modP(T1 * d) * T2);
|
|
383
|
-
const D = modP(Z1 * Z2);
|
|
384
|
-
const E = mod(modP(mod(X1 + Y1) * mod(X2 + Y2)) - A - B);
|
|
385
|
-
const F = mod(D - C);
|
|
386
|
-
const G = mod(D + C);
|
|
387
|
-
const H = mod(B - modP(a * A));
|
|
388
|
-
const X3 = modP(E * F);
|
|
389
|
-
const Y3 = modP(G * H);
|
|
390
|
-
const T3 = modP(E * H);
|
|
391
|
-
const Z3 = modP(F * G);
|
|
392
|
-
return new Point(X3, Y3, Z3, T3);
|
|
393
|
-
}
|
|
394
|
-
subtract(other: Point): Point {
|
|
395
|
-
return this.add(apoint(other).negate());
|
|
396
|
-
}
|
|
397
|
-
/**
|
|
398
|
-
* Point-by-scalar multiplication. Safe mode requires `1 <= n < CURVE.n`.
|
|
399
|
-
* Unsafe mode additionally permits `n = 0` and returns the identity point for that case.
|
|
400
|
-
* Uses {@link wNAF} for base point.
|
|
401
|
-
* Uses fake point to mitigate side-channel leakage.
|
|
402
|
-
* @param n - scalar by which point is multiplied
|
|
403
|
-
* @param safe - safe mode guards against timing attacks; unsafe mode is faster
|
|
404
|
-
*/
|
|
405
|
-
multiply(n: bigint, safe = true): Point {
|
|
406
|
-
// Mirror noble-curves: unsafe mode still validates scalar range first, but intentionally keeps
|
|
407
|
-
// `n = 0` as the one extra accepted case used by verification-style callers.
|
|
408
|
-
if (!safe && n === 0n) return I;
|
|
409
|
-
arange(n, 1n, N);
|
|
410
|
-
if (!safe && this.is0()) return I;
|
|
411
|
-
if (n === 1n) return this;
|
|
412
|
-
if (this.equals(G)) return wNAF(n).p;
|
|
413
|
-
// init result point & fake point
|
|
414
|
-
let p = I;
|
|
415
|
-
let f = G;
|
|
416
|
-
let d: Point = this;
|
|
417
|
-
// Safe mode always runs 256 iterations so ladder length can't leak the scalar's
|
|
418
|
-
// leading zero bits; unsafe mode stops at the top set bit for speed.
|
|
419
|
-
for (let i = 0; safe ? i < 256 : n > 0n; i++) {
|
|
420
|
-
// if bit is present, add to point
|
|
421
|
-
// if not present, add to fake, for timing safety
|
|
422
|
-
if (n & 1n) p = p.add(d);
|
|
423
|
-
else if (safe) f = f.add(d);
|
|
424
|
-
d = d.double();
|
|
425
|
-
n >>= 1n;
|
|
426
|
-
}
|
|
427
|
-
return p;
|
|
428
|
-
}
|
|
429
|
-
multiplyUnsafe(scalar: bigint): Point {
|
|
430
|
-
return this.multiply(scalar, false);
|
|
431
|
-
}
|
|
432
|
-
/** Convert point to 2d xy affine point. (X, Y, Z) ∋ (x=X/Z, y=Y/Z) */
|
|
433
|
-
toAffine(): AffinePoint {
|
|
434
|
-
const { X, Y, Z } = this;
|
|
435
|
-
// Fast-path only for the identity point; all other inputs still go through inversion.
|
|
436
|
-
if (this.equals(I)) return { x: 0n, y: 1n };
|
|
437
|
-
const iz = invert(Z, P);
|
|
438
|
-
// (Z * Z^-1) must be 1, otherwise bad math
|
|
439
|
-
if (modP(Z * iz) !== 1n) throw new Error('invalid inverse');
|
|
440
|
-
// x = X*Z^-1; y = Y*Z^-1
|
|
441
|
-
return { x: modP(X * iz), y: modP(Y * iz) };
|
|
442
|
-
}
|
|
443
|
-
toBytes(): TRet<Uint8Array> {
|
|
444
|
-
const { x, y } = this.toAffine();
|
|
445
|
-
const b = numTo32bLE(y);
|
|
446
|
-
// store sign in first LE byte
|
|
447
|
-
b[31] |= x & 1n ? 0x80 : 0;
|
|
448
|
-
return b;
|
|
449
|
-
}
|
|
450
|
-
toHex(): string {
|
|
451
|
-
return bytesToHex(this.toBytes());
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
clearCofactor(): Point {
|
|
455
|
-
return this.multiply(8n, false); // h = 8
|
|
456
|
-
}
|
|
457
|
-
isSmallOrder(): boolean {
|
|
458
|
-
return this.clearCofactor().is0();
|
|
459
|
-
}
|
|
460
|
-
isTorsionFree(): boolean {
|
|
461
|
-
// Multiply by big number N. We can't `mul(N)` because of checks. Instead, we `mul(N/2)*2+1`;
|
|
462
|
-
// N is odd, so N/2 truncates and the final `add(this)` is always needed.
|
|
463
|
-
return this.multiply(N / 2n, false)
|
|
464
|
-
.double()
|
|
465
|
-
.add(this)
|
|
466
|
-
.is0();
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
/** Generator / base point */
|
|
470
|
-
const G: Point = new Point(Gx, Gy, 1n, mod(Gx * Gy));
|
|
471
|
-
/** Identity / zero point */
|
|
472
|
-
const I: Point = new Point(0n, 1n, 1n, 0n);
|
|
473
|
-
// Static aliases
|
|
474
|
-
Point.BASE = G;
|
|
475
|
-
Point.ZERO = I;
|
|
476
|
-
|
|
477
|
-
const numTo32bLE = (num: bigint): TRet<Uint8Array> =>
|
|
478
|
-
hexToBytes(padh(arange(num, 0n, B256), 64)).reverse() as TRet<Uint8Array>;
|
|
479
|
-
// Caller-enforced width: some sites require 32-byte RFC encodings, while others intentionally feed
|
|
480
|
-
// wider SHA-512 output chunks through the same little-endian parser.
|
|
481
|
-
const bytesToNumberLE = (b: Uint8Array): bigint =>
|
|
482
|
-
BigInt('0x' + bytesToHex(Uint8Array.from(abytes(b)).reverse()));
|
|
483
|
-
|
|
484
|
-
const pow2 = (x: bigint, power: number): bigint => {
|
|
485
|
-
// pow2(x, 4) == x^(2^4)
|
|
486
|
-
// Negative `power` values are not rejected here and currently leave `x` unchanged.
|
|
487
|
-
let r = x;
|
|
488
|
-
while (power-- > 0) {
|
|
489
|
-
r = modP(r * r);
|
|
490
|
-
}
|
|
491
|
-
return r;
|
|
492
|
-
};
|
|
493
|
-
|
|
494
|
-
// prettier-ignore
|
|
495
|
-
const pow_2_252_3 = (x: bigint) => { // x^(2^252-3) unrolled util for square root
|
|
496
|
-
const x2 = modP(x * x); // x^2, bits 1
|
|
497
|
-
const b2 = modP(x2 * x); // x^3, bits 11
|
|
498
|
-
const b4 = modP(pow2(b2, 2) * b2); // x^(2^4-1), bits 1111
|
|
499
|
-
const b5 = modP(pow2(b4, 1) * x); // x^(2^5-1), bits 11111
|
|
500
|
-
const b10 = modP(pow2(b5, 5) * b5); // x^(2^10-1)
|
|
501
|
-
const b20 = modP(pow2(b10, 10) * b10); // x^(2^20-1)
|
|
502
|
-
const b40 = modP(pow2(b20, 20) * b20); // x^(2^40-1)
|
|
503
|
-
const b80 = modP(pow2(b40, 40) * b40); // x^(2^80-1)
|
|
504
|
-
const b160 = modP(pow2(b80, 80) * b80); // x^(2^160-1)
|
|
505
|
-
const b240 = modP(pow2(b160, 80) * b80); // x^(2^240-1)
|
|
506
|
-
const b250 = modP(pow2(b240, 10) * b10); // x^(2^250-1)
|
|
507
|
-
return modP(pow2(b250, 2) * x); // x^((p-5)/8), used by RFC8032 point decode
|
|
508
|
-
};
|
|
509
|
-
const RM1 = 0x2b8324804fc1df0b2b4d00993dfbd7a72f431806ad2fe478c4ee1b274a0ea0b0n; // 2^((p-1)/4) = sqrt(-1)
|
|
510
|
-
// RFC8032 §5.1.3 square-root helper for point decompression. `value` is only meaningful when
|
|
511
|
-
// `isValid` is true; callers are also expected to pass canonical field elements with non-zero `v`.
|
|
512
|
-
// prettier-ignore
|
|
513
|
-
const uvRatio = (u: bigint, v: bigint): { isValid: boolean, value: bigint } => {
|
|
514
|
-
const v3 = modP(v * modP(v * v)); // v³
|
|
515
|
-
const v7 = modP(modP(v3 * v3) * v); // v⁷
|
|
516
|
-
const pow = pow_2_252_3(modP(u * v7)); // (uv⁷)^(p-5)/8
|
|
517
|
-
let x = modP(u * modP(v3 * pow)); // (uv³)(uv⁷)^(p-5)/8
|
|
518
|
-
const vx2 = modP(v * modP(x * x)); // vx²
|
|
519
|
-
const root1 = x; // First root candidate
|
|
520
|
-
const root2 = modP(x * RM1); // Second root candidate; RM1 is √-1
|
|
521
|
-
const useRoot1 = vx2 === u; // If vx² = u (mod p), x is a square root
|
|
522
|
-
const useRoot2 = vx2 === mod(-u); // If vx² = -u, set x <-- x * 2^((p-1)/4)
|
|
523
|
-
const noRoot = vx2 === mod(-u * RM1); // There is no valid root, vx² = -u√-1
|
|
524
|
-
if (useRoot1) x = root1;
|
|
525
|
-
if (useRoot2 || noRoot) x = root2; // We return root2 anyway, for const-time
|
|
526
|
-
if ((mod(x) & 1n) === 1n) x = mod(-x); // edIsNegative
|
|
527
|
-
return { isValid: useRoot1 || useRoot2, value: x };
|
|
528
|
-
};
|
|
529
|
-
// Reduce a little-endian byte string modulo the subgroup order `N` (RFC 8032's `L`); the `hash`
|
|
530
|
-
// param name reflects the common caller shape, not an input restriction.
|
|
531
|
-
const modL_LE = (hash: Uint8Array): bigint => modN(bytesToNumberLE(hash));
|
|
532
|
-
type ExtK = {
|
|
533
|
-
head: Uint8Array;
|
|
534
|
-
prefix: Uint8Array;
|
|
535
|
-
scalar: bigint;
|
|
536
|
-
point: Point;
|
|
537
|
-
pointBytes: Uint8Array;
|
|
538
|
-
};
|
|
539
|
-
|
|
540
|
-
// RFC8032 5.1.5. Split the 64-byte hashed seed into the clamped scalar half and nonce prefix.
|
|
541
|
-
const hashedToExtK = (hashed: Uint8Array): TRet<ExtK> => {
|
|
542
|
-
// slice creates a copy, unlike subarray
|
|
543
|
-
const copy = snapshotBytes(hashed);
|
|
544
|
-
const head = copy.slice(0, 32);
|
|
545
|
-
head[0] &= 248; // Clamp bits: 0b1111_1000
|
|
546
|
-
head[31] &= 127; // 0b0111_1111
|
|
547
|
-
head[31] |= 64; // 0b0100_0000
|
|
548
|
-
const prefix = copy.slice(32); // secret key "prefix"
|
|
549
|
-
// RFC words this as `[s]B`; reducing the clamped little-endian scalar modulo `N` is equivalent
|
|
550
|
-
// for base-point multiplication because `G` already has subgroup order `N`.
|
|
551
|
-
const scalar = modL_LE(head);
|
|
552
|
-
const point = G.multiply(scalar); // public key point
|
|
553
|
-
const pointBytes = point.toBytes(); // point serialized to Uint8Array
|
|
554
|
-
return { head, prefix, scalar, point, pointBytes } as TRet<ExtK>;
|
|
555
|
-
};
|
|
556
|
-
|
|
557
|
-
// RFC8032 5.1.5; getPublicKey async, sync. Hash secret key and extract point.
|
|
558
|
-
const getExtendedPublicKeyAsync = (secretKey: TArg<Uint8Array>): Promise<TRet<ExtK>> =>
|
|
559
|
-
callHashAsync('sha512Async', abytes(secretKey, LEN, 'secretKey')).then(hashedToExtK);
|
|
560
|
-
const getExtendedPublicKey = (secretKey: TArg<Uint8Array>): TRet<ExtK> =>
|
|
561
|
-
hashedToExtK(callHash('sha512', abytes(secretKey, LEN, 'secretKey')));
|
|
562
|
-
/**
|
|
563
|
-
* Creates a 32-byte Ed25519 public key from the RFC 8032 32-byte secret-key seed. Async.
|
|
564
|
-
* @param secretKey - 32-byte RFC 8032 secret-key seed, not a 64-byte expanded secret key.
|
|
565
|
-
* @returns 32-byte public key.
|
|
566
|
-
* @throws On wrong argument types. {@link TypeError}
|
|
567
|
-
* @throws On wrong argument ranges or values. {@link RangeError}
|
|
568
|
-
* @example
|
|
569
|
-
* Derive the public key bytes for a newly generated signer secret.
|
|
570
|
-
*
|
|
571
|
-
* ```ts
|
|
572
|
-
* import * as ed from '@noble/ed25519';
|
|
573
|
-
*
|
|
574
|
-
* const secretKey = ed.utils.randomSecretKey();
|
|
575
|
-
* const publicKey = await ed.getPublicKeyAsync(secretKey);
|
|
576
|
-
* ```
|
|
577
|
-
*/
|
|
578
|
-
const getPublicKeyAsync = (secretKey: TArg<Uint8Array>): Promise<TRet<Uint8Array>> =>
|
|
579
|
-
getExtendedPublicKeyAsync(secretKey).then((p) => p.pointBytes as TRet<Uint8Array>);
|
|
580
|
-
/**
|
|
581
|
-
* Creates a 32-byte Ed25519 public key from the RFC 8032 32-byte secret-key seed.
|
|
582
|
-
* To use, set `hashes.sha512` first.
|
|
583
|
-
* @param secretKey - 32-byte RFC 8032 secret-key seed, not a 64-byte expanded secret key.
|
|
584
|
-
* @returns 32-byte public key.
|
|
585
|
-
* @throws If synchronous SHA-512 has not been configured in `hashes`. {@link Error}
|
|
586
|
-
* @throws On wrong argument types. {@link TypeError}
|
|
587
|
-
* @throws On wrong argument ranges or values. {@link RangeError}
|
|
588
|
-
* @example
|
|
589
|
-
* Derive the public key entirely through the synchronous API.
|
|
590
|
-
*
|
|
591
|
-
* ```ts
|
|
592
|
-
* import * as ed from '@noble/ed25519';
|
|
593
|
-
* import { sha512 } from '@noble/hashes/sha2.js';
|
|
594
|
-
*
|
|
595
|
-
* ed.hashes.sha512 = sha512;
|
|
596
|
-
* const secretKey = ed.utils.randomSecretKey();
|
|
597
|
-
* const publicKey = ed.getPublicKey(secretKey);
|
|
598
|
-
* ```
|
|
599
|
-
*/
|
|
600
|
-
const getPublicKey = (secretKey: TArg<Uint8Array>): TRet<Uint8Array> =>
|
|
601
|
-
getExtendedPublicKey(secretKey).pointBytes;
|
|
602
|
-
type Finishable<T> = readonly [
|
|
603
|
-
// Shared between sync/async sign() and verify(): hash `hashable` with SHA-512, then hand the
|
|
604
|
-
// resulting 64-byte digest to `finish(...)`.
|
|
605
|
-
Uint8Array,
|
|
606
|
-
(hashed: Uint8Array) => T,
|
|
607
|
-
];
|
|
608
|
-
const hashFinishAsync = async <T>(res: Finishable<T>): Promise<T> =>
|
|
609
|
-
res[1](await callHashAsync('sha512Async', res[0]));
|
|
610
|
-
const hashFinishSync = <T>(res: Finishable<T>): T => res[1](callHash('sha512', res[0]));
|
|
611
|
-
// Code, shared between sync & async sign
|
|
612
|
-
const _sign = (
|
|
613
|
-
e: { pointBytes: Uint8Array; scalar: bigint },
|
|
614
|
-
rBytes: Uint8Array,
|
|
615
|
-
msg: Uint8Array
|
|
616
|
-
): Finishable<TRet<Uint8Array>> => {
|
|
617
|
-
const { pointBytes: A, scalar: s } = e;
|
|
618
|
-
const r = modL_LE(rBytes); // r was created outside, reduce it modulo L
|
|
619
|
-
// RFC 8032 5.1.6 allows r mod L = 0, and SUPERCOP ref10 accepts the resulting identity-point
|
|
620
|
-
// signature.
|
|
621
|
-
// We intentionally keep the safe multiply() rejection here so a miswired all-zero SHA-512 provider
|
|
622
|
-
// fails loudly instead of silently producing a degenerate signature.
|
|
623
|
-
const R = G.multiply(r).toBytes(); // R = [r]B
|
|
624
|
-
const hashable = concatBytes(R, A, msg); // dom2(F, C) || R || A || PH(M)
|
|
625
|
-
const finish = (hashed: Uint8Array): TRet<Uint8Array> => {
|
|
626
|
-
// k = SHA512(dom2(F, C) || R || A || PH(M))
|
|
627
|
-
const S = modN(r + modL_LE(hashed) * s); // S = (r + k * s) mod L; 0 <= s < l
|
|
628
|
-
return abytes(concatBytes(R, numTo32bLE(S)), 64); // 64-byte sig: 32-byte encoded R point || 32-byte LE(S)
|
|
629
|
-
};
|
|
630
|
-
return [hashable, finish];
|
|
631
|
-
};
|
|
632
|
-
/**
|
|
633
|
-
* Signs message using secret key. Async.
|
|
634
|
-
* Follows RFC8032 5.1.6.
|
|
635
|
-
* @param message - Message bytes to sign.
|
|
636
|
-
* @param secretKey - 32-byte RFC 8032 secret-key seed, not a 64-byte expanded secret key.
|
|
637
|
-
* @returns 64-byte Ed25519 signature.
|
|
638
|
-
* @throws On wrong argument types. {@link TypeError}
|
|
639
|
-
* @throws On wrong argument ranges or values. {@link RangeError}
|
|
640
|
-
* @example
|
|
641
|
-
* Sign an arbitrary message with a fresh Ed25519 secret key.
|
|
642
|
-
*
|
|
643
|
-
* ```ts
|
|
644
|
-
* import * as ed from '@noble/ed25519';
|
|
645
|
-
*
|
|
646
|
-
* const secretKey = ed.utils.randomSecretKey();
|
|
647
|
-
* const message = new Uint8Array([1, 2, 3]);
|
|
648
|
-
* const signature = await ed.signAsync(message, secretKey);
|
|
649
|
-
* ```
|
|
650
|
-
*/
|
|
651
|
-
const signAsync = async (
|
|
652
|
-
message: TArg<Uint8Array>,
|
|
653
|
-
secretKey: TArg<Uint8Array>
|
|
654
|
-
): Promise<TRet<Uint8Array>> => {
|
|
655
|
-
const m = snapshotBytes(message, 'message');
|
|
656
|
-
const e = await getExtendedPublicKeyAsync(secretKey);
|
|
657
|
-
// r = SHA512(dom2(F, C) || prefix || PH(M)); then generate R, k, S and the signature.
|
|
658
|
-
return hashFinishAsync(_sign(e, await callHashAsync('sha512Async', e.prefix, m), m));
|
|
659
|
-
};
|
|
660
|
-
/**
|
|
661
|
-
* Signs message using secret key. To use, set `hashes.sha512` first.
|
|
662
|
-
* Follows RFC8032 5.1.6.
|
|
663
|
-
* @param message - Message bytes to sign.
|
|
664
|
-
* @param secretKey - 32-byte RFC 8032 secret-key seed, not a 64-byte expanded secret key.
|
|
665
|
-
* @returns 64-byte Ed25519 signature.
|
|
666
|
-
* @throws If synchronous SHA-512 has not been configured in `hashes`. {@link Error}
|
|
667
|
-
* @throws On wrong argument types. {@link TypeError}
|
|
668
|
-
* @throws On wrong argument ranges or values. {@link RangeError}
|
|
669
|
-
* @example
|
|
670
|
-
* Use the sync API when you've wired a SHA-512 implementation yourself.
|
|
671
|
-
*
|
|
672
|
-
* ```ts
|
|
673
|
-
* import * as ed from '@noble/ed25519';
|
|
674
|
-
* import { sha512 } from '@noble/hashes/sha2.js';
|
|
675
|
-
*
|
|
676
|
-
* ed.hashes.sha512 = sha512;
|
|
677
|
-
* const secretKey = ed.utils.randomSecretKey();
|
|
678
|
-
* const signature = ed.sign(new Uint8Array([1, 2, 3]), secretKey);
|
|
679
|
-
* ```
|
|
680
|
-
*/
|
|
681
|
-
const sign = (message: TArg<Uint8Array>, secretKey: TArg<Uint8Array>): TRet<Uint8Array> => {
|
|
682
|
-
const m = snapshotBytes(message, 'message');
|
|
683
|
-
const e = getExtendedPublicKey(secretKey);
|
|
684
|
-
// r = SHA512(dom2(F, C) || prefix || PH(M)); then generate R, k, S and the signature.
|
|
685
|
-
return hashFinishSync(_sign(e, callHash('sha512', e.prefix, m), m));
|
|
686
|
-
};
|
|
687
|
-
/**
|
|
688
|
-
* Verification options. zip215: true (default) follows ZIP215 spec. false would follow RFC8032.
|
|
689
|
-
*
|
|
690
|
-
* Any message with pubkey from `ED25519_TORSION_SUBGROUP` would be valid in sigs under ZIP215.
|
|
691
|
-
*/
|
|
692
|
-
export type EdDSAVerifyOpts = {
|
|
693
|
-
/** Whether to use ZIP215 verification semantics instead of the library's stricter branch. */
|
|
694
|
-
zip215?: boolean;
|
|
695
|
-
};
|
|
696
|
-
// Exported defaults favor ZIP-215 interoperability semantics; callers must opt into the stricter
|
|
697
|
-
// branch with `{ zip215: false }`.
|
|
698
|
-
// Preserves the exported ZIP-215 default for `{}` / `{ zip215: undefined }`, not just omitted opts.
|
|
699
|
-
const getZip215 = (options: TArg<EdDSAVerifyOpts>): boolean => {
|
|
700
|
-
if (options === null || typeof options !== 'object')
|
|
701
|
-
throw new TypeError('expected valid options object');
|
|
702
|
-
return options.zip215 ?? true;
|
|
703
|
-
};
|
|
704
|
-
const _verify = (
|
|
705
|
-
sig: Uint8Array,
|
|
706
|
-
msg: Uint8Array,
|
|
707
|
-
publicKey: Uint8Array,
|
|
708
|
-
options: TArg<EdDSAVerifyOpts>
|
|
709
|
-
): Finishable<boolean> => {
|
|
710
|
-
sig = abytes(sig, 64, 'signature'); // Signature hex str/Bytes, must be 64 bytes
|
|
711
|
-
msg = abytes(msg, undefined, 'message'); // Message hex str/Bytes
|
|
712
|
-
publicKey = abytes(publicKey, LEN, 'publicKey');
|
|
713
|
-
const zip215 = getZip215(options);
|
|
714
|
-
// zip215=false keeps the library's stricter branch, which still canonicalizes `R` / `A` before
|
|
715
|
-
// hashing and rejects small-order public keys earlier than pure RFC8032 text would require.
|
|
716
|
-
const r = sig.subarray(0, LEN);
|
|
717
|
-
const s = bytesToNumberLE(sig.subarray(LEN, 64)); // Decode second half as an integer S;
|
|
718
|
-
let A: Point, R: Point, SB: Point;
|
|
719
|
-
let hashable: Uint8Array = Uint8Array.of();
|
|
720
|
-
let finished = false;
|
|
721
|
-
try {
|
|
722
|
-
// zip215=true is good for consensus-critical apps. =false follows RFC8032 / NIST186-5.
|
|
723
|
-
// zip215=true: 0 <= y < MASK (2^256 for ed25519)
|
|
724
|
-
// zip215=false: 0 <= y < P (2^255-19 for ed25519)
|
|
725
|
-
A = Point.fromBytes(publicKey, zip215);
|
|
726
|
-
R = Point.fromBytes(r, zip215);
|
|
727
|
-
SB = G.multiply(s, false); // 0 <= s < l is done inside
|
|
728
|
-
// ZIP-215 accepts noncanonical / unreduced point encodings, so the challenge hash must use the
|
|
729
|
-
// exact signature/public-key bytes rather than canonicalized re-encodings of the decoded points.
|
|
730
|
-
hashable = concatBytes(r, publicKey, msg); // dom2(F, C) || R || A || PH(M)
|
|
731
|
-
finished = true;
|
|
732
|
-
} catch (error) {}
|
|
733
|
-
const finish = (hashed: Uint8Array): boolean => {
|
|
734
|
-
if (!finished) return false;
|
|
735
|
-
// Policy: strict mode intentionally rejects all small-order public keys, even though the raw RFC
|
|
736
|
-
// equation text is looser here. This matches libsodium and avoids weak / ambiguous verification
|
|
737
|
-
// outcomes where unusual low-order public keys can make distinct key/signature combinations verify.
|
|
738
|
-
if (!zip215 && A.isSmallOrder()) return false;
|
|
739
|
-
|
|
740
|
-
// k = SHA512(dom2(F, C) || R || A || PH(M))
|
|
741
|
-
const k = modL_LE(hashed);
|
|
742
|
-
const RkA = R.add(A.multiply(k, false));
|
|
743
|
-
// Extended group equation
|
|
744
|
-
// [8][S]B = [8]R + [8][k]A'
|
|
745
|
-
return RkA.subtract(SB).clearCofactor().is0();
|
|
746
|
-
};
|
|
747
|
-
return [hashable, finish];
|
|
748
|
-
};
|
|
749
|
-
|
|
750
|
-
/**
|
|
751
|
-
* Verifies a signature on message and public key. Async.
|
|
752
|
-
* The implementation is based on RFC8032 5.1.7, but default opts use ZIP-215 semantics; pass
|
|
753
|
-
* `{ zip215: false }` for the library's stricter branch.
|
|
754
|
-
* @param signature - 64-byte signature.
|
|
755
|
-
* @param message - Signed message bytes.
|
|
756
|
-
* @param publicKey - 32-byte public key.
|
|
757
|
-
* @param opts - Verification options. Defaults to ZIP-215 semantics. See {@link EdDSAVerifyOpts}.
|
|
758
|
-
* @returns `true` when the signature is valid.
|
|
759
|
-
* @throws On wrong argument types. {@link TypeError}
|
|
760
|
-
* @throws On wrong argument ranges or values. {@link RangeError}
|
|
761
|
-
* @example
|
|
762
|
-
* Verify the signature against the same message and derived public key.
|
|
763
|
-
*
|
|
764
|
-
* ```ts
|
|
765
|
-
* import * as ed from '@noble/ed25519';
|
|
766
|
-
*
|
|
767
|
-
* const secretKey = ed.utils.randomSecretKey();
|
|
768
|
-
* const message = new Uint8Array([1, 2, 3]);
|
|
769
|
-
* const publicKey = await ed.getPublicKeyAsync(secretKey);
|
|
770
|
-
* const signature = await ed.signAsync(message, secretKey);
|
|
771
|
-
* const isValid = await ed.verifyAsync(signature, message, publicKey);
|
|
772
|
-
* ```
|
|
773
|
-
*/
|
|
774
|
-
const verifyAsync = async (
|
|
775
|
-
signature: TArg<Uint8Array>,
|
|
776
|
-
message: TArg<Uint8Array>,
|
|
777
|
-
publicKey: TArg<Uint8Array>,
|
|
778
|
-
opts: TArg<EdDSAVerifyOpts> = {}
|
|
779
|
-
): Promise<boolean> => hashFinishAsync(_verify(signature, message, publicKey, opts));
|
|
780
|
-
/**
|
|
781
|
-
* Verifies a signature on message and public key using the synchronous hash path.
|
|
782
|
-
* The implementation is based on RFC8032 5.1.7, but default opts use ZIP-215 semantics; pass
|
|
783
|
-
* `{ zip215: false }` for the library's stricter branch.
|
|
784
|
-
* @param signature - 64-byte signature.
|
|
785
|
-
* @param message - Signed message bytes.
|
|
786
|
-
* @param publicKey - 32-byte public key.
|
|
787
|
-
* @param opts - Verification options. Defaults to ZIP-215 semantics. See {@link EdDSAVerifyOpts}.
|
|
788
|
-
* @returns `true` when the signature is valid.
|
|
789
|
-
* @throws If synchronous SHA-512 has not been configured in `hashes`. {@link Error}
|
|
790
|
-
* @throws On wrong argument types. {@link TypeError}
|
|
791
|
-
* @throws On wrong argument ranges or values. {@link RangeError}
|
|
792
|
-
* @example
|
|
793
|
-
* Verify a signature entirely through the synchronous API.
|
|
794
|
-
*
|
|
795
|
-
* ```ts
|
|
796
|
-
* import * as ed from '@noble/ed25519';
|
|
797
|
-
* import { sha512 } from '@noble/hashes/sha2.js';
|
|
798
|
-
*
|
|
799
|
-
* ed.hashes.sha512 = sha512;
|
|
800
|
-
* const secretKey = ed.utils.randomSecretKey();
|
|
801
|
-
* const message = new Uint8Array([1, 2, 3]);
|
|
802
|
-
* const publicKey = ed.getPublicKey(secretKey);
|
|
803
|
-
* const signature = ed.sign(message, secretKey);
|
|
804
|
-
* const isValid = ed.verify(signature, message, publicKey);
|
|
805
|
-
* ```
|
|
806
|
-
*/
|
|
807
|
-
const verify = (
|
|
808
|
-
signature: TArg<Uint8Array>,
|
|
809
|
-
message: TArg<Uint8Array>,
|
|
810
|
-
publicKey: TArg<Uint8Array>,
|
|
811
|
-
opts: TArg<EdDSAVerifyOpts> = {}
|
|
812
|
-
): boolean => hashFinishSync(_verify(signature, message, publicKey, opts));
|
|
813
|
-
|
|
814
|
-
/**
|
|
815
|
-
* Math, hex, byte helpers. Not in `utils` because utils share API with noble-curves.
|
|
816
|
-
* Exposes the same low-level field-default `mod` reducer and non-CT `invert` helper used
|
|
817
|
-
* internally.
|
|
818
|
-
* @example
|
|
819
|
-
* Convert bytes to a hex string with the low-level helper namespace.
|
|
820
|
-
*
|
|
821
|
-
* ```ts
|
|
822
|
-
* const hex = etc.bytesToHex(new Uint8Array([1, 2, 3]));
|
|
823
|
-
* ```
|
|
824
|
-
*/
|
|
825
|
-
const etc: {
|
|
826
|
-
bytesToHex: (bytes: TArg<Uint8Array>) => string;
|
|
827
|
-
hexToBytes: (hex: string) => TRet<Uint8Array>;
|
|
828
|
-
concatBytes: (...arrs: TArg<Uint8Array[]>) => TRet<Uint8Array>;
|
|
829
|
-
mod: (a: bigint, md?: bigint) => bigint;
|
|
830
|
-
invert: typeof invert;
|
|
831
|
-
randomBytes: (len?: number) => TRet<Uint8Array>;
|
|
832
|
-
} = /* @__PURE__ */ freeze({
|
|
833
|
-
bytesToHex,
|
|
834
|
-
hexToBytes,
|
|
835
|
-
concatBytes,
|
|
836
|
-
mod,
|
|
837
|
-
invert,
|
|
838
|
-
randomBytes,
|
|
839
|
-
});
|
|
840
|
-
/**
|
|
841
|
-
* Hash implementations used by the synchronous API plus the default async WebCrypto provider.
|
|
842
|
-
* Both slots are configurable API surface; wrapper helpers revalidate that providers still return
|
|
843
|
-
* 64-byte SHA-512 digests.
|
|
844
|
-
* @example
|
|
845
|
-
* Provide a SHA-512 implementation before calling synchronous helpers.
|
|
846
|
-
*
|
|
847
|
-
* ```ts
|
|
848
|
-
* import * as ed from '@noble/ed25519';
|
|
849
|
-
* import { sha512 } from '@noble/hashes/sha2.js';
|
|
850
|
-
*
|
|
851
|
-
* ed.hashes.sha512 = sha512;
|
|
852
|
-
* const { publicKey } = ed.keygen();
|
|
853
|
-
* ```
|
|
854
|
-
*/
|
|
855
|
-
const hashes = {
|
|
856
|
-
sha512Async: async (message: TArg<Uint8Array>): Promise<TRet<Uint8Array>> => {
|
|
857
|
-
const s = globalThis?.crypto?.subtle;
|
|
858
|
-
if (!s) throw new Error('crypto.subtle must be defined, consider polyfill');
|
|
859
|
-
return new Uint8Array(await s.digest('SHA-512', concatBytes(message))) as TRet<Uint8Array>;
|
|
860
|
-
},
|
|
861
|
-
sha512: undefined as undefined | ((message: TArg<Uint8Array>) => TRet<Uint8Array>),
|
|
862
|
-
};
|
|
863
|
-
|
|
864
|
-
// Returns the final 32-byte Ed25519 secret-key seed verbatim, generating fresh random bytes only
|
|
865
|
-
// when omitted.
|
|
866
|
-
const randomSecretKey = (seed?: TArg<Uint8Array>): TRet<Uint8Array> => {
|
|
867
|
-
return abytes(seed === undefined ? randomBytes() : seed, LEN, 'seed');
|
|
868
|
-
};
|
|
869
|
-
|
|
870
|
-
type KeysSecPub = { secretKey: Uint8Array; publicKey: Uint8Array };
|
|
871
|
-
/**
|
|
872
|
-
* Generates a secret/public keypair.
|
|
873
|
-
* @param seed - Optional 32-byte Ed25519 secret-key seed, returned verbatim as `secretKey`.
|
|
874
|
-
* @returns Keypair with `secretKey` and `publicKey`.
|
|
875
|
-
* @throws If synchronous SHA-512 has not been configured in `hashes`. {@link Error}
|
|
876
|
-
* @throws On wrong argument types. {@link TypeError}
|
|
877
|
-
* @throws On wrong argument ranges or values. {@link RangeError}
|
|
878
|
-
* @example
|
|
879
|
-
* Generate a new keypair through the synchronous API after wiring SHA-512.
|
|
880
|
-
*
|
|
881
|
-
* ```ts
|
|
882
|
-
* import * as ed from '@noble/ed25519';
|
|
883
|
-
* import { sha512 } from '@noble/hashes/sha2.js';
|
|
884
|
-
*
|
|
885
|
-
* ed.hashes.sha512 = sha512;
|
|
886
|
-
* const { secretKey, publicKey } = ed.keygen();
|
|
887
|
-
* ```
|
|
888
|
-
*/
|
|
889
|
-
const keygen = (seed?: TArg<Uint8Array>): TRet<KeysSecPub> => {
|
|
890
|
-
const secretKey = randomSecretKey(seed);
|
|
891
|
-
const publicKey = getPublicKey(secretKey);
|
|
892
|
-
return { secretKey, publicKey } as TRet<KeysSecPub>;
|
|
893
|
-
};
|
|
894
|
-
/**
|
|
895
|
-
* Generates a secret/public keypair asynchronously.
|
|
896
|
-
* @param seed - Optional 32-byte Ed25519 secret-key seed, returned verbatim as `secretKey`.
|
|
897
|
-
* @returns Keypair with `secretKey` and `publicKey`.
|
|
898
|
-
* @throws On wrong argument types. {@link TypeError}
|
|
899
|
-
* @throws On wrong argument ranges or values. {@link RangeError}
|
|
900
|
-
* @example
|
|
901
|
-
* Generate a new keypair through the asynchronous WebCrypto-backed path.
|
|
902
|
-
*
|
|
903
|
-
* ```ts
|
|
904
|
-
* import * as ed from '@noble/ed25519';
|
|
905
|
-
*
|
|
906
|
-
* const { secretKey, publicKey } = await ed.keygenAsync();
|
|
907
|
-
* ```
|
|
908
|
-
*/
|
|
909
|
-
const keygenAsync = async (seed?: TArg<Uint8Array>): Promise<TRet<KeysSecPub>> => {
|
|
910
|
-
const secretKey = randomSecretKey(seed);
|
|
911
|
-
const publicKey = await getPublicKeyAsync(secretKey);
|
|
912
|
-
return { secretKey, publicKey } as TRet<KeysSecPub>;
|
|
913
|
-
};
|
|
914
|
-
|
|
915
|
-
/**
|
|
916
|
-
* Ed25519-specific key utilities.
|
|
917
|
-
* `utils.getExtendedPublicKey*` expose secret-derived internals (`head`, `prefix`, `scalar`, and
|
|
918
|
-
* point objects), not just public-key bytes.
|
|
919
|
-
* @example
|
|
920
|
-
* Generate a new Ed25519 secret key and derive the matching public key.
|
|
921
|
-
*
|
|
922
|
-
* ```ts
|
|
923
|
-
* import * as ed from '@noble/ed25519';
|
|
924
|
-
*
|
|
925
|
-
* const secretKey = ed.utils.randomSecretKey();
|
|
926
|
-
* const publicKey = await ed.getPublicKeyAsync(secretKey);
|
|
927
|
-
* ```
|
|
928
|
-
*/
|
|
929
|
-
const utils: {
|
|
930
|
-
getExtendedPublicKeyAsync: typeof getExtendedPublicKeyAsync;
|
|
931
|
-
getExtendedPublicKey: typeof getExtendedPublicKey;
|
|
932
|
-
randomSecretKey: typeof randomSecretKey;
|
|
933
|
-
} = /* @__PURE__ */ freeze({
|
|
934
|
-
getExtendedPublicKeyAsync,
|
|
935
|
-
getExtendedPublicKey,
|
|
936
|
-
randomSecretKey,
|
|
937
|
-
});
|
|
938
|
-
|
|
939
|
-
// ## Precomputes
|
|
940
|
-
// --------------
|
|
941
|
-
|
|
942
|
-
// Fixed W=8 window: 33 windows (ceil(256/8) + 1, NOT 32 - see wNAF loop), 128 points per window.
|
|
943
|
-
// Layout is grouped by window: each block stores the positive multiples `1*base .. 128*base` for
|
|
944
|
-
// that window, and the extra `+1` window absorbs carries from signed-digit recoding.
|
|
945
|
-
const precompute = () => {
|
|
946
|
-
const points: Point[] = [];
|
|
947
|
-
let p = G;
|
|
948
|
-
let b: Point;
|
|
949
|
-
for (let w = 0; w < 33; w++) {
|
|
950
|
-
b = p;
|
|
951
|
-
points.push(b);
|
|
952
|
-
for (let i = 1; i < 128; i++) {
|
|
953
|
-
b = b.add(p);
|
|
954
|
-
points.push(b);
|
|
955
|
-
} // i=1, bc we skip 0
|
|
956
|
-
p = b.double();
|
|
957
|
-
}
|
|
958
|
-
return points;
|
|
959
|
-
};
|
|
960
|
-
let Gpows: Point[] | undefined = undefined; // shared process-wide cache of base-point precomputes
|
|
961
|
-
// Branch-based negate helper used for JS/JIT mitigation symmetry, not a strict constant-time claim.
|
|
962
|
-
const ctneg = (cnd: boolean, p: Point): Point => {
|
|
963
|
-
const n = p.negate();
|
|
964
|
-
return cnd ? n : p;
|
|
965
|
-
};
|
|
966
|
-
|
|
967
|
-
/**
|
|
968
|
-
* Precomputes give 12x faster getPublicKey(), 10x sign(), 2x verify() by
|
|
969
|
-
* caching multiples of G (base point). Cache is stored in 32MB of RAM.
|
|
970
|
-
* Any time `G.multiply` is done, precomputes are used.
|
|
971
|
-
* Not used for getSharedSecret, which instead multiplies random pubkey `P.multiply`.
|
|
972
|
-
*
|
|
973
|
-
* w-ary non-adjacent form (wNAF) precomputation method is 10% slower than windowed method,
|
|
974
|
-
* but takes 2x less RAM. RAM reduction is possible by utilizing `.subtract`.
|
|
975
|
-
* Returns the real accumulator `p` plus a fake accumulator `f`; callers only care about `p`, while
|
|
976
|
-
* `f` exists to keep similar work in zero-digit branches as a JS/JIT side-channel mitigation.
|
|
977
|
-
*
|
|
978
|
-
* !! Precomputes can be disabled by commenting-out call of the wNAF() inside Point#multiply().
|
|
979
|
-
*/
|
|
980
|
-
const wNAF = (n: bigint): { p: Point; f: Point } => {
|
|
981
|
-
const comp = Gpows || (Gpows = precompute());
|
|
982
|
-
let p = I;
|
|
983
|
-
let f = G; // f must be G, or could become I in the end
|
|
984
|
-
for (let w = 0; w < 33; w++) {
|
|
985
|
-
let wbits = Number(n & 255n); // extract W=8 bits.
|
|
986
|
-
n >>= 8n; // shift number by W=8 bits.
|
|
987
|
-
// We use negative indexes to reduce size of precomputed table by 2x.
|
|
988
|
-
// Instead of needing precomputes 0..256, we only calculate them for 0..128.
|
|
989
|
-
// If an index > 128 is found, we do (256-index) - where 256 is next window.
|
|
990
|
-
// Naive: index +127 => 127, +224 => 224
|
|
991
|
-
// Optimized: index +127 => 127, +224 => 256-32
|
|
992
|
-
if (wbits > 128) {
|
|
993
|
-
wbits -= 256;
|
|
994
|
-
n += 1n;
|
|
995
|
-
}
|
|
996
|
-
const off = w * 128; // offset of this window's block; also the fake-add index
|
|
997
|
-
const offP = off + Math.abs(wbits) - 1; // real-add index; both offsets always evaluated
|
|
998
|
-
const isOddW = w % 2 !== 0; // conditions, evaluate both; alternates fake-add sign per window
|
|
999
|
-
const isNeg = wbits < 0;
|
|
1000
|
-
if (wbits === 0) {
|
|
1001
|
-
// wbits == 0 means the real index would be I: can't add it. Add window offset `off` instead.
|
|
1002
|
-
f = f.add(ctneg(isOddW, comp[off])); // bits are 0: add garbage to fake point
|
|
1003
|
-
} else {
|
|
1004
|
-
p = p.add(ctneg(isNeg, comp[offP])); // bits are 1: add to result point
|
|
1005
|
-
}
|
|
1006
|
-
}
|
|
1007
|
-
if (n !== 0n) throw new Error('invalid wnaf');
|
|
1008
|
-
return { p, f }; // return both real and fake points for JIT/leakage-shape symmetry
|
|
1009
|
-
};
|
|
1010
|
-
|
|
1011
|
-
// !! Remove the export to easily use in REPL / browser console
|
|
1012
|
-
export {
|
|
1013
|
-
etc,
|
|
1014
|
-
getPublicKey,
|
|
1015
|
-
getPublicKeyAsync,
|
|
1016
|
-
hash,
|
|
1017
|
-
hashes,
|
|
1018
|
-
keygen,
|
|
1019
|
-
keygenAsync,
|
|
1020
|
-
Point,
|
|
1021
|
-
sign,
|
|
1022
|
-
signAsync,
|
|
1023
|
-
utils,
|
|
1024
|
-
verify,
|
|
1025
|
-
verifyAsync,
|
|
1026
|
-
};
|
|
1027
|
-
|
|
1028
|
-
// ## TypeScript Uint8Array compat types
|
|
1029
|
-
// -------------------------------------
|
|
1030
|
-
/**
|
|
1031
|
-
* Bytes API type helpers for old + new TypeScript.
|
|
1032
|
-
*
|
|
1033
|
-
* TS 5.6 has `Uint8Array`, while TS 5.9+ made it generic `Uint8Array<ArrayBuffer>`.
|
|
1034
|
-
* We can't use specific return type, because TS 5.6 will error.
|
|
1035
|
-
* We can't use generic return type, because most TS 5.9 software will expect specific type.
|
|
1036
|
-
*
|
|
1037
|
-
* Maps typed-array input leaves to broad forms.
|
|
1038
|
-
* These are compatibility adapters, not ownership guarantees.
|
|
1039
|
-
*
|
|
1040
|
-
* - `TArg` keeps byte inputs broad.
|
|
1041
|
-
* - `TRet` marks byte outputs for TS 5.6 and TS 5.9+ compatibility.
|
|
1042
|
-
*/
|
|
1043
|
-
export type TypedArg<T> = T extends BigInt64Array
|
|
1044
|
-
? BigInt64Array
|
|
1045
|
-
: T extends BigUint64Array
|
|
1046
|
-
? BigUint64Array
|
|
1047
|
-
: T extends Float32Array
|
|
1048
|
-
? Float32Array
|
|
1049
|
-
: T extends Float64Array
|
|
1050
|
-
? Float64Array
|
|
1051
|
-
: T extends Int16Array
|
|
1052
|
-
? Int16Array
|
|
1053
|
-
: T extends Int32Array
|
|
1054
|
-
? Int32Array
|
|
1055
|
-
: T extends Int8Array
|
|
1056
|
-
? Int8Array
|
|
1057
|
-
: T extends Uint16Array
|
|
1058
|
-
? Uint16Array
|
|
1059
|
-
: T extends Uint32Array
|
|
1060
|
-
? Uint32Array
|
|
1061
|
-
: T extends Uint8ClampedArray
|
|
1062
|
-
? Uint8ClampedArray
|
|
1063
|
-
: T extends Uint8Array
|
|
1064
|
-
? Uint8Array
|
|
1065
|
-
: never;
|
|
1066
|
-
/** Maps typed-array output leaves to narrow TS-compatible forms. */
|
|
1067
|
-
export type TypedRet<T> = T extends BigInt64Array
|
|
1068
|
-
? ReturnType<typeof BigInt64Array.of>
|
|
1069
|
-
: T extends BigUint64Array
|
|
1070
|
-
? ReturnType<typeof BigUint64Array.of>
|
|
1071
|
-
: T extends Float32Array
|
|
1072
|
-
? ReturnType<typeof Float32Array.of>
|
|
1073
|
-
: T extends Float64Array
|
|
1074
|
-
? ReturnType<typeof Float64Array.of>
|
|
1075
|
-
: T extends Int16Array
|
|
1076
|
-
? ReturnType<typeof Int16Array.of>
|
|
1077
|
-
: T extends Int32Array
|
|
1078
|
-
? ReturnType<typeof Int32Array.of>
|
|
1079
|
-
: T extends Int8Array
|
|
1080
|
-
? ReturnType<typeof Int8Array.of>
|
|
1081
|
-
: T extends Uint16Array
|
|
1082
|
-
? ReturnType<typeof Uint16Array.of>
|
|
1083
|
-
: T extends Uint32Array
|
|
1084
|
-
? ReturnType<typeof Uint32Array.of>
|
|
1085
|
-
: T extends Uint8ClampedArray
|
|
1086
|
-
? ReturnType<typeof Uint8ClampedArray.of>
|
|
1087
|
-
: T extends Uint8Array
|
|
1088
|
-
? ReturnType<typeof Uint8Array.of>
|
|
1089
|
-
: never;
|
|
1090
|
-
/** Recursively adapts byte-carrying API input types. See {@link TypedArg}. */
|
|
1091
|
-
export type TArg<T> =
|
|
1092
|
-
| T
|
|
1093
|
-
| ([TypedArg<T>] extends [never]
|
|
1094
|
-
? T extends (...args: infer A) => infer R
|
|
1095
|
-
? ((...args: { [K in keyof A]: TRet<A[K]> }) => TArg<R>) & {
|
|
1096
|
-
[K in keyof T]: T[K] extends (...args: any) => any ? T[K] : TArg<T[K]>;
|
|
1097
|
-
}
|
|
1098
|
-
: T extends [infer A, ...infer R]
|
|
1099
|
-
? [TArg<A>, ...{ [K in keyof R]: TArg<R[K]> }]
|
|
1100
|
-
: T extends readonly [infer A, ...infer R]
|
|
1101
|
-
? readonly [TArg<A>, ...{ [K in keyof R]: TArg<R[K]> }]
|
|
1102
|
-
: T extends (infer A)[]
|
|
1103
|
-
? TArg<A>[]
|
|
1104
|
-
: T extends readonly (infer A)[]
|
|
1105
|
-
? readonly TArg<A>[]
|
|
1106
|
-
: T extends Promise<infer A>
|
|
1107
|
-
? Promise<TArg<A>>
|
|
1108
|
-
: T extends object
|
|
1109
|
-
? { [K in keyof T]: TArg<T[K]> }
|
|
1110
|
-
: T
|
|
1111
|
-
: TypedArg<T>);
|
|
1112
|
-
/** Recursively adapts byte-carrying API output types. See {@link TypedArg}. */
|
|
1113
|
-
export type TRet<T> = T extends unknown
|
|
1114
|
-
? T &
|
|
1115
|
-
([TypedRet<T>] extends [never]
|
|
1116
|
-
? T extends (...args: infer A) => infer R
|
|
1117
|
-
? ((...args: { [K in keyof A]: TArg<A[K]> }) => TRet<R>) & {
|
|
1118
|
-
[K in keyof T]: T[K] extends (...args: any) => any ? T[K] : TRet<T[K]>;
|
|
1119
|
-
}
|
|
1120
|
-
: T extends [infer A, ...infer R]
|
|
1121
|
-
? [TRet<A>, ...{ [K in keyof R]: TRet<R[K]> }]
|
|
1122
|
-
: T extends readonly [infer A, ...infer R]
|
|
1123
|
-
? readonly [TRet<A>, ...{ [K in keyof R]: TRet<R[K]> }]
|
|
1124
|
-
: T extends (infer A)[]
|
|
1125
|
-
? TRet<A>[]
|
|
1126
|
-
: T extends readonly (infer A)[]
|
|
1127
|
-
? readonly TRet<A>[]
|
|
1128
|
-
: T extends Promise<infer A>
|
|
1129
|
-
? Promise<TRet<A>>
|
|
1130
|
-
: T extends object
|
|
1131
|
-
? { [K in keyof T]: TRet<T[K]> }
|
|
1132
|
-
: T
|
|
1133
|
-
: TypedRet<T>)
|
|
1134
|
-
: never;
|