@newtype-ai/nit 0.4.7 → 0.4.9
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/README.md +97 -46
- package/dist/chunk-Q5GX7ZXR.js +3842 -0
- package/dist/cli.js +86 -2
- package/dist/index.d.ts +78 -1
- package/dist/index.js +13 -1
- package/package.json +2 -1
- package/scripts/postinstall.js +8 -1
- package/dist/chunk-535YI4CD.js +0 -1599
|
@@ -0,0 +1,3842 @@
|
|
|
1
|
+
// nit — version control for agent cards
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { promises as fs7, statSync } from "fs";
|
|
5
|
+
import { join as join7, basename as basename2, dirname as dirname2, resolve as resolve2 } from "path";
|
|
6
|
+
|
|
7
|
+
// src/objects.ts
|
|
8
|
+
import { createHash } from "crypto";
|
|
9
|
+
import { promises as fs } from "fs";
|
|
10
|
+
import { join } from "path";
|
|
11
|
+
function hashObject(type, content) {
|
|
12
|
+
const buf = Buffer.from(content, "utf-8");
|
|
13
|
+
const header = `${type} ${buf.byteLength}\0`;
|
|
14
|
+
const hash = createHash("sha256");
|
|
15
|
+
hash.update(header);
|
|
16
|
+
hash.update(buf);
|
|
17
|
+
return hash.digest("hex");
|
|
18
|
+
}
|
|
19
|
+
async function writeObject(nitDir, type, content) {
|
|
20
|
+
const hex = hashObject(type, content);
|
|
21
|
+
const dir = join(nitDir, "objects", hex.slice(0, 2));
|
|
22
|
+
const file = join(dir, hex.slice(2));
|
|
23
|
+
try {
|
|
24
|
+
await fs.access(file);
|
|
25
|
+
return hex;
|
|
26
|
+
} catch {
|
|
27
|
+
}
|
|
28
|
+
await fs.mkdir(dir, { recursive: true });
|
|
29
|
+
await fs.writeFile(file, content, "utf-8");
|
|
30
|
+
return hex;
|
|
31
|
+
}
|
|
32
|
+
async function readObject(nitDir, hash) {
|
|
33
|
+
const file = join(nitDir, "objects", hash.slice(0, 2), hash.slice(2));
|
|
34
|
+
try {
|
|
35
|
+
return await fs.readFile(file, "utf-8");
|
|
36
|
+
} catch {
|
|
37
|
+
throw new Error(`Object not found: ${hash}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function serializeCommit(commit2) {
|
|
41
|
+
const lines = [];
|
|
42
|
+
lines.push(`card ${commit2.card}`);
|
|
43
|
+
if (commit2.parent !== null) {
|
|
44
|
+
lines.push(`parent ${commit2.parent}`);
|
|
45
|
+
}
|
|
46
|
+
lines.push(`author ${commit2.author} ${commit2.timestamp}`);
|
|
47
|
+
lines.push("");
|
|
48
|
+
lines.push(commit2.message);
|
|
49
|
+
return lines.join("\n");
|
|
50
|
+
}
|
|
51
|
+
function parseCommit(hash, raw) {
|
|
52
|
+
const lines = raw.split("\n");
|
|
53
|
+
let card = "";
|
|
54
|
+
let parent = null;
|
|
55
|
+
let author = "";
|
|
56
|
+
let timestamp = 0;
|
|
57
|
+
let messageStart = -1;
|
|
58
|
+
for (let i = 0; i < lines.length; i++) {
|
|
59
|
+
const line = lines[i];
|
|
60
|
+
if (line === "") {
|
|
61
|
+
messageStart = i + 1;
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
if (line.startsWith("card ")) {
|
|
65
|
+
card = line.slice(5);
|
|
66
|
+
} else if (line.startsWith("parent ")) {
|
|
67
|
+
parent = line.slice(7);
|
|
68
|
+
} else if (line.startsWith("author ")) {
|
|
69
|
+
const authorPart = line.slice(7);
|
|
70
|
+
const lastSpace = authorPart.lastIndexOf(" ");
|
|
71
|
+
author = authorPart.slice(0, lastSpace);
|
|
72
|
+
timestamp = parseInt(authorPart.slice(lastSpace + 1), 10);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (!card) {
|
|
76
|
+
throw new Error(`Malformed commit object ${hash}: missing card hash`);
|
|
77
|
+
}
|
|
78
|
+
const message = messageStart >= 0 ? lines.slice(messageStart).join("\n") : "";
|
|
79
|
+
return {
|
|
80
|
+
type: "commit",
|
|
81
|
+
hash,
|
|
82
|
+
card,
|
|
83
|
+
parent,
|
|
84
|
+
author,
|
|
85
|
+
timestamp,
|
|
86
|
+
message
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// src/refs.ts
|
|
91
|
+
import { promises as fs2 } from "fs";
|
|
92
|
+
import { join as join2 } from "path";
|
|
93
|
+
async function getHead(nitDir) {
|
|
94
|
+
const headPath = join2(nitDir, "HEAD");
|
|
95
|
+
const content = (await fs2.readFile(headPath, "utf-8")).trim();
|
|
96
|
+
if (!content.startsWith("ref: ")) {
|
|
97
|
+
throw new Error(
|
|
98
|
+
`HEAD is in an unexpected state: "${content}". Only symbolic refs are supported.`
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
return { type: "ref", ref: content.slice(5) };
|
|
102
|
+
}
|
|
103
|
+
async function resolveHead(nitDir) {
|
|
104
|
+
const head = await getHead(nitDir);
|
|
105
|
+
const refPath = join2(nitDir, head.ref);
|
|
106
|
+
try {
|
|
107
|
+
return (await fs2.readFile(refPath, "utf-8")).trim();
|
|
108
|
+
} catch {
|
|
109
|
+
throw new Error(
|
|
110
|
+
`Branch ref ${head.ref} does not exist. Repository may be empty.`
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
async function getCurrentBranch(nitDir) {
|
|
115
|
+
const head = await getHead(nitDir);
|
|
116
|
+
const prefix = "refs/heads/";
|
|
117
|
+
if (!head.ref.startsWith(prefix)) {
|
|
118
|
+
throw new Error(`HEAD ref has unexpected format: ${head.ref}`);
|
|
119
|
+
}
|
|
120
|
+
return head.ref.slice(prefix.length);
|
|
121
|
+
}
|
|
122
|
+
async function setBranch(nitDir, branch2, commitHash) {
|
|
123
|
+
const refPath = join2(nitDir, "refs", "heads", branch2);
|
|
124
|
+
await fs2.mkdir(join2(nitDir, "refs", "heads"), { recursive: true });
|
|
125
|
+
await fs2.writeFile(refPath, commitHash + "\n", "utf-8");
|
|
126
|
+
}
|
|
127
|
+
async function getBranch(nitDir, branch2) {
|
|
128
|
+
const refPath = join2(nitDir, "refs", "heads", branch2);
|
|
129
|
+
try {
|
|
130
|
+
return (await fs2.readFile(refPath, "utf-8")).trim();
|
|
131
|
+
} catch {
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
async function listBranches(nitDir) {
|
|
136
|
+
const headsDir = join2(nitDir, "refs", "heads");
|
|
137
|
+
const branches = [];
|
|
138
|
+
try {
|
|
139
|
+
const entries = await fs2.readdir(headsDir);
|
|
140
|
+
for (const name of entries) {
|
|
141
|
+
const refPath = join2(headsDir, name);
|
|
142
|
+
const stat = await fs2.stat(refPath);
|
|
143
|
+
if (stat.isFile()) {
|
|
144
|
+
const commitHash = (await fs2.readFile(refPath, "utf-8")).trim();
|
|
145
|
+
branches.push({ name, commitHash });
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
} catch {
|
|
149
|
+
}
|
|
150
|
+
return branches.sort((a, b) => a.name.localeCompare(b.name));
|
|
151
|
+
}
|
|
152
|
+
async function setHead(nitDir, branch2) {
|
|
153
|
+
const headPath = join2(nitDir, "HEAD");
|
|
154
|
+
await fs2.writeFile(headPath, `ref: refs/heads/${branch2}
|
|
155
|
+
`, "utf-8");
|
|
156
|
+
}
|
|
157
|
+
async function setRemoteRef(nitDir, remote2, branch2, commitHash) {
|
|
158
|
+
const dir = join2(nitDir, "refs", "remote", remote2);
|
|
159
|
+
await fs2.mkdir(dir, { recursive: true });
|
|
160
|
+
await fs2.writeFile(join2(dir, branch2), commitHash + "\n", "utf-8");
|
|
161
|
+
}
|
|
162
|
+
async function getRemoteRef(nitDir, remote2, branch2) {
|
|
163
|
+
const refPath = join2(nitDir, "refs", "remote", remote2, branch2);
|
|
164
|
+
try {
|
|
165
|
+
return (await fs2.readFile(refPath, "utf-8")).trim();
|
|
166
|
+
} catch {
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// src/identity.ts
|
|
172
|
+
import {
|
|
173
|
+
createHash as createHash2,
|
|
174
|
+
generateKeyPairSync,
|
|
175
|
+
createPrivateKey,
|
|
176
|
+
createPublicKey,
|
|
177
|
+
sign,
|
|
178
|
+
verify
|
|
179
|
+
} from "crypto";
|
|
180
|
+
import { promises as fs3 } from "fs";
|
|
181
|
+
import { join as join3 } from "path";
|
|
182
|
+
function base64urlToBase64(b64url) {
|
|
183
|
+
let s = b64url.replace(/-/g, "+").replace(/_/g, "/");
|
|
184
|
+
while (s.length % 4 !== 0) s += "=";
|
|
185
|
+
return s;
|
|
186
|
+
}
|
|
187
|
+
function base64ToBase64url(b64) {
|
|
188
|
+
return b64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
189
|
+
}
|
|
190
|
+
async function generateKeypair(nitDir) {
|
|
191
|
+
const identityDir = join3(nitDir, "identity");
|
|
192
|
+
await fs3.mkdir(identityDir, { recursive: true });
|
|
193
|
+
const { publicKey, privateKey } = generateKeyPairSync("ed25519");
|
|
194
|
+
const pubJwk = publicKey.export({ format: "jwk" });
|
|
195
|
+
const privJwk = privateKey.export({ format: "jwk" });
|
|
196
|
+
const pubBase64 = base64urlToBase64(pubJwk.x);
|
|
197
|
+
const privBase64 = base64urlToBase64(privJwk.d);
|
|
198
|
+
const pubPath = join3(identityDir, "agent.pub");
|
|
199
|
+
const keyPath = join3(identityDir, "agent.key");
|
|
200
|
+
await fs3.writeFile(pubPath, pubBase64 + "\n", "utf-8");
|
|
201
|
+
await fs3.writeFile(keyPath, privBase64 + "\n", {
|
|
202
|
+
mode: 384,
|
|
203
|
+
encoding: "utf-8"
|
|
204
|
+
});
|
|
205
|
+
return { publicKey: pubBase64, privateKey: privBase64 };
|
|
206
|
+
}
|
|
207
|
+
async function loadPublicKey(nitDir) {
|
|
208
|
+
const pubPath = join3(nitDir, "identity", "agent.pub");
|
|
209
|
+
try {
|
|
210
|
+
return (await fs3.readFile(pubPath, "utf-8")).trim();
|
|
211
|
+
} catch {
|
|
212
|
+
throw new Error(
|
|
213
|
+
"No identity found. Run `nit init` to generate a keypair."
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
async function loadPrivateKey(nitDir) {
|
|
218
|
+
const pubBase64 = await loadPublicKey(nitDir);
|
|
219
|
+
const keyPath = join3(nitDir, "identity", "agent.key");
|
|
220
|
+
let privBase64;
|
|
221
|
+
try {
|
|
222
|
+
privBase64 = (await fs3.readFile(keyPath, "utf-8")).trim();
|
|
223
|
+
} catch {
|
|
224
|
+
throw new Error(
|
|
225
|
+
"Private key not found at .nit/identity/agent.key. Regenerate with `nit init`."
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
const xB64url = base64ToBase64url(pubBase64);
|
|
229
|
+
const dB64url = base64ToBase64url(privBase64);
|
|
230
|
+
return createPrivateKey({
|
|
231
|
+
key: { kty: "OKP", crv: "Ed25519", x: xB64url, d: dB64url },
|
|
232
|
+
format: "jwk"
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
async function loadRawKeyPair(nitDir) {
|
|
236
|
+
const pubBase64 = await loadPublicKey(nitDir);
|
|
237
|
+
const keyPath = join3(nitDir, "identity", "agent.key");
|
|
238
|
+
let privBase64;
|
|
239
|
+
try {
|
|
240
|
+
privBase64 = (await fs3.readFile(keyPath, "utf-8")).trim();
|
|
241
|
+
} catch {
|
|
242
|
+
throw new Error(
|
|
243
|
+
"Private key not found at .nit/identity/agent.key. Regenerate with `nit init`."
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
const seed = Buffer.from(privBase64, "base64");
|
|
247
|
+
const pubkey = Buffer.from(pubBase64, "base64");
|
|
248
|
+
const keypair = new Uint8Array(64);
|
|
249
|
+
keypair.set(seed, 0);
|
|
250
|
+
keypair.set(pubkey, 32);
|
|
251
|
+
return keypair;
|
|
252
|
+
}
|
|
253
|
+
function formatPublicKeyField(pubBase64) {
|
|
254
|
+
return `ed25519:${pubBase64}`;
|
|
255
|
+
}
|
|
256
|
+
function parsePublicKeyField(field) {
|
|
257
|
+
const prefix = "ed25519:";
|
|
258
|
+
if (!field.startsWith(prefix)) {
|
|
259
|
+
throw new Error(
|
|
260
|
+
`Invalid publicKey format: expected "ed25519:<base64>", got "${field}"`
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
return field.slice(prefix.length);
|
|
264
|
+
}
|
|
265
|
+
async function signChallenge(nitDir, challenge) {
|
|
266
|
+
const privateKey = await loadPrivateKey(nitDir);
|
|
267
|
+
const sig = sign(null, Buffer.from(challenge, "utf-8"), privateKey);
|
|
268
|
+
return sig.toString("base64");
|
|
269
|
+
}
|
|
270
|
+
async function signMessage(nitDir, message) {
|
|
271
|
+
const privateKey = await loadPrivateKey(nitDir);
|
|
272
|
+
const sig = sign(null, Buffer.from(message, "utf-8"), privateKey);
|
|
273
|
+
return sig.toString("base64");
|
|
274
|
+
}
|
|
275
|
+
var NIT_NAMESPACE = "801ba518-f326-47e5-97c9-d1efd1865a19";
|
|
276
|
+
function deriveAgentId(publicKeyField) {
|
|
277
|
+
return uuidv5(publicKeyField, NIT_NAMESPACE);
|
|
278
|
+
}
|
|
279
|
+
async function loadAgentId(nitDir) {
|
|
280
|
+
const idPath = join3(nitDir, "identity", "agent-id");
|
|
281
|
+
try {
|
|
282
|
+
return (await fs3.readFile(idPath, "utf-8")).trim();
|
|
283
|
+
} catch {
|
|
284
|
+
throw new Error(
|
|
285
|
+
"No agent ID found. Run `nit init` to generate identity."
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
async function saveAgentId(nitDir, agentId) {
|
|
290
|
+
const idPath = join3(nitDir, "identity", "agent-id");
|
|
291
|
+
await fs3.writeFile(idPath, agentId + "\n", "utf-8");
|
|
292
|
+
}
|
|
293
|
+
function parseUuid(uuid) {
|
|
294
|
+
const hex = uuid.replace(/-/g, "");
|
|
295
|
+
return Buffer.from(hex, "hex");
|
|
296
|
+
}
|
|
297
|
+
function formatUuid(bytes) {
|
|
298
|
+
const hex = bytes.toString("hex");
|
|
299
|
+
return [
|
|
300
|
+
hex.slice(0, 8),
|
|
301
|
+
hex.slice(8, 12),
|
|
302
|
+
hex.slice(12, 16),
|
|
303
|
+
hex.slice(16, 20),
|
|
304
|
+
hex.slice(20, 32)
|
|
305
|
+
].join("-");
|
|
306
|
+
}
|
|
307
|
+
function uuidv5(name, namespace) {
|
|
308
|
+
const namespaceBytes = parseUuid(namespace);
|
|
309
|
+
const nameBytes = Buffer.from(name, "utf-8");
|
|
310
|
+
const data = Buffer.concat([namespaceBytes, nameBytes]);
|
|
311
|
+
const hash = createHash2("sha1").update(data).digest();
|
|
312
|
+
const uuid = Buffer.from(hash.subarray(0, 16));
|
|
313
|
+
uuid[6] = uuid[6] & 15 | 80;
|
|
314
|
+
uuid[8] = uuid[8] & 63 | 128;
|
|
315
|
+
return formatUuid(uuid);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// src/skills.ts
|
|
319
|
+
import { promises as fs4 } from "fs";
|
|
320
|
+
import { join as join4, resolve } from "path";
|
|
321
|
+
import { homedir } from "os";
|
|
322
|
+
var FRAMEWORK_MARKERS = [
|
|
323
|
+
{ marker: ".claude", skillsPath: ".claude/skills" },
|
|
324
|
+
{ marker: ".cursor", skillsPath: ".cursor/skills" },
|
|
325
|
+
{ marker: ".codex", skillsPath: ".codex/skills" },
|
|
326
|
+
{ marker: ".windsurf", skillsPath: ".windsurf/skills" },
|
|
327
|
+
{ marker: ".openclaw", skillsPath: ".openclaw/workspace/skills" }
|
|
328
|
+
];
|
|
329
|
+
var GLOBAL_SKILLS_DIRS = [
|
|
330
|
+
{ marker: ".claude", skillsPath: ".claude/skills" },
|
|
331
|
+
{ marker: ".codex", skillsPath: ".codex/skills" },
|
|
332
|
+
{ marker: ".codeium", skillsPath: ".codeium/windsurf/skills" }
|
|
333
|
+
];
|
|
334
|
+
async function discoverSkillsDir(projectDir2) {
|
|
335
|
+
const absProject = resolve(projectDir2);
|
|
336
|
+
const home = homedir();
|
|
337
|
+
for (const { marker, skillsPath } of FRAMEWORK_MARKERS) {
|
|
338
|
+
const idx = absProject.indexOf(`/${marker}`);
|
|
339
|
+
if (idx !== -1) {
|
|
340
|
+
const root = absProject.slice(0, idx);
|
|
341
|
+
return join4(root, skillsPath);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
for (const { marker, skillsPath } of FRAMEWORK_MARKERS) {
|
|
345
|
+
try {
|
|
346
|
+
const stat = await fs4.stat(join4(absProject, marker));
|
|
347
|
+
if (stat.isDirectory()) {
|
|
348
|
+
return join4(absProject, skillsPath);
|
|
349
|
+
}
|
|
350
|
+
} catch {
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
for (const { marker, skillsPath } of GLOBAL_SKILLS_DIRS) {
|
|
354
|
+
try {
|
|
355
|
+
const stat = await fs4.stat(join4(home, marker));
|
|
356
|
+
if (stat.isDirectory()) {
|
|
357
|
+
return join4(home, skillsPath);
|
|
358
|
+
}
|
|
359
|
+
} catch {
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
return join4(absProject, ".agents", "skills");
|
|
363
|
+
}
|
|
364
|
+
async function createSkillTemplate(skillsDir, domain) {
|
|
365
|
+
const skillId = domain.replace(/\./g, "-");
|
|
366
|
+
const skillDir = join4(skillsDir, skillId);
|
|
367
|
+
const skillPath = join4(skillDir, "SKILL.md");
|
|
368
|
+
let localVersion;
|
|
369
|
+
try {
|
|
370
|
+
const existing = await fs4.readFile(skillPath, "utf-8");
|
|
371
|
+
localVersion = parseVersion(existing);
|
|
372
|
+
} catch {
|
|
373
|
+
}
|
|
374
|
+
let remoteContent = null;
|
|
375
|
+
let remoteVersion;
|
|
376
|
+
try {
|
|
377
|
+
const res = await fetch(`https://${domain}/skill.md`, {
|
|
378
|
+
headers: { "Accept": "text/markdown, text/plain" },
|
|
379
|
+
signal: AbortSignal.timeout(5e3)
|
|
380
|
+
});
|
|
381
|
+
if (res.ok) {
|
|
382
|
+
const text = await res.text();
|
|
383
|
+
if (text.startsWith("---")) {
|
|
384
|
+
remoteContent = text;
|
|
385
|
+
remoteVersion = parseVersion(text);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
} catch {
|
|
389
|
+
}
|
|
390
|
+
if (localVersion !== void 0) {
|
|
391
|
+
if (!remoteVersion || !isNewerVersion(remoteVersion, localVersion)) {
|
|
392
|
+
return skillId;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
await fs4.mkdir(skillDir, { recursive: true });
|
|
396
|
+
await fs4.writeFile(
|
|
397
|
+
skillPath,
|
|
398
|
+
remoteContent ?? fallbackTemplate(skillId, domain),
|
|
399
|
+
"utf-8"
|
|
400
|
+
);
|
|
401
|
+
return skillId;
|
|
402
|
+
}
|
|
403
|
+
function parseVersion(content) {
|
|
404
|
+
const fmMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
405
|
+
if (!fmMatch) return void 0;
|
|
406
|
+
const versionMatch = fmMatch[1].match(/^version:\s*(.+)$/m);
|
|
407
|
+
return versionMatch ? versionMatch[1].trim() : void 0;
|
|
408
|
+
}
|
|
409
|
+
function isNewerVersion(remote2, local) {
|
|
410
|
+
const r = remote2.split(".").map(Number);
|
|
411
|
+
const l = local.split(".").map(Number);
|
|
412
|
+
const len = Math.max(r.length, l.length);
|
|
413
|
+
for (let i = 0; i < len; i++) {
|
|
414
|
+
const rv = r[i] ?? 0;
|
|
415
|
+
const lv = l[i] ?? 0;
|
|
416
|
+
if (rv > lv) return true;
|
|
417
|
+
if (rv < lv) return false;
|
|
418
|
+
}
|
|
419
|
+
return false;
|
|
420
|
+
}
|
|
421
|
+
function fallbackTemplate(skillId, domain) {
|
|
422
|
+
return `---
|
|
423
|
+
name: ${skillId}
|
|
424
|
+
description: Skills and context for ${domain}
|
|
425
|
+
---
|
|
426
|
+
|
|
427
|
+
# ${skillId}
|
|
428
|
+
|
|
429
|
+
Configure your skills and context for ${domain} here.
|
|
430
|
+
`;
|
|
431
|
+
}
|
|
432
|
+
async function discoverSkills(projectDir2) {
|
|
433
|
+
const home = homedir();
|
|
434
|
+
const searchDirs = [
|
|
435
|
+
// Project-local (all known agent frameworks)
|
|
436
|
+
join4(projectDir2, ".claude", "skills"),
|
|
437
|
+
join4(projectDir2, ".cursor", "skills"),
|
|
438
|
+
join4(projectDir2, ".windsurf", "skills"),
|
|
439
|
+
join4(projectDir2, ".codex", "skills"),
|
|
440
|
+
join4(projectDir2, ".agents", "skills"),
|
|
441
|
+
// User-global
|
|
442
|
+
join4(home, ".claude", "skills"),
|
|
443
|
+
// Claude Code + Cursor (shared)
|
|
444
|
+
join4(home, ".codex", "skills"),
|
|
445
|
+
// Codex CLI
|
|
446
|
+
join4(home, ".codeium", "windsurf", "skills")
|
|
447
|
+
// Windsurf
|
|
448
|
+
];
|
|
449
|
+
const seen = /* @__PURE__ */ new Set();
|
|
450
|
+
const skills = [];
|
|
451
|
+
for (const searchDir of searchDirs) {
|
|
452
|
+
const found = await scanSkillDir(searchDir);
|
|
453
|
+
for (const skill of found) {
|
|
454
|
+
if (!seen.has(skill.id)) {
|
|
455
|
+
seen.add(skill.id);
|
|
456
|
+
skills.push(skill);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
return skills;
|
|
461
|
+
}
|
|
462
|
+
async function resolveSkillPointers(card, projectDir2) {
|
|
463
|
+
const discovered = await discoverSkills(projectDir2);
|
|
464
|
+
const skillMap = new Map(discovered.map((s) => [s.id, s]));
|
|
465
|
+
const resolvedSkills = card.skills.map((skill) => {
|
|
466
|
+
const meta = skillMap.get(skill.id);
|
|
467
|
+
if (!meta) return skill;
|
|
468
|
+
return {
|
|
469
|
+
...skill,
|
|
470
|
+
name: meta.name,
|
|
471
|
+
description: meta.description
|
|
472
|
+
};
|
|
473
|
+
});
|
|
474
|
+
return { ...card, skills: resolvedSkills };
|
|
475
|
+
}
|
|
476
|
+
async function scanSkillDir(dir) {
|
|
477
|
+
let entries;
|
|
478
|
+
try {
|
|
479
|
+
entries = await fs4.readdir(dir);
|
|
480
|
+
} catch {
|
|
481
|
+
return [];
|
|
482
|
+
}
|
|
483
|
+
const skills = [];
|
|
484
|
+
for (const entry of entries) {
|
|
485
|
+
const skillMdPath = join4(dir, entry, "SKILL.md");
|
|
486
|
+
try {
|
|
487
|
+
const content = await fs4.readFile(skillMdPath, "utf-8");
|
|
488
|
+
const meta = parseFrontmatter(content, entry, skillMdPath);
|
|
489
|
+
if (meta) skills.push(meta);
|
|
490
|
+
} catch {
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
return skills;
|
|
494
|
+
}
|
|
495
|
+
function parseFrontmatter(content, dirName, filePath) {
|
|
496
|
+
const fmMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
497
|
+
if (!fmMatch) return null;
|
|
498
|
+
const fmBlock = fmMatch[1];
|
|
499
|
+
const fields = {};
|
|
500
|
+
let inMetadata = false;
|
|
501
|
+
let metadataVersion;
|
|
502
|
+
for (const line of fmBlock.split("\n")) {
|
|
503
|
+
const trimmed = line.trimEnd();
|
|
504
|
+
if (trimmed === "metadata:") {
|
|
505
|
+
inMetadata = true;
|
|
506
|
+
continue;
|
|
507
|
+
}
|
|
508
|
+
if (inMetadata) {
|
|
509
|
+
const nestedMatch = trimmed.match(/^\s+(\w+):\s*(.+)$/);
|
|
510
|
+
if (nestedMatch) {
|
|
511
|
+
if (nestedMatch[1] === "version") {
|
|
512
|
+
metadataVersion = nestedMatch[2].trim();
|
|
513
|
+
}
|
|
514
|
+
continue;
|
|
515
|
+
}
|
|
516
|
+
inMetadata = false;
|
|
517
|
+
}
|
|
518
|
+
const kvMatch = trimmed.match(/^(\w+):\s*(.+)$/);
|
|
519
|
+
if (kvMatch) {
|
|
520
|
+
fields[kvMatch[1]] = kvMatch[2].trim();
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
const name = fields["name"];
|
|
524
|
+
const description = fields["description"];
|
|
525
|
+
if (!name || !description) return null;
|
|
526
|
+
return {
|
|
527
|
+
id: dirName,
|
|
528
|
+
name,
|
|
529
|
+
description,
|
|
530
|
+
version: metadataVersion,
|
|
531
|
+
path: filePath
|
|
532
|
+
};
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
// src/wallet.ts
|
|
536
|
+
import { createHmac, createECDH, sign as cryptoSign } from "crypto";
|
|
537
|
+
import { promises as fs5 } from "fs";
|
|
538
|
+
import { join as join5 } from "path";
|
|
539
|
+
|
|
540
|
+
// node_modules/@noble/hashes/_u64.js
|
|
541
|
+
var U32_MASK64 = /* @__PURE__ */ BigInt(2 ** 32 - 1);
|
|
542
|
+
var _32n = /* @__PURE__ */ BigInt(32);
|
|
543
|
+
function fromBig(n, le = false) {
|
|
544
|
+
if (le)
|
|
545
|
+
return { h: Number(n & U32_MASK64), l: Number(n >> _32n & U32_MASK64) };
|
|
546
|
+
return { h: Number(n >> _32n & U32_MASK64) | 0, l: Number(n & U32_MASK64) | 0 };
|
|
547
|
+
}
|
|
548
|
+
function split(lst, le = false) {
|
|
549
|
+
const len = lst.length;
|
|
550
|
+
let Ah = new Uint32Array(len);
|
|
551
|
+
let Al = new Uint32Array(len);
|
|
552
|
+
for (let i = 0; i < len; i++) {
|
|
553
|
+
const { h, l } = fromBig(lst[i], le);
|
|
554
|
+
[Ah[i], Al[i]] = [h, l];
|
|
555
|
+
}
|
|
556
|
+
return [Ah, Al];
|
|
557
|
+
}
|
|
558
|
+
var rotlSH = (h, l, s) => h << s | l >>> 32 - s;
|
|
559
|
+
var rotlSL = (h, l, s) => l << s | h >>> 32 - s;
|
|
560
|
+
var rotlBH = (h, l, s) => l << s - 32 | h >>> 64 - s;
|
|
561
|
+
var rotlBL = (h, l, s) => h << s - 32 | l >>> 64 - s;
|
|
562
|
+
|
|
563
|
+
// node_modules/@noble/hashes/utils.js
|
|
564
|
+
function isBytes(a) {
|
|
565
|
+
return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array";
|
|
566
|
+
}
|
|
567
|
+
function anumber(n, title = "") {
|
|
568
|
+
if (!Number.isSafeInteger(n) || n < 0) {
|
|
569
|
+
const prefix = title && `"${title}" `;
|
|
570
|
+
throw new Error(`${prefix}expected integer >= 0, got ${n}`);
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
function abytes(value, length, title = "") {
|
|
574
|
+
const bytes = isBytes(value);
|
|
575
|
+
const len = value?.length;
|
|
576
|
+
const needsLen = length !== void 0;
|
|
577
|
+
if (!bytes || needsLen && len !== length) {
|
|
578
|
+
const prefix = title && `"${title}" `;
|
|
579
|
+
const ofLen = needsLen ? ` of length ${length}` : "";
|
|
580
|
+
const got = bytes ? `length=${len}` : `type=${typeof value}`;
|
|
581
|
+
throw new Error(prefix + "expected Uint8Array" + ofLen + ", got " + got);
|
|
582
|
+
}
|
|
583
|
+
return value;
|
|
584
|
+
}
|
|
585
|
+
function ahash(h) {
|
|
586
|
+
if (typeof h !== "function" || typeof h.create !== "function")
|
|
587
|
+
throw new Error("Hash must wrapped by utils.createHasher");
|
|
588
|
+
anumber(h.outputLen);
|
|
589
|
+
anumber(h.blockLen);
|
|
590
|
+
}
|
|
591
|
+
function aexists(instance, checkFinished = true) {
|
|
592
|
+
if (instance.destroyed)
|
|
593
|
+
throw new Error("Hash instance has been destroyed");
|
|
594
|
+
if (checkFinished && instance.finished)
|
|
595
|
+
throw new Error("Hash#digest() has already been called");
|
|
596
|
+
}
|
|
597
|
+
function aoutput(out, instance) {
|
|
598
|
+
abytes(out, void 0, "digestInto() output");
|
|
599
|
+
const min = instance.outputLen;
|
|
600
|
+
if (out.length < min) {
|
|
601
|
+
throw new Error('"digestInto() output" expected to be of length >=' + min);
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
function u32(arr) {
|
|
605
|
+
return new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4));
|
|
606
|
+
}
|
|
607
|
+
function clean(...arrays) {
|
|
608
|
+
for (let i = 0; i < arrays.length; i++) {
|
|
609
|
+
arrays[i].fill(0);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
function createView(arr) {
|
|
613
|
+
return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
|
|
614
|
+
}
|
|
615
|
+
function rotr(word, shift) {
|
|
616
|
+
return word << 32 - shift | word >>> shift;
|
|
617
|
+
}
|
|
618
|
+
var isLE = /* @__PURE__ */ (() => new Uint8Array(new Uint32Array([287454020]).buffer)[0] === 68)();
|
|
619
|
+
function byteSwap(word) {
|
|
620
|
+
return word << 24 & 4278190080 | word << 8 & 16711680 | word >>> 8 & 65280 | word >>> 24 & 255;
|
|
621
|
+
}
|
|
622
|
+
function byteSwap32(arr) {
|
|
623
|
+
for (let i = 0; i < arr.length; i++) {
|
|
624
|
+
arr[i] = byteSwap(arr[i]);
|
|
625
|
+
}
|
|
626
|
+
return arr;
|
|
627
|
+
}
|
|
628
|
+
var swap32IfBE = isLE ? (u) => u : byteSwap32;
|
|
629
|
+
var hasHexBuiltin = /* @__PURE__ */ (() => (
|
|
630
|
+
// @ts-ignore
|
|
631
|
+
typeof Uint8Array.from([]).toHex === "function" && typeof Uint8Array.fromHex === "function"
|
|
632
|
+
))();
|
|
633
|
+
var hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0"));
|
|
634
|
+
function bytesToHex(bytes) {
|
|
635
|
+
abytes(bytes);
|
|
636
|
+
if (hasHexBuiltin)
|
|
637
|
+
return bytes.toHex();
|
|
638
|
+
let hex = "";
|
|
639
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
640
|
+
hex += hexes[bytes[i]];
|
|
641
|
+
}
|
|
642
|
+
return hex;
|
|
643
|
+
}
|
|
644
|
+
var asciis = { _0: 48, _9: 57, A: 65, F: 70, a: 97, f: 102 };
|
|
645
|
+
function asciiToBase16(ch) {
|
|
646
|
+
if (ch >= asciis._0 && ch <= asciis._9)
|
|
647
|
+
return ch - asciis._0;
|
|
648
|
+
if (ch >= asciis.A && ch <= asciis.F)
|
|
649
|
+
return ch - (asciis.A - 10);
|
|
650
|
+
if (ch >= asciis.a && ch <= asciis.f)
|
|
651
|
+
return ch - (asciis.a - 10);
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
654
|
+
function hexToBytes(hex) {
|
|
655
|
+
if (typeof hex !== "string")
|
|
656
|
+
throw new Error("hex string expected, got " + typeof hex);
|
|
657
|
+
if (hasHexBuiltin)
|
|
658
|
+
return Uint8Array.fromHex(hex);
|
|
659
|
+
const hl = hex.length;
|
|
660
|
+
const al = hl / 2;
|
|
661
|
+
if (hl % 2)
|
|
662
|
+
throw new Error("hex string expected, got unpadded hex of length " + hl);
|
|
663
|
+
const array = new Uint8Array(al);
|
|
664
|
+
for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) {
|
|
665
|
+
const n1 = asciiToBase16(hex.charCodeAt(hi));
|
|
666
|
+
const n2 = asciiToBase16(hex.charCodeAt(hi + 1));
|
|
667
|
+
if (n1 === void 0 || n2 === void 0) {
|
|
668
|
+
const char = hex[hi] + hex[hi + 1];
|
|
669
|
+
throw new Error('hex string expected, got non-hex character "' + char + '" at index ' + hi);
|
|
670
|
+
}
|
|
671
|
+
array[ai] = n1 * 16 + n2;
|
|
672
|
+
}
|
|
673
|
+
return array;
|
|
674
|
+
}
|
|
675
|
+
function concatBytes(...arrays) {
|
|
676
|
+
let sum = 0;
|
|
677
|
+
for (let i = 0; i < arrays.length; i++) {
|
|
678
|
+
const a = arrays[i];
|
|
679
|
+
abytes(a);
|
|
680
|
+
sum += a.length;
|
|
681
|
+
}
|
|
682
|
+
const res = new Uint8Array(sum);
|
|
683
|
+
for (let i = 0, pad = 0; i < arrays.length; i++) {
|
|
684
|
+
const a = arrays[i];
|
|
685
|
+
res.set(a, pad);
|
|
686
|
+
pad += a.length;
|
|
687
|
+
}
|
|
688
|
+
return res;
|
|
689
|
+
}
|
|
690
|
+
function createHasher(hashCons, info = {}) {
|
|
691
|
+
const hashC = (msg, opts) => hashCons(opts).update(msg).digest();
|
|
692
|
+
const tmp = hashCons(void 0);
|
|
693
|
+
hashC.outputLen = tmp.outputLen;
|
|
694
|
+
hashC.blockLen = tmp.blockLen;
|
|
695
|
+
hashC.create = (opts) => hashCons(opts);
|
|
696
|
+
Object.assign(hashC, info);
|
|
697
|
+
return Object.freeze(hashC);
|
|
698
|
+
}
|
|
699
|
+
function randomBytes(bytesLength = 32) {
|
|
700
|
+
const cr = typeof globalThis === "object" ? globalThis.crypto : null;
|
|
701
|
+
if (typeof cr?.getRandomValues !== "function")
|
|
702
|
+
throw new Error("crypto.getRandomValues must be defined");
|
|
703
|
+
return cr.getRandomValues(new Uint8Array(bytesLength));
|
|
704
|
+
}
|
|
705
|
+
var oidNist = (suffix) => ({
|
|
706
|
+
oid: Uint8Array.from([6, 9, 96, 134, 72, 1, 101, 3, 4, 2, suffix])
|
|
707
|
+
});
|
|
708
|
+
|
|
709
|
+
// node_modules/@noble/hashes/sha3.js
|
|
710
|
+
var _0n = BigInt(0);
|
|
711
|
+
var _1n = BigInt(1);
|
|
712
|
+
var _2n = BigInt(2);
|
|
713
|
+
var _7n = BigInt(7);
|
|
714
|
+
var _256n = BigInt(256);
|
|
715
|
+
var _0x71n = BigInt(113);
|
|
716
|
+
var SHA3_PI = [];
|
|
717
|
+
var SHA3_ROTL = [];
|
|
718
|
+
var _SHA3_IOTA = [];
|
|
719
|
+
for (let round = 0, R = _1n, x = 1, y = 0; round < 24; round++) {
|
|
720
|
+
[x, y] = [y, (2 * x + 3 * y) % 5];
|
|
721
|
+
SHA3_PI.push(2 * (5 * y + x));
|
|
722
|
+
SHA3_ROTL.push((round + 1) * (round + 2) / 2 % 64);
|
|
723
|
+
let t = _0n;
|
|
724
|
+
for (let j = 0; j < 7; j++) {
|
|
725
|
+
R = (R << _1n ^ (R >> _7n) * _0x71n) % _256n;
|
|
726
|
+
if (R & _2n)
|
|
727
|
+
t ^= _1n << (_1n << BigInt(j)) - _1n;
|
|
728
|
+
}
|
|
729
|
+
_SHA3_IOTA.push(t);
|
|
730
|
+
}
|
|
731
|
+
var IOTAS = split(_SHA3_IOTA, true);
|
|
732
|
+
var SHA3_IOTA_H = IOTAS[0];
|
|
733
|
+
var SHA3_IOTA_L = IOTAS[1];
|
|
734
|
+
var rotlH = (h, l, s) => s > 32 ? rotlBH(h, l, s) : rotlSH(h, l, s);
|
|
735
|
+
var rotlL = (h, l, s) => s > 32 ? rotlBL(h, l, s) : rotlSL(h, l, s);
|
|
736
|
+
function keccakP(s, rounds = 24) {
|
|
737
|
+
const B = new Uint32Array(5 * 2);
|
|
738
|
+
for (let round = 24 - rounds; round < 24; round++) {
|
|
739
|
+
for (let x = 0; x < 10; x++)
|
|
740
|
+
B[x] = s[x] ^ s[x + 10] ^ s[x + 20] ^ s[x + 30] ^ s[x + 40];
|
|
741
|
+
for (let x = 0; x < 10; x += 2) {
|
|
742
|
+
const idx1 = (x + 8) % 10;
|
|
743
|
+
const idx0 = (x + 2) % 10;
|
|
744
|
+
const B0 = B[idx0];
|
|
745
|
+
const B1 = B[idx0 + 1];
|
|
746
|
+
const Th = rotlH(B0, B1, 1) ^ B[idx1];
|
|
747
|
+
const Tl = rotlL(B0, B1, 1) ^ B[idx1 + 1];
|
|
748
|
+
for (let y = 0; y < 50; y += 10) {
|
|
749
|
+
s[x + y] ^= Th;
|
|
750
|
+
s[x + y + 1] ^= Tl;
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
let curH = s[2];
|
|
754
|
+
let curL = s[3];
|
|
755
|
+
for (let t = 0; t < 24; t++) {
|
|
756
|
+
const shift = SHA3_ROTL[t];
|
|
757
|
+
const Th = rotlH(curH, curL, shift);
|
|
758
|
+
const Tl = rotlL(curH, curL, shift);
|
|
759
|
+
const PI = SHA3_PI[t];
|
|
760
|
+
curH = s[PI];
|
|
761
|
+
curL = s[PI + 1];
|
|
762
|
+
s[PI] = Th;
|
|
763
|
+
s[PI + 1] = Tl;
|
|
764
|
+
}
|
|
765
|
+
for (let y = 0; y < 50; y += 10) {
|
|
766
|
+
for (let x = 0; x < 10; x++)
|
|
767
|
+
B[x] = s[y + x];
|
|
768
|
+
for (let x = 0; x < 10; x++)
|
|
769
|
+
s[y + x] ^= ~B[(x + 2) % 10] & B[(x + 4) % 10];
|
|
770
|
+
}
|
|
771
|
+
s[0] ^= SHA3_IOTA_H[round];
|
|
772
|
+
s[1] ^= SHA3_IOTA_L[round];
|
|
773
|
+
}
|
|
774
|
+
clean(B);
|
|
775
|
+
}
|
|
776
|
+
var Keccak = class _Keccak {
|
|
777
|
+
state;
|
|
778
|
+
pos = 0;
|
|
779
|
+
posOut = 0;
|
|
780
|
+
finished = false;
|
|
781
|
+
state32;
|
|
782
|
+
destroyed = false;
|
|
783
|
+
blockLen;
|
|
784
|
+
suffix;
|
|
785
|
+
outputLen;
|
|
786
|
+
enableXOF = false;
|
|
787
|
+
rounds;
|
|
788
|
+
// NOTE: we accept arguments in bytes instead of bits here.
|
|
789
|
+
constructor(blockLen, suffix, outputLen, enableXOF = false, rounds = 24) {
|
|
790
|
+
this.blockLen = blockLen;
|
|
791
|
+
this.suffix = suffix;
|
|
792
|
+
this.outputLen = outputLen;
|
|
793
|
+
this.enableXOF = enableXOF;
|
|
794
|
+
this.rounds = rounds;
|
|
795
|
+
anumber(outputLen, "outputLen");
|
|
796
|
+
if (!(0 < blockLen && blockLen < 200))
|
|
797
|
+
throw new Error("only keccak-f1600 function is supported");
|
|
798
|
+
this.state = new Uint8Array(200);
|
|
799
|
+
this.state32 = u32(this.state);
|
|
800
|
+
}
|
|
801
|
+
clone() {
|
|
802
|
+
return this._cloneInto();
|
|
803
|
+
}
|
|
804
|
+
keccak() {
|
|
805
|
+
swap32IfBE(this.state32);
|
|
806
|
+
keccakP(this.state32, this.rounds);
|
|
807
|
+
swap32IfBE(this.state32);
|
|
808
|
+
this.posOut = 0;
|
|
809
|
+
this.pos = 0;
|
|
810
|
+
}
|
|
811
|
+
update(data) {
|
|
812
|
+
aexists(this);
|
|
813
|
+
abytes(data);
|
|
814
|
+
const { blockLen, state } = this;
|
|
815
|
+
const len = data.length;
|
|
816
|
+
for (let pos = 0; pos < len; ) {
|
|
817
|
+
const take = Math.min(blockLen - this.pos, len - pos);
|
|
818
|
+
for (let i = 0; i < take; i++)
|
|
819
|
+
state[this.pos++] ^= data[pos++];
|
|
820
|
+
if (this.pos === blockLen)
|
|
821
|
+
this.keccak();
|
|
822
|
+
}
|
|
823
|
+
return this;
|
|
824
|
+
}
|
|
825
|
+
finish() {
|
|
826
|
+
if (this.finished)
|
|
827
|
+
return;
|
|
828
|
+
this.finished = true;
|
|
829
|
+
const { state, suffix, pos, blockLen } = this;
|
|
830
|
+
state[pos] ^= suffix;
|
|
831
|
+
if ((suffix & 128) !== 0 && pos === blockLen - 1)
|
|
832
|
+
this.keccak();
|
|
833
|
+
state[blockLen - 1] ^= 128;
|
|
834
|
+
this.keccak();
|
|
835
|
+
}
|
|
836
|
+
writeInto(out) {
|
|
837
|
+
aexists(this, false);
|
|
838
|
+
abytes(out);
|
|
839
|
+
this.finish();
|
|
840
|
+
const bufferOut = this.state;
|
|
841
|
+
const { blockLen } = this;
|
|
842
|
+
for (let pos = 0, len = out.length; pos < len; ) {
|
|
843
|
+
if (this.posOut >= blockLen)
|
|
844
|
+
this.keccak();
|
|
845
|
+
const take = Math.min(blockLen - this.posOut, len - pos);
|
|
846
|
+
out.set(bufferOut.subarray(this.posOut, this.posOut + take), pos);
|
|
847
|
+
this.posOut += take;
|
|
848
|
+
pos += take;
|
|
849
|
+
}
|
|
850
|
+
return out;
|
|
851
|
+
}
|
|
852
|
+
xofInto(out) {
|
|
853
|
+
if (!this.enableXOF)
|
|
854
|
+
throw new Error("XOF is not possible for this instance");
|
|
855
|
+
return this.writeInto(out);
|
|
856
|
+
}
|
|
857
|
+
xof(bytes) {
|
|
858
|
+
anumber(bytes);
|
|
859
|
+
return this.xofInto(new Uint8Array(bytes));
|
|
860
|
+
}
|
|
861
|
+
digestInto(out) {
|
|
862
|
+
aoutput(out, this);
|
|
863
|
+
if (this.finished)
|
|
864
|
+
throw new Error("digest() was already called");
|
|
865
|
+
this.writeInto(out);
|
|
866
|
+
this.destroy();
|
|
867
|
+
return out;
|
|
868
|
+
}
|
|
869
|
+
digest() {
|
|
870
|
+
return this.digestInto(new Uint8Array(this.outputLen));
|
|
871
|
+
}
|
|
872
|
+
destroy() {
|
|
873
|
+
this.destroyed = true;
|
|
874
|
+
clean(this.state);
|
|
875
|
+
}
|
|
876
|
+
_cloneInto(to) {
|
|
877
|
+
const { blockLen, suffix, outputLen, rounds, enableXOF } = this;
|
|
878
|
+
to ||= new _Keccak(blockLen, suffix, outputLen, enableXOF, rounds);
|
|
879
|
+
to.state32.set(this.state32);
|
|
880
|
+
to.pos = this.pos;
|
|
881
|
+
to.posOut = this.posOut;
|
|
882
|
+
to.finished = this.finished;
|
|
883
|
+
to.rounds = rounds;
|
|
884
|
+
to.suffix = suffix;
|
|
885
|
+
to.outputLen = outputLen;
|
|
886
|
+
to.enableXOF = enableXOF;
|
|
887
|
+
to.destroyed = this.destroyed;
|
|
888
|
+
return to;
|
|
889
|
+
}
|
|
890
|
+
};
|
|
891
|
+
var genKeccak = (suffix, blockLen, outputLen, info = {}) => createHasher(() => new Keccak(blockLen, suffix, outputLen), info);
|
|
892
|
+
var keccak_256 = /* @__PURE__ */ genKeccak(1, 136, 32);
|
|
893
|
+
|
|
894
|
+
// node_modules/@noble/hashes/_md.js
|
|
895
|
+
function Chi(a, b, c) {
|
|
896
|
+
return a & b ^ ~a & c;
|
|
897
|
+
}
|
|
898
|
+
function Maj(a, b, c) {
|
|
899
|
+
return a & b ^ a & c ^ b & c;
|
|
900
|
+
}
|
|
901
|
+
var HashMD = class {
|
|
902
|
+
blockLen;
|
|
903
|
+
outputLen;
|
|
904
|
+
padOffset;
|
|
905
|
+
isLE;
|
|
906
|
+
// For partial updates less than block size
|
|
907
|
+
buffer;
|
|
908
|
+
view;
|
|
909
|
+
finished = false;
|
|
910
|
+
length = 0;
|
|
911
|
+
pos = 0;
|
|
912
|
+
destroyed = false;
|
|
913
|
+
constructor(blockLen, outputLen, padOffset, isLE2) {
|
|
914
|
+
this.blockLen = blockLen;
|
|
915
|
+
this.outputLen = outputLen;
|
|
916
|
+
this.padOffset = padOffset;
|
|
917
|
+
this.isLE = isLE2;
|
|
918
|
+
this.buffer = new Uint8Array(blockLen);
|
|
919
|
+
this.view = createView(this.buffer);
|
|
920
|
+
}
|
|
921
|
+
update(data) {
|
|
922
|
+
aexists(this);
|
|
923
|
+
abytes(data);
|
|
924
|
+
const { view, buffer, blockLen } = this;
|
|
925
|
+
const len = data.length;
|
|
926
|
+
for (let pos = 0; pos < len; ) {
|
|
927
|
+
const take = Math.min(blockLen - this.pos, len - pos);
|
|
928
|
+
if (take === blockLen) {
|
|
929
|
+
const dataView = createView(data);
|
|
930
|
+
for (; blockLen <= len - pos; pos += blockLen)
|
|
931
|
+
this.process(dataView, pos);
|
|
932
|
+
continue;
|
|
933
|
+
}
|
|
934
|
+
buffer.set(data.subarray(pos, pos + take), this.pos);
|
|
935
|
+
this.pos += take;
|
|
936
|
+
pos += take;
|
|
937
|
+
if (this.pos === blockLen) {
|
|
938
|
+
this.process(view, 0);
|
|
939
|
+
this.pos = 0;
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
this.length += data.length;
|
|
943
|
+
this.roundClean();
|
|
944
|
+
return this;
|
|
945
|
+
}
|
|
946
|
+
digestInto(out) {
|
|
947
|
+
aexists(this);
|
|
948
|
+
aoutput(out, this);
|
|
949
|
+
this.finished = true;
|
|
950
|
+
const { buffer, view, blockLen, isLE: isLE2 } = this;
|
|
951
|
+
let { pos } = this;
|
|
952
|
+
buffer[pos++] = 128;
|
|
953
|
+
clean(this.buffer.subarray(pos));
|
|
954
|
+
if (this.padOffset > blockLen - pos) {
|
|
955
|
+
this.process(view, 0);
|
|
956
|
+
pos = 0;
|
|
957
|
+
}
|
|
958
|
+
for (let i = pos; i < blockLen; i++)
|
|
959
|
+
buffer[i] = 0;
|
|
960
|
+
view.setBigUint64(blockLen - 8, BigInt(this.length * 8), isLE2);
|
|
961
|
+
this.process(view, 0);
|
|
962
|
+
const oview = createView(out);
|
|
963
|
+
const len = this.outputLen;
|
|
964
|
+
if (len % 4)
|
|
965
|
+
throw new Error("_sha2: outputLen must be aligned to 32bit");
|
|
966
|
+
const outLen = len / 4;
|
|
967
|
+
const state = this.get();
|
|
968
|
+
if (outLen > state.length)
|
|
969
|
+
throw new Error("_sha2: outputLen bigger than state");
|
|
970
|
+
for (let i = 0; i < outLen; i++)
|
|
971
|
+
oview.setUint32(4 * i, state[i], isLE2);
|
|
972
|
+
}
|
|
973
|
+
digest() {
|
|
974
|
+
const { buffer, outputLen } = this;
|
|
975
|
+
this.digestInto(buffer);
|
|
976
|
+
const res = buffer.slice(0, outputLen);
|
|
977
|
+
this.destroy();
|
|
978
|
+
return res;
|
|
979
|
+
}
|
|
980
|
+
_cloneInto(to) {
|
|
981
|
+
to ||= new this.constructor();
|
|
982
|
+
to.set(...this.get());
|
|
983
|
+
const { blockLen, buffer, length, finished, destroyed, pos } = this;
|
|
984
|
+
to.destroyed = destroyed;
|
|
985
|
+
to.finished = finished;
|
|
986
|
+
to.length = length;
|
|
987
|
+
to.pos = pos;
|
|
988
|
+
if (length % blockLen)
|
|
989
|
+
to.buffer.set(buffer);
|
|
990
|
+
return to;
|
|
991
|
+
}
|
|
992
|
+
clone() {
|
|
993
|
+
return this._cloneInto();
|
|
994
|
+
}
|
|
995
|
+
};
|
|
996
|
+
var SHA256_IV = /* @__PURE__ */ Uint32Array.from([
|
|
997
|
+
1779033703,
|
|
998
|
+
3144134277,
|
|
999
|
+
1013904242,
|
|
1000
|
+
2773480762,
|
|
1001
|
+
1359893119,
|
|
1002
|
+
2600822924,
|
|
1003
|
+
528734635,
|
|
1004
|
+
1541459225
|
|
1005
|
+
]);
|
|
1006
|
+
|
|
1007
|
+
// node_modules/@noble/hashes/sha2.js
|
|
1008
|
+
var SHA256_K = /* @__PURE__ */ Uint32Array.from([
|
|
1009
|
+
1116352408,
|
|
1010
|
+
1899447441,
|
|
1011
|
+
3049323471,
|
|
1012
|
+
3921009573,
|
|
1013
|
+
961987163,
|
|
1014
|
+
1508970993,
|
|
1015
|
+
2453635748,
|
|
1016
|
+
2870763221,
|
|
1017
|
+
3624381080,
|
|
1018
|
+
310598401,
|
|
1019
|
+
607225278,
|
|
1020
|
+
1426881987,
|
|
1021
|
+
1925078388,
|
|
1022
|
+
2162078206,
|
|
1023
|
+
2614888103,
|
|
1024
|
+
3248222580,
|
|
1025
|
+
3835390401,
|
|
1026
|
+
4022224774,
|
|
1027
|
+
264347078,
|
|
1028
|
+
604807628,
|
|
1029
|
+
770255983,
|
|
1030
|
+
1249150122,
|
|
1031
|
+
1555081692,
|
|
1032
|
+
1996064986,
|
|
1033
|
+
2554220882,
|
|
1034
|
+
2821834349,
|
|
1035
|
+
2952996808,
|
|
1036
|
+
3210313671,
|
|
1037
|
+
3336571891,
|
|
1038
|
+
3584528711,
|
|
1039
|
+
113926993,
|
|
1040
|
+
338241895,
|
|
1041
|
+
666307205,
|
|
1042
|
+
773529912,
|
|
1043
|
+
1294757372,
|
|
1044
|
+
1396182291,
|
|
1045
|
+
1695183700,
|
|
1046
|
+
1986661051,
|
|
1047
|
+
2177026350,
|
|
1048
|
+
2456956037,
|
|
1049
|
+
2730485921,
|
|
1050
|
+
2820302411,
|
|
1051
|
+
3259730800,
|
|
1052
|
+
3345764771,
|
|
1053
|
+
3516065817,
|
|
1054
|
+
3600352804,
|
|
1055
|
+
4094571909,
|
|
1056
|
+
275423344,
|
|
1057
|
+
430227734,
|
|
1058
|
+
506948616,
|
|
1059
|
+
659060556,
|
|
1060
|
+
883997877,
|
|
1061
|
+
958139571,
|
|
1062
|
+
1322822218,
|
|
1063
|
+
1537002063,
|
|
1064
|
+
1747873779,
|
|
1065
|
+
1955562222,
|
|
1066
|
+
2024104815,
|
|
1067
|
+
2227730452,
|
|
1068
|
+
2361852424,
|
|
1069
|
+
2428436474,
|
|
1070
|
+
2756734187,
|
|
1071
|
+
3204031479,
|
|
1072
|
+
3329325298
|
|
1073
|
+
]);
|
|
1074
|
+
var SHA256_W = /* @__PURE__ */ new Uint32Array(64);
|
|
1075
|
+
var SHA2_32B = class extends HashMD {
|
|
1076
|
+
constructor(outputLen) {
|
|
1077
|
+
super(64, outputLen, 8, false);
|
|
1078
|
+
}
|
|
1079
|
+
get() {
|
|
1080
|
+
const { A, B, C, D, E, F, G, H } = this;
|
|
1081
|
+
return [A, B, C, D, E, F, G, H];
|
|
1082
|
+
}
|
|
1083
|
+
// prettier-ignore
|
|
1084
|
+
set(A, B, C, D, E, F, G, H) {
|
|
1085
|
+
this.A = A | 0;
|
|
1086
|
+
this.B = B | 0;
|
|
1087
|
+
this.C = C | 0;
|
|
1088
|
+
this.D = D | 0;
|
|
1089
|
+
this.E = E | 0;
|
|
1090
|
+
this.F = F | 0;
|
|
1091
|
+
this.G = G | 0;
|
|
1092
|
+
this.H = H | 0;
|
|
1093
|
+
}
|
|
1094
|
+
process(view, offset) {
|
|
1095
|
+
for (let i = 0; i < 16; i++, offset += 4)
|
|
1096
|
+
SHA256_W[i] = view.getUint32(offset, false);
|
|
1097
|
+
for (let i = 16; i < 64; i++) {
|
|
1098
|
+
const W15 = SHA256_W[i - 15];
|
|
1099
|
+
const W2 = SHA256_W[i - 2];
|
|
1100
|
+
const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ W15 >>> 3;
|
|
1101
|
+
const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ W2 >>> 10;
|
|
1102
|
+
SHA256_W[i] = s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16] | 0;
|
|
1103
|
+
}
|
|
1104
|
+
let { A, B, C, D, E, F, G, H } = this;
|
|
1105
|
+
for (let i = 0; i < 64; i++) {
|
|
1106
|
+
const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);
|
|
1107
|
+
const T1 = H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i] | 0;
|
|
1108
|
+
const sigma0 = rotr(A, 2) ^ rotr(A, 13) ^ rotr(A, 22);
|
|
1109
|
+
const T2 = sigma0 + Maj(A, B, C) | 0;
|
|
1110
|
+
H = G;
|
|
1111
|
+
G = F;
|
|
1112
|
+
F = E;
|
|
1113
|
+
E = D + T1 | 0;
|
|
1114
|
+
D = C;
|
|
1115
|
+
C = B;
|
|
1116
|
+
B = A;
|
|
1117
|
+
A = T1 + T2 | 0;
|
|
1118
|
+
}
|
|
1119
|
+
A = A + this.A | 0;
|
|
1120
|
+
B = B + this.B | 0;
|
|
1121
|
+
C = C + this.C | 0;
|
|
1122
|
+
D = D + this.D | 0;
|
|
1123
|
+
E = E + this.E | 0;
|
|
1124
|
+
F = F + this.F | 0;
|
|
1125
|
+
G = G + this.G | 0;
|
|
1126
|
+
H = H + this.H | 0;
|
|
1127
|
+
this.set(A, B, C, D, E, F, G, H);
|
|
1128
|
+
}
|
|
1129
|
+
roundClean() {
|
|
1130
|
+
clean(SHA256_W);
|
|
1131
|
+
}
|
|
1132
|
+
destroy() {
|
|
1133
|
+
this.set(0, 0, 0, 0, 0, 0, 0, 0);
|
|
1134
|
+
clean(this.buffer);
|
|
1135
|
+
}
|
|
1136
|
+
};
|
|
1137
|
+
var _SHA256 = class extends SHA2_32B {
|
|
1138
|
+
// We cannot use array here since array allows indexing by variable
|
|
1139
|
+
// which means optimizer/compiler cannot use registers.
|
|
1140
|
+
A = SHA256_IV[0] | 0;
|
|
1141
|
+
B = SHA256_IV[1] | 0;
|
|
1142
|
+
C = SHA256_IV[2] | 0;
|
|
1143
|
+
D = SHA256_IV[3] | 0;
|
|
1144
|
+
E = SHA256_IV[4] | 0;
|
|
1145
|
+
F = SHA256_IV[5] | 0;
|
|
1146
|
+
G = SHA256_IV[6] | 0;
|
|
1147
|
+
H = SHA256_IV[7] | 0;
|
|
1148
|
+
constructor() {
|
|
1149
|
+
super(32);
|
|
1150
|
+
}
|
|
1151
|
+
};
|
|
1152
|
+
var sha256 = /* @__PURE__ */ createHasher(
|
|
1153
|
+
() => new _SHA256(),
|
|
1154
|
+
/* @__PURE__ */ oidNist(1)
|
|
1155
|
+
);
|
|
1156
|
+
|
|
1157
|
+
// node_modules/@noble/curves/utils.js
|
|
1158
|
+
var _0n2 = /* @__PURE__ */ BigInt(0);
|
|
1159
|
+
var _1n2 = /* @__PURE__ */ BigInt(1);
|
|
1160
|
+
function abool(value, title = "") {
|
|
1161
|
+
if (typeof value !== "boolean") {
|
|
1162
|
+
const prefix = title && `"${title}" `;
|
|
1163
|
+
throw new Error(prefix + "expected boolean, got type=" + typeof value);
|
|
1164
|
+
}
|
|
1165
|
+
return value;
|
|
1166
|
+
}
|
|
1167
|
+
function abignumber(n) {
|
|
1168
|
+
if (typeof n === "bigint") {
|
|
1169
|
+
if (!isPosBig(n))
|
|
1170
|
+
throw new Error("positive bigint expected, got " + n);
|
|
1171
|
+
} else
|
|
1172
|
+
anumber(n);
|
|
1173
|
+
return n;
|
|
1174
|
+
}
|
|
1175
|
+
function numberToHexUnpadded(num) {
|
|
1176
|
+
const hex = abignumber(num).toString(16);
|
|
1177
|
+
return hex.length & 1 ? "0" + hex : hex;
|
|
1178
|
+
}
|
|
1179
|
+
function hexToNumber(hex) {
|
|
1180
|
+
if (typeof hex !== "string")
|
|
1181
|
+
throw new Error("hex string expected, got " + typeof hex);
|
|
1182
|
+
return hex === "" ? _0n2 : BigInt("0x" + hex);
|
|
1183
|
+
}
|
|
1184
|
+
function bytesToNumberBE(bytes) {
|
|
1185
|
+
return hexToNumber(bytesToHex(bytes));
|
|
1186
|
+
}
|
|
1187
|
+
function bytesToNumberLE(bytes) {
|
|
1188
|
+
return hexToNumber(bytesToHex(copyBytes(abytes(bytes)).reverse()));
|
|
1189
|
+
}
|
|
1190
|
+
function numberToBytesBE(n, len) {
|
|
1191
|
+
anumber(len);
|
|
1192
|
+
n = abignumber(n);
|
|
1193
|
+
const res = hexToBytes(n.toString(16).padStart(len * 2, "0"));
|
|
1194
|
+
if (res.length !== len)
|
|
1195
|
+
throw new Error("number too large");
|
|
1196
|
+
return res;
|
|
1197
|
+
}
|
|
1198
|
+
function numberToBytesLE(n, len) {
|
|
1199
|
+
return numberToBytesBE(n, len).reverse();
|
|
1200
|
+
}
|
|
1201
|
+
function copyBytes(bytes) {
|
|
1202
|
+
return Uint8Array.from(bytes);
|
|
1203
|
+
}
|
|
1204
|
+
var isPosBig = (n) => typeof n === "bigint" && _0n2 <= n;
|
|
1205
|
+
function inRange(n, min, max) {
|
|
1206
|
+
return isPosBig(n) && isPosBig(min) && isPosBig(max) && min <= n && n < max;
|
|
1207
|
+
}
|
|
1208
|
+
function aInRange(title, n, min, max) {
|
|
1209
|
+
if (!inRange(n, min, max))
|
|
1210
|
+
throw new Error("expected valid " + title + ": " + min + " <= n < " + max + ", got " + n);
|
|
1211
|
+
}
|
|
1212
|
+
function bitLen(n) {
|
|
1213
|
+
let len;
|
|
1214
|
+
for (len = 0; n > _0n2; n >>= _1n2, len += 1)
|
|
1215
|
+
;
|
|
1216
|
+
return len;
|
|
1217
|
+
}
|
|
1218
|
+
var bitMask = (n) => (_1n2 << BigInt(n)) - _1n2;
|
|
1219
|
+
function createHmacDrbg(hashLen, qByteLen, hmacFn) {
|
|
1220
|
+
anumber(hashLen, "hashLen");
|
|
1221
|
+
anumber(qByteLen, "qByteLen");
|
|
1222
|
+
if (typeof hmacFn !== "function")
|
|
1223
|
+
throw new Error("hmacFn must be a function");
|
|
1224
|
+
const u8n = (len) => new Uint8Array(len);
|
|
1225
|
+
const NULL = Uint8Array.of();
|
|
1226
|
+
const byte0 = Uint8Array.of(0);
|
|
1227
|
+
const byte1 = Uint8Array.of(1);
|
|
1228
|
+
const _maxDrbgIters = 1e3;
|
|
1229
|
+
let v = u8n(hashLen);
|
|
1230
|
+
let k = u8n(hashLen);
|
|
1231
|
+
let i = 0;
|
|
1232
|
+
const reset = () => {
|
|
1233
|
+
v.fill(1);
|
|
1234
|
+
k.fill(0);
|
|
1235
|
+
i = 0;
|
|
1236
|
+
};
|
|
1237
|
+
const h = (...msgs) => hmacFn(k, concatBytes(v, ...msgs));
|
|
1238
|
+
const reseed = (seed = NULL) => {
|
|
1239
|
+
k = h(byte0, seed);
|
|
1240
|
+
v = h();
|
|
1241
|
+
if (seed.length === 0)
|
|
1242
|
+
return;
|
|
1243
|
+
k = h(byte1, seed);
|
|
1244
|
+
v = h();
|
|
1245
|
+
};
|
|
1246
|
+
const gen = () => {
|
|
1247
|
+
if (i++ >= _maxDrbgIters)
|
|
1248
|
+
throw new Error("drbg: tried max amount of iterations");
|
|
1249
|
+
let len = 0;
|
|
1250
|
+
const out = [];
|
|
1251
|
+
while (len < qByteLen) {
|
|
1252
|
+
v = h();
|
|
1253
|
+
const sl = v.slice();
|
|
1254
|
+
out.push(sl);
|
|
1255
|
+
len += v.length;
|
|
1256
|
+
}
|
|
1257
|
+
return concatBytes(...out);
|
|
1258
|
+
};
|
|
1259
|
+
const genUntil = (seed, pred) => {
|
|
1260
|
+
reset();
|
|
1261
|
+
reseed(seed);
|
|
1262
|
+
let res = void 0;
|
|
1263
|
+
while (!(res = pred(gen())))
|
|
1264
|
+
reseed();
|
|
1265
|
+
reset();
|
|
1266
|
+
return res;
|
|
1267
|
+
};
|
|
1268
|
+
return genUntil;
|
|
1269
|
+
}
|
|
1270
|
+
function validateObject(object, fields = {}, optFields = {}) {
|
|
1271
|
+
if (!object || typeof object !== "object")
|
|
1272
|
+
throw new Error("expected valid options object");
|
|
1273
|
+
function checkField(fieldName, expectedType, isOpt) {
|
|
1274
|
+
const val = object[fieldName];
|
|
1275
|
+
if (isOpt && val === void 0)
|
|
1276
|
+
return;
|
|
1277
|
+
const current = typeof val;
|
|
1278
|
+
if (current !== expectedType || val === null)
|
|
1279
|
+
throw new Error(`param "${fieldName}" is invalid: expected ${expectedType}, got ${current}`);
|
|
1280
|
+
}
|
|
1281
|
+
const iter = (f, isOpt) => Object.entries(f).forEach(([k, v]) => checkField(k, v, isOpt));
|
|
1282
|
+
iter(fields, false);
|
|
1283
|
+
iter(optFields, true);
|
|
1284
|
+
}
|
|
1285
|
+
function memoized(fn) {
|
|
1286
|
+
const map = /* @__PURE__ */ new WeakMap();
|
|
1287
|
+
return (arg, ...args) => {
|
|
1288
|
+
const val = map.get(arg);
|
|
1289
|
+
if (val !== void 0)
|
|
1290
|
+
return val;
|
|
1291
|
+
const computed = fn(arg, ...args);
|
|
1292
|
+
map.set(arg, computed);
|
|
1293
|
+
return computed;
|
|
1294
|
+
};
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
// node_modules/@noble/curves/abstract/modular.js
|
|
1298
|
+
var _0n3 = /* @__PURE__ */ BigInt(0);
|
|
1299
|
+
var _1n3 = /* @__PURE__ */ BigInt(1);
|
|
1300
|
+
var _2n2 = /* @__PURE__ */ BigInt(2);
|
|
1301
|
+
var _3n = /* @__PURE__ */ BigInt(3);
|
|
1302
|
+
var _4n = /* @__PURE__ */ BigInt(4);
|
|
1303
|
+
var _5n = /* @__PURE__ */ BigInt(5);
|
|
1304
|
+
var _7n2 = /* @__PURE__ */ BigInt(7);
|
|
1305
|
+
var _8n = /* @__PURE__ */ BigInt(8);
|
|
1306
|
+
var _9n = /* @__PURE__ */ BigInt(9);
|
|
1307
|
+
var _16n = /* @__PURE__ */ BigInt(16);
|
|
1308
|
+
function mod(a, b) {
|
|
1309
|
+
const result = a % b;
|
|
1310
|
+
return result >= _0n3 ? result : b + result;
|
|
1311
|
+
}
|
|
1312
|
+
function pow2(x, power, modulo) {
|
|
1313
|
+
let res = x;
|
|
1314
|
+
while (power-- > _0n3) {
|
|
1315
|
+
res *= res;
|
|
1316
|
+
res %= modulo;
|
|
1317
|
+
}
|
|
1318
|
+
return res;
|
|
1319
|
+
}
|
|
1320
|
+
function invert(number, modulo) {
|
|
1321
|
+
if (number === _0n3)
|
|
1322
|
+
throw new Error("invert: expected non-zero number");
|
|
1323
|
+
if (modulo <= _0n3)
|
|
1324
|
+
throw new Error("invert: expected positive modulus, got " + modulo);
|
|
1325
|
+
let a = mod(number, modulo);
|
|
1326
|
+
let b = modulo;
|
|
1327
|
+
let x = _0n3, y = _1n3, u = _1n3, v = _0n3;
|
|
1328
|
+
while (a !== _0n3) {
|
|
1329
|
+
const q = b / a;
|
|
1330
|
+
const r = b % a;
|
|
1331
|
+
const m = x - u * q;
|
|
1332
|
+
const n = y - v * q;
|
|
1333
|
+
b = a, a = r, x = u, y = v, u = m, v = n;
|
|
1334
|
+
}
|
|
1335
|
+
const gcd = b;
|
|
1336
|
+
if (gcd !== _1n3)
|
|
1337
|
+
throw new Error("invert: does not exist");
|
|
1338
|
+
return mod(x, modulo);
|
|
1339
|
+
}
|
|
1340
|
+
function assertIsSquare(Fp, root, n) {
|
|
1341
|
+
if (!Fp.eql(Fp.sqr(root), n))
|
|
1342
|
+
throw new Error("Cannot find square root");
|
|
1343
|
+
}
|
|
1344
|
+
function sqrt3mod4(Fp, n) {
|
|
1345
|
+
const p1div4 = (Fp.ORDER + _1n3) / _4n;
|
|
1346
|
+
const root = Fp.pow(n, p1div4);
|
|
1347
|
+
assertIsSquare(Fp, root, n);
|
|
1348
|
+
return root;
|
|
1349
|
+
}
|
|
1350
|
+
function sqrt5mod8(Fp, n) {
|
|
1351
|
+
const p5div8 = (Fp.ORDER - _5n) / _8n;
|
|
1352
|
+
const n2 = Fp.mul(n, _2n2);
|
|
1353
|
+
const v = Fp.pow(n2, p5div8);
|
|
1354
|
+
const nv = Fp.mul(n, v);
|
|
1355
|
+
const i = Fp.mul(Fp.mul(nv, _2n2), v);
|
|
1356
|
+
const root = Fp.mul(nv, Fp.sub(i, Fp.ONE));
|
|
1357
|
+
assertIsSquare(Fp, root, n);
|
|
1358
|
+
return root;
|
|
1359
|
+
}
|
|
1360
|
+
function sqrt9mod16(P) {
|
|
1361
|
+
const Fp_ = Field(P);
|
|
1362
|
+
const tn = tonelliShanks(P);
|
|
1363
|
+
const c1 = tn(Fp_, Fp_.neg(Fp_.ONE));
|
|
1364
|
+
const c2 = tn(Fp_, c1);
|
|
1365
|
+
const c3 = tn(Fp_, Fp_.neg(c1));
|
|
1366
|
+
const c4 = (P + _7n2) / _16n;
|
|
1367
|
+
return (Fp, n) => {
|
|
1368
|
+
let tv1 = Fp.pow(n, c4);
|
|
1369
|
+
let tv2 = Fp.mul(tv1, c1);
|
|
1370
|
+
const tv3 = Fp.mul(tv1, c2);
|
|
1371
|
+
const tv4 = Fp.mul(tv1, c3);
|
|
1372
|
+
const e1 = Fp.eql(Fp.sqr(tv2), n);
|
|
1373
|
+
const e2 = Fp.eql(Fp.sqr(tv3), n);
|
|
1374
|
+
tv1 = Fp.cmov(tv1, tv2, e1);
|
|
1375
|
+
tv2 = Fp.cmov(tv4, tv3, e2);
|
|
1376
|
+
const e3 = Fp.eql(Fp.sqr(tv2), n);
|
|
1377
|
+
const root = Fp.cmov(tv1, tv2, e3);
|
|
1378
|
+
assertIsSquare(Fp, root, n);
|
|
1379
|
+
return root;
|
|
1380
|
+
};
|
|
1381
|
+
}
|
|
1382
|
+
function tonelliShanks(P) {
|
|
1383
|
+
if (P < _3n)
|
|
1384
|
+
throw new Error("sqrt is not defined for small field");
|
|
1385
|
+
let Q = P - _1n3;
|
|
1386
|
+
let S = 0;
|
|
1387
|
+
while (Q % _2n2 === _0n3) {
|
|
1388
|
+
Q /= _2n2;
|
|
1389
|
+
S++;
|
|
1390
|
+
}
|
|
1391
|
+
let Z = _2n2;
|
|
1392
|
+
const _Fp = Field(P);
|
|
1393
|
+
while (FpLegendre(_Fp, Z) === 1) {
|
|
1394
|
+
if (Z++ > 1e3)
|
|
1395
|
+
throw new Error("Cannot find square root: probably non-prime P");
|
|
1396
|
+
}
|
|
1397
|
+
if (S === 1)
|
|
1398
|
+
return sqrt3mod4;
|
|
1399
|
+
let cc = _Fp.pow(Z, Q);
|
|
1400
|
+
const Q1div2 = (Q + _1n3) / _2n2;
|
|
1401
|
+
return function tonelliSlow(Fp, n) {
|
|
1402
|
+
if (Fp.is0(n))
|
|
1403
|
+
return n;
|
|
1404
|
+
if (FpLegendre(Fp, n) !== 1)
|
|
1405
|
+
throw new Error("Cannot find square root");
|
|
1406
|
+
let M = S;
|
|
1407
|
+
let c = Fp.mul(Fp.ONE, cc);
|
|
1408
|
+
let t = Fp.pow(n, Q);
|
|
1409
|
+
let R = Fp.pow(n, Q1div2);
|
|
1410
|
+
while (!Fp.eql(t, Fp.ONE)) {
|
|
1411
|
+
if (Fp.is0(t))
|
|
1412
|
+
return Fp.ZERO;
|
|
1413
|
+
let i = 1;
|
|
1414
|
+
let t_tmp = Fp.sqr(t);
|
|
1415
|
+
while (!Fp.eql(t_tmp, Fp.ONE)) {
|
|
1416
|
+
i++;
|
|
1417
|
+
t_tmp = Fp.sqr(t_tmp);
|
|
1418
|
+
if (i === M)
|
|
1419
|
+
throw new Error("Cannot find square root");
|
|
1420
|
+
}
|
|
1421
|
+
const exponent = _1n3 << BigInt(M - i - 1);
|
|
1422
|
+
const b = Fp.pow(c, exponent);
|
|
1423
|
+
M = i;
|
|
1424
|
+
c = Fp.sqr(b);
|
|
1425
|
+
t = Fp.mul(t, c);
|
|
1426
|
+
R = Fp.mul(R, b);
|
|
1427
|
+
}
|
|
1428
|
+
return R;
|
|
1429
|
+
};
|
|
1430
|
+
}
|
|
1431
|
+
function FpSqrt(P) {
|
|
1432
|
+
if (P % _4n === _3n)
|
|
1433
|
+
return sqrt3mod4;
|
|
1434
|
+
if (P % _8n === _5n)
|
|
1435
|
+
return sqrt5mod8;
|
|
1436
|
+
if (P % _16n === _9n)
|
|
1437
|
+
return sqrt9mod16(P);
|
|
1438
|
+
return tonelliShanks(P);
|
|
1439
|
+
}
|
|
1440
|
+
var FIELD_FIELDS = [
|
|
1441
|
+
"create",
|
|
1442
|
+
"isValid",
|
|
1443
|
+
"is0",
|
|
1444
|
+
"neg",
|
|
1445
|
+
"inv",
|
|
1446
|
+
"sqrt",
|
|
1447
|
+
"sqr",
|
|
1448
|
+
"eql",
|
|
1449
|
+
"add",
|
|
1450
|
+
"sub",
|
|
1451
|
+
"mul",
|
|
1452
|
+
"pow",
|
|
1453
|
+
"div",
|
|
1454
|
+
"addN",
|
|
1455
|
+
"subN",
|
|
1456
|
+
"mulN",
|
|
1457
|
+
"sqrN"
|
|
1458
|
+
];
|
|
1459
|
+
function validateField(field) {
|
|
1460
|
+
const initial = {
|
|
1461
|
+
ORDER: "bigint",
|
|
1462
|
+
BYTES: "number",
|
|
1463
|
+
BITS: "number"
|
|
1464
|
+
};
|
|
1465
|
+
const opts = FIELD_FIELDS.reduce((map, val) => {
|
|
1466
|
+
map[val] = "function";
|
|
1467
|
+
return map;
|
|
1468
|
+
}, initial);
|
|
1469
|
+
validateObject(field, opts);
|
|
1470
|
+
return field;
|
|
1471
|
+
}
|
|
1472
|
+
function FpPow(Fp, num, power) {
|
|
1473
|
+
if (power < _0n3)
|
|
1474
|
+
throw new Error("invalid exponent, negatives unsupported");
|
|
1475
|
+
if (power === _0n3)
|
|
1476
|
+
return Fp.ONE;
|
|
1477
|
+
if (power === _1n3)
|
|
1478
|
+
return num;
|
|
1479
|
+
let p = Fp.ONE;
|
|
1480
|
+
let d = num;
|
|
1481
|
+
while (power > _0n3) {
|
|
1482
|
+
if (power & _1n3)
|
|
1483
|
+
p = Fp.mul(p, d);
|
|
1484
|
+
d = Fp.sqr(d);
|
|
1485
|
+
power >>= _1n3;
|
|
1486
|
+
}
|
|
1487
|
+
return p;
|
|
1488
|
+
}
|
|
1489
|
+
function FpInvertBatch(Fp, nums, passZero = false) {
|
|
1490
|
+
const inverted = new Array(nums.length).fill(passZero ? Fp.ZERO : void 0);
|
|
1491
|
+
const multipliedAcc = nums.reduce((acc, num, i) => {
|
|
1492
|
+
if (Fp.is0(num))
|
|
1493
|
+
return acc;
|
|
1494
|
+
inverted[i] = acc;
|
|
1495
|
+
return Fp.mul(acc, num);
|
|
1496
|
+
}, Fp.ONE);
|
|
1497
|
+
const invertedAcc = Fp.inv(multipliedAcc);
|
|
1498
|
+
nums.reduceRight((acc, num, i) => {
|
|
1499
|
+
if (Fp.is0(num))
|
|
1500
|
+
return acc;
|
|
1501
|
+
inverted[i] = Fp.mul(acc, inverted[i]);
|
|
1502
|
+
return Fp.mul(acc, num);
|
|
1503
|
+
}, invertedAcc);
|
|
1504
|
+
return inverted;
|
|
1505
|
+
}
|
|
1506
|
+
function FpLegendre(Fp, n) {
|
|
1507
|
+
const p1mod2 = (Fp.ORDER - _1n3) / _2n2;
|
|
1508
|
+
const powered = Fp.pow(n, p1mod2);
|
|
1509
|
+
const yes = Fp.eql(powered, Fp.ONE);
|
|
1510
|
+
const zero = Fp.eql(powered, Fp.ZERO);
|
|
1511
|
+
const no = Fp.eql(powered, Fp.neg(Fp.ONE));
|
|
1512
|
+
if (!yes && !zero && !no)
|
|
1513
|
+
throw new Error("invalid Legendre symbol result");
|
|
1514
|
+
return yes ? 1 : zero ? 0 : -1;
|
|
1515
|
+
}
|
|
1516
|
+
function nLength(n, nBitLength) {
|
|
1517
|
+
if (nBitLength !== void 0)
|
|
1518
|
+
anumber(nBitLength);
|
|
1519
|
+
const _nBitLength = nBitLength !== void 0 ? nBitLength : n.toString(2).length;
|
|
1520
|
+
const nByteLength = Math.ceil(_nBitLength / 8);
|
|
1521
|
+
return { nBitLength: _nBitLength, nByteLength };
|
|
1522
|
+
}
|
|
1523
|
+
var _Field = class {
|
|
1524
|
+
ORDER;
|
|
1525
|
+
BITS;
|
|
1526
|
+
BYTES;
|
|
1527
|
+
isLE;
|
|
1528
|
+
ZERO = _0n3;
|
|
1529
|
+
ONE = _1n3;
|
|
1530
|
+
_lengths;
|
|
1531
|
+
_sqrt;
|
|
1532
|
+
// cached sqrt
|
|
1533
|
+
_mod;
|
|
1534
|
+
constructor(ORDER, opts = {}) {
|
|
1535
|
+
if (ORDER <= _0n3)
|
|
1536
|
+
throw new Error("invalid field: expected ORDER > 0, got " + ORDER);
|
|
1537
|
+
let _nbitLength = void 0;
|
|
1538
|
+
this.isLE = false;
|
|
1539
|
+
if (opts != null && typeof opts === "object") {
|
|
1540
|
+
if (typeof opts.BITS === "number")
|
|
1541
|
+
_nbitLength = opts.BITS;
|
|
1542
|
+
if (typeof opts.sqrt === "function")
|
|
1543
|
+
this.sqrt = opts.sqrt;
|
|
1544
|
+
if (typeof opts.isLE === "boolean")
|
|
1545
|
+
this.isLE = opts.isLE;
|
|
1546
|
+
if (opts.allowedLengths)
|
|
1547
|
+
this._lengths = opts.allowedLengths?.slice();
|
|
1548
|
+
if (typeof opts.modFromBytes === "boolean")
|
|
1549
|
+
this._mod = opts.modFromBytes;
|
|
1550
|
+
}
|
|
1551
|
+
const { nBitLength, nByteLength } = nLength(ORDER, _nbitLength);
|
|
1552
|
+
if (nByteLength > 2048)
|
|
1553
|
+
throw new Error("invalid field: expected ORDER of <= 2048 bytes");
|
|
1554
|
+
this.ORDER = ORDER;
|
|
1555
|
+
this.BITS = nBitLength;
|
|
1556
|
+
this.BYTES = nByteLength;
|
|
1557
|
+
this._sqrt = void 0;
|
|
1558
|
+
Object.preventExtensions(this);
|
|
1559
|
+
}
|
|
1560
|
+
create(num) {
|
|
1561
|
+
return mod(num, this.ORDER);
|
|
1562
|
+
}
|
|
1563
|
+
isValid(num) {
|
|
1564
|
+
if (typeof num !== "bigint")
|
|
1565
|
+
throw new Error("invalid field element: expected bigint, got " + typeof num);
|
|
1566
|
+
return _0n3 <= num && num < this.ORDER;
|
|
1567
|
+
}
|
|
1568
|
+
is0(num) {
|
|
1569
|
+
return num === _0n3;
|
|
1570
|
+
}
|
|
1571
|
+
// is valid and invertible
|
|
1572
|
+
isValidNot0(num) {
|
|
1573
|
+
return !this.is0(num) && this.isValid(num);
|
|
1574
|
+
}
|
|
1575
|
+
isOdd(num) {
|
|
1576
|
+
return (num & _1n3) === _1n3;
|
|
1577
|
+
}
|
|
1578
|
+
neg(num) {
|
|
1579
|
+
return mod(-num, this.ORDER);
|
|
1580
|
+
}
|
|
1581
|
+
eql(lhs, rhs) {
|
|
1582
|
+
return lhs === rhs;
|
|
1583
|
+
}
|
|
1584
|
+
sqr(num) {
|
|
1585
|
+
return mod(num * num, this.ORDER);
|
|
1586
|
+
}
|
|
1587
|
+
add(lhs, rhs) {
|
|
1588
|
+
return mod(lhs + rhs, this.ORDER);
|
|
1589
|
+
}
|
|
1590
|
+
sub(lhs, rhs) {
|
|
1591
|
+
return mod(lhs - rhs, this.ORDER);
|
|
1592
|
+
}
|
|
1593
|
+
mul(lhs, rhs) {
|
|
1594
|
+
return mod(lhs * rhs, this.ORDER);
|
|
1595
|
+
}
|
|
1596
|
+
pow(num, power) {
|
|
1597
|
+
return FpPow(this, num, power);
|
|
1598
|
+
}
|
|
1599
|
+
div(lhs, rhs) {
|
|
1600
|
+
return mod(lhs * invert(rhs, this.ORDER), this.ORDER);
|
|
1601
|
+
}
|
|
1602
|
+
// Same as above, but doesn't normalize
|
|
1603
|
+
sqrN(num) {
|
|
1604
|
+
return num * num;
|
|
1605
|
+
}
|
|
1606
|
+
addN(lhs, rhs) {
|
|
1607
|
+
return lhs + rhs;
|
|
1608
|
+
}
|
|
1609
|
+
subN(lhs, rhs) {
|
|
1610
|
+
return lhs - rhs;
|
|
1611
|
+
}
|
|
1612
|
+
mulN(lhs, rhs) {
|
|
1613
|
+
return lhs * rhs;
|
|
1614
|
+
}
|
|
1615
|
+
inv(num) {
|
|
1616
|
+
return invert(num, this.ORDER);
|
|
1617
|
+
}
|
|
1618
|
+
sqrt(num) {
|
|
1619
|
+
if (!this._sqrt)
|
|
1620
|
+
this._sqrt = FpSqrt(this.ORDER);
|
|
1621
|
+
return this._sqrt(this, num);
|
|
1622
|
+
}
|
|
1623
|
+
toBytes(num) {
|
|
1624
|
+
return this.isLE ? numberToBytesLE(num, this.BYTES) : numberToBytesBE(num, this.BYTES);
|
|
1625
|
+
}
|
|
1626
|
+
fromBytes(bytes, skipValidation = false) {
|
|
1627
|
+
abytes(bytes);
|
|
1628
|
+
const { _lengths: allowedLengths, BYTES, isLE: isLE2, ORDER, _mod: modFromBytes } = this;
|
|
1629
|
+
if (allowedLengths) {
|
|
1630
|
+
if (!allowedLengths.includes(bytes.length) || bytes.length > BYTES) {
|
|
1631
|
+
throw new Error("Field.fromBytes: expected " + allowedLengths + " bytes, got " + bytes.length);
|
|
1632
|
+
}
|
|
1633
|
+
const padded = new Uint8Array(BYTES);
|
|
1634
|
+
padded.set(bytes, isLE2 ? 0 : padded.length - bytes.length);
|
|
1635
|
+
bytes = padded;
|
|
1636
|
+
}
|
|
1637
|
+
if (bytes.length !== BYTES)
|
|
1638
|
+
throw new Error("Field.fromBytes: expected " + BYTES + " bytes, got " + bytes.length);
|
|
1639
|
+
let scalar = isLE2 ? bytesToNumberLE(bytes) : bytesToNumberBE(bytes);
|
|
1640
|
+
if (modFromBytes)
|
|
1641
|
+
scalar = mod(scalar, ORDER);
|
|
1642
|
+
if (!skipValidation) {
|
|
1643
|
+
if (!this.isValid(scalar))
|
|
1644
|
+
throw new Error("invalid field element: outside of range 0..ORDER");
|
|
1645
|
+
}
|
|
1646
|
+
return scalar;
|
|
1647
|
+
}
|
|
1648
|
+
// TODO: we don't need it here, move out to separate fn
|
|
1649
|
+
invertBatch(lst) {
|
|
1650
|
+
return FpInvertBatch(this, lst);
|
|
1651
|
+
}
|
|
1652
|
+
// We can't move this out because Fp6, Fp12 implement it
|
|
1653
|
+
// and it's unclear what to return in there.
|
|
1654
|
+
cmov(a, b, condition) {
|
|
1655
|
+
return condition ? b : a;
|
|
1656
|
+
}
|
|
1657
|
+
};
|
|
1658
|
+
function Field(ORDER, opts = {}) {
|
|
1659
|
+
return new _Field(ORDER, opts);
|
|
1660
|
+
}
|
|
1661
|
+
function getFieldBytesLength(fieldOrder) {
|
|
1662
|
+
if (typeof fieldOrder !== "bigint")
|
|
1663
|
+
throw new Error("field order must be bigint");
|
|
1664
|
+
const bitLength = fieldOrder.toString(2).length;
|
|
1665
|
+
return Math.ceil(bitLength / 8);
|
|
1666
|
+
}
|
|
1667
|
+
function getMinHashLength(fieldOrder) {
|
|
1668
|
+
const length = getFieldBytesLength(fieldOrder);
|
|
1669
|
+
return length + Math.ceil(length / 2);
|
|
1670
|
+
}
|
|
1671
|
+
function mapHashToField(key, fieldOrder, isLE2 = false) {
|
|
1672
|
+
abytes(key);
|
|
1673
|
+
const len = key.length;
|
|
1674
|
+
const fieldLen = getFieldBytesLength(fieldOrder);
|
|
1675
|
+
const minLen = getMinHashLength(fieldOrder);
|
|
1676
|
+
if (len < 16 || len < minLen || len > 1024)
|
|
1677
|
+
throw new Error("expected " + minLen + "-1024 bytes of input, got " + len);
|
|
1678
|
+
const num = isLE2 ? bytesToNumberLE(key) : bytesToNumberBE(key);
|
|
1679
|
+
const reduced = mod(num, fieldOrder - _1n3) + _1n3;
|
|
1680
|
+
return isLE2 ? numberToBytesLE(reduced, fieldLen) : numberToBytesBE(reduced, fieldLen);
|
|
1681
|
+
}
|
|
1682
|
+
|
|
1683
|
+
// node_modules/@noble/curves/abstract/curve.js
|
|
1684
|
+
var _0n4 = /* @__PURE__ */ BigInt(0);
|
|
1685
|
+
var _1n4 = /* @__PURE__ */ BigInt(1);
|
|
1686
|
+
function negateCt(condition, item) {
|
|
1687
|
+
const neg = item.negate();
|
|
1688
|
+
return condition ? neg : item;
|
|
1689
|
+
}
|
|
1690
|
+
function normalizeZ(c, points) {
|
|
1691
|
+
const invertedZs = FpInvertBatch(c.Fp, points.map((p) => p.Z));
|
|
1692
|
+
return points.map((p, i) => c.fromAffine(p.toAffine(invertedZs[i])));
|
|
1693
|
+
}
|
|
1694
|
+
function validateW(W, bits) {
|
|
1695
|
+
if (!Number.isSafeInteger(W) || W <= 0 || W > bits)
|
|
1696
|
+
throw new Error("invalid window size, expected [1.." + bits + "], got W=" + W);
|
|
1697
|
+
}
|
|
1698
|
+
function calcWOpts(W, scalarBits) {
|
|
1699
|
+
validateW(W, scalarBits);
|
|
1700
|
+
const windows = Math.ceil(scalarBits / W) + 1;
|
|
1701
|
+
const windowSize = 2 ** (W - 1);
|
|
1702
|
+
const maxNumber = 2 ** W;
|
|
1703
|
+
const mask = bitMask(W);
|
|
1704
|
+
const shiftBy = BigInt(W);
|
|
1705
|
+
return { windows, windowSize, mask, maxNumber, shiftBy };
|
|
1706
|
+
}
|
|
1707
|
+
function calcOffsets(n, window, wOpts) {
|
|
1708
|
+
const { windowSize, mask, maxNumber, shiftBy } = wOpts;
|
|
1709
|
+
let wbits = Number(n & mask);
|
|
1710
|
+
let nextN = n >> shiftBy;
|
|
1711
|
+
if (wbits > windowSize) {
|
|
1712
|
+
wbits -= maxNumber;
|
|
1713
|
+
nextN += _1n4;
|
|
1714
|
+
}
|
|
1715
|
+
const offsetStart = window * windowSize;
|
|
1716
|
+
const offset = offsetStart + Math.abs(wbits) - 1;
|
|
1717
|
+
const isZero = wbits === 0;
|
|
1718
|
+
const isNeg = wbits < 0;
|
|
1719
|
+
const isNegF = window % 2 !== 0;
|
|
1720
|
+
const offsetF = offsetStart;
|
|
1721
|
+
return { nextN, offset, isZero, isNeg, isNegF, offsetF };
|
|
1722
|
+
}
|
|
1723
|
+
var pointPrecomputes = /* @__PURE__ */ new WeakMap();
|
|
1724
|
+
var pointWindowSizes = /* @__PURE__ */ new WeakMap();
|
|
1725
|
+
function getW(P) {
|
|
1726
|
+
return pointWindowSizes.get(P) || 1;
|
|
1727
|
+
}
|
|
1728
|
+
function assert0(n) {
|
|
1729
|
+
if (n !== _0n4)
|
|
1730
|
+
throw new Error("invalid wNAF");
|
|
1731
|
+
}
|
|
1732
|
+
var wNAF = class {
|
|
1733
|
+
BASE;
|
|
1734
|
+
ZERO;
|
|
1735
|
+
Fn;
|
|
1736
|
+
bits;
|
|
1737
|
+
// Parametrized with a given Point class (not individual point)
|
|
1738
|
+
constructor(Point, bits) {
|
|
1739
|
+
this.BASE = Point.BASE;
|
|
1740
|
+
this.ZERO = Point.ZERO;
|
|
1741
|
+
this.Fn = Point.Fn;
|
|
1742
|
+
this.bits = bits;
|
|
1743
|
+
}
|
|
1744
|
+
// non-const time multiplication ladder
|
|
1745
|
+
_unsafeLadder(elm, n, p = this.ZERO) {
|
|
1746
|
+
let d = elm;
|
|
1747
|
+
while (n > _0n4) {
|
|
1748
|
+
if (n & _1n4)
|
|
1749
|
+
p = p.add(d);
|
|
1750
|
+
d = d.double();
|
|
1751
|
+
n >>= _1n4;
|
|
1752
|
+
}
|
|
1753
|
+
return p;
|
|
1754
|
+
}
|
|
1755
|
+
/**
|
|
1756
|
+
* Creates a wNAF precomputation window. Used for caching.
|
|
1757
|
+
* Default window size is set by `utils.precompute()` and is equal to 8.
|
|
1758
|
+
* Number of precomputed points depends on the curve size:
|
|
1759
|
+
* 2^(𝑊−1) * (Math.ceil(𝑛 / 𝑊) + 1), where:
|
|
1760
|
+
* - 𝑊 is the window size
|
|
1761
|
+
* - 𝑛 is the bitlength of the curve order.
|
|
1762
|
+
* For a 256-bit curve and window size 8, the number of precomputed points is 128 * 33 = 4224.
|
|
1763
|
+
* @param point Point instance
|
|
1764
|
+
* @param W window size
|
|
1765
|
+
* @returns precomputed point tables flattened to a single array
|
|
1766
|
+
*/
|
|
1767
|
+
precomputeWindow(point, W) {
|
|
1768
|
+
const { windows, windowSize } = calcWOpts(W, this.bits);
|
|
1769
|
+
const points = [];
|
|
1770
|
+
let p = point;
|
|
1771
|
+
let base = p;
|
|
1772
|
+
for (let window = 0; window < windows; window++) {
|
|
1773
|
+
base = p;
|
|
1774
|
+
points.push(base);
|
|
1775
|
+
for (let i = 1; i < windowSize; i++) {
|
|
1776
|
+
base = base.add(p);
|
|
1777
|
+
points.push(base);
|
|
1778
|
+
}
|
|
1779
|
+
p = base.double();
|
|
1780
|
+
}
|
|
1781
|
+
return points;
|
|
1782
|
+
}
|
|
1783
|
+
/**
|
|
1784
|
+
* Implements ec multiplication using precomputed tables and w-ary non-adjacent form.
|
|
1785
|
+
* More compact implementation:
|
|
1786
|
+
* https://github.com/paulmillr/noble-secp256k1/blob/47cb1669b6e506ad66b35fe7d76132ae97465da2/index.ts#L502-L541
|
|
1787
|
+
* @returns real and fake (for const-time) points
|
|
1788
|
+
*/
|
|
1789
|
+
wNAF(W, precomputes, n) {
|
|
1790
|
+
if (!this.Fn.isValid(n))
|
|
1791
|
+
throw new Error("invalid scalar");
|
|
1792
|
+
let p = this.ZERO;
|
|
1793
|
+
let f = this.BASE;
|
|
1794
|
+
const wo = calcWOpts(W, this.bits);
|
|
1795
|
+
for (let window = 0; window < wo.windows; window++) {
|
|
1796
|
+
const { nextN, offset, isZero, isNeg, isNegF, offsetF } = calcOffsets(n, window, wo);
|
|
1797
|
+
n = nextN;
|
|
1798
|
+
if (isZero) {
|
|
1799
|
+
f = f.add(negateCt(isNegF, precomputes[offsetF]));
|
|
1800
|
+
} else {
|
|
1801
|
+
p = p.add(negateCt(isNeg, precomputes[offset]));
|
|
1802
|
+
}
|
|
1803
|
+
}
|
|
1804
|
+
assert0(n);
|
|
1805
|
+
return { p, f };
|
|
1806
|
+
}
|
|
1807
|
+
/**
|
|
1808
|
+
* Implements ec unsafe (non const-time) multiplication using precomputed tables and w-ary non-adjacent form.
|
|
1809
|
+
* @param acc accumulator point to add result of multiplication
|
|
1810
|
+
* @returns point
|
|
1811
|
+
*/
|
|
1812
|
+
wNAFUnsafe(W, precomputes, n, acc = this.ZERO) {
|
|
1813
|
+
const wo = calcWOpts(W, this.bits);
|
|
1814
|
+
for (let window = 0; window < wo.windows; window++) {
|
|
1815
|
+
if (n === _0n4)
|
|
1816
|
+
break;
|
|
1817
|
+
const { nextN, offset, isZero, isNeg } = calcOffsets(n, window, wo);
|
|
1818
|
+
n = nextN;
|
|
1819
|
+
if (isZero) {
|
|
1820
|
+
continue;
|
|
1821
|
+
} else {
|
|
1822
|
+
const item = precomputes[offset];
|
|
1823
|
+
acc = acc.add(isNeg ? item.negate() : item);
|
|
1824
|
+
}
|
|
1825
|
+
}
|
|
1826
|
+
assert0(n);
|
|
1827
|
+
return acc;
|
|
1828
|
+
}
|
|
1829
|
+
getPrecomputes(W, point, transform) {
|
|
1830
|
+
let comp = pointPrecomputes.get(point);
|
|
1831
|
+
if (!comp) {
|
|
1832
|
+
comp = this.precomputeWindow(point, W);
|
|
1833
|
+
if (W !== 1) {
|
|
1834
|
+
if (typeof transform === "function")
|
|
1835
|
+
comp = transform(comp);
|
|
1836
|
+
pointPrecomputes.set(point, comp);
|
|
1837
|
+
}
|
|
1838
|
+
}
|
|
1839
|
+
return comp;
|
|
1840
|
+
}
|
|
1841
|
+
cached(point, scalar, transform) {
|
|
1842
|
+
const W = getW(point);
|
|
1843
|
+
return this.wNAF(W, this.getPrecomputes(W, point, transform), scalar);
|
|
1844
|
+
}
|
|
1845
|
+
unsafe(point, scalar, transform, prev) {
|
|
1846
|
+
const W = getW(point);
|
|
1847
|
+
if (W === 1)
|
|
1848
|
+
return this._unsafeLadder(point, scalar, prev);
|
|
1849
|
+
return this.wNAFUnsafe(W, this.getPrecomputes(W, point, transform), scalar, prev);
|
|
1850
|
+
}
|
|
1851
|
+
// We calculate precomputes for elliptic curve point multiplication
|
|
1852
|
+
// using windowed method. This specifies window size and
|
|
1853
|
+
// stores precomputed values. Usually only base point would be precomputed.
|
|
1854
|
+
createCache(P, W) {
|
|
1855
|
+
validateW(W, this.bits);
|
|
1856
|
+
pointWindowSizes.set(P, W);
|
|
1857
|
+
pointPrecomputes.delete(P);
|
|
1858
|
+
}
|
|
1859
|
+
hasCache(elm) {
|
|
1860
|
+
return getW(elm) !== 1;
|
|
1861
|
+
}
|
|
1862
|
+
};
|
|
1863
|
+
function mulEndoUnsafe(Point, point, k1, k2) {
|
|
1864
|
+
let acc = point;
|
|
1865
|
+
let p1 = Point.ZERO;
|
|
1866
|
+
let p2 = Point.ZERO;
|
|
1867
|
+
while (k1 > _0n4 || k2 > _0n4) {
|
|
1868
|
+
if (k1 & _1n4)
|
|
1869
|
+
p1 = p1.add(acc);
|
|
1870
|
+
if (k2 & _1n4)
|
|
1871
|
+
p2 = p2.add(acc);
|
|
1872
|
+
acc = acc.double();
|
|
1873
|
+
k1 >>= _1n4;
|
|
1874
|
+
k2 >>= _1n4;
|
|
1875
|
+
}
|
|
1876
|
+
return { p1, p2 };
|
|
1877
|
+
}
|
|
1878
|
+
function createField(order, field, isLE2) {
|
|
1879
|
+
if (field) {
|
|
1880
|
+
if (field.ORDER !== order)
|
|
1881
|
+
throw new Error("Field.ORDER must match order: Fp == p, Fn == n");
|
|
1882
|
+
validateField(field);
|
|
1883
|
+
return field;
|
|
1884
|
+
} else {
|
|
1885
|
+
return Field(order, { isLE: isLE2 });
|
|
1886
|
+
}
|
|
1887
|
+
}
|
|
1888
|
+
function createCurveFields(type, CURVE, curveOpts = {}, FpFnLE) {
|
|
1889
|
+
if (FpFnLE === void 0)
|
|
1890
|
+
FpFnLE = type === "edwards";
|
|
1891
|
+
if (!CURVE || typeof CURVE !== "object")
|
|
1892
|
+
throw new Error(`expected valid ${type} CURVE object`);
|
|
1893
|
+
for (const p of ["p", "n", "h"]) {
|
|
1894
|
+
const val = CURVE[p];
|
|
1895
|
+
if (!(typeof val === "bigint" && val > _0n4))
|
|
1896
|
+
throw new Error(`CURVE.${p} must be positive bigint`);
|
|
1897
|
+
}
|
|
1898
|
+
const Fp = createField(CURVE.p, curveOpts.Fp, FpFnLE);
|
|
1899
|
+
const Fn = createField(CURVE.n, curveOpts.Fn, FpFnLE);
|
|
1900
|
+
const _b = type === "weierstrass" ? "b" : "d";
|
|
1901
|
+
const params = ["Gx", "Gy", "a", _b];
|
|
1902
|
+
for (const p of params) {
|
|
1903
|
+
if (!Fp.isValid(CURVE[p]))
|
|
1904
|
+
throw new Error(`CURVE.${p} must be valid field element of CURVE.Fp`);
|
|
1905
|
+
}
|
|
1906
|
+
CURVE = Object.freeze(Object.assign({}, CURVE));
|
|
1907
|
+
return { CURVE, Fp, Fn };
|
|
1908
|
+
}
|
|
1909
|
+
function createKeygen(randomSecretKey, getPublicKey) {
|
|
1910
|
+
return function keygen(seed) {
|
|
1911
|
+
const secretKey = randomSecretKey(seed);
|
|
1912
|
+
return { secretKey, publicKey: getPublicKey(secretKey) };
|
|
1913
|
+
};
|
|
1914
|
+
}
|
|
1915
|
+
|
|
1916
|
+
// node_modules/@noble/hashes/hmac.js
|
|
1917
|
+
var _HMAC = class {
|
|
1918
|
+
oHash;
|
|
1919
|
+
iHash;
|
|
1920
|
+
blockLen;
|
|
1921
|
+
outputLen;
|
|
1922
|
+
finished = false;
|
|
1923
|
+
destroyed = false;
|
|
1924
|
+
constructor(hash, key) {
|
|
1925
|
+
ahash(hash);
|
|
1926
|
+
abytes(key, void 0, "key");
|
|
1927
|
+
this.iHash = hash.create();
|
|
1928
|
+
if (typeof this.iHash.update !== "function")
|
|
1929
|
+
throw new Error("Expected instance of class which extends utils.Hash");
|
|
1930
|
+
this.blockLen = this.iHash.blockLen;
|
|
1931
|
+
this.outputLen = this.iHash.outputLen;
|
|
1932
|
+
const blockLen = this.blockLen;
|
|
1933
|
+
const pad = new Uint8Array(blockLen);
|
|
1934
|
+
pad.set(key.length > blockLen ? hash.create().update(key).digest() : key);
|
|
1935
|
+
for (let i = 0; i < pad.length; i++)
|
|
1936
|
+
pad[i] ^= 54;
|
|
1937
|
+
this.iHash.update(pad);
|
|
1938
|
+
this.oHash = hash.create();
|
|
1939
|
+
for (let i = 0; i < pad.length; i++)
|
|
1940
|
+
pad[i] ^= 54 ^ 92;
|
|
1941
|
+
this.oHash.update(pad);
|
|
1942
|
+
clean(pad);
|
|
1943
|
+
}
|
|
1944
|
+
update(buf) {
|
|
1945
|
+
aexists(this);
|
|
1946
|
+
this.iHash.update(buf);
|
|
1947
|
+
return this;
|
|
1948
|
+
}
|
|
1949
|
+
digestInto(out) {
|
|
1950
|
+
aexists(this);
|
|
1951
|
+
abytes(out, this.outputLen, "output");
|
|
1952
|
+
this.finished = true;
|
|
1953
|
+
this.iHash.digestInto(out);
|
|
1954
|
+
this.oHash.update(out);
|
|
1955
|
+
this.oHash.digestInto(out);
|
|
1956
|
+
this.destroy();
|
|
1957
|
+
}
|
|
1958
|
+
digest() {
|
|
1959
|
+
const out = new Uint8Array(this.oHash.outputLen);
|
|
1960
|
+
this.digestInto(out);
|
|
1961
|
+
return out;
|
|
1962
|
+
}
|
|
1963
|
+
_cloneInto(to) {
|
|
1964
|
+
to ||= Object.create(Object.getPrototypeOf(this), {});
|
|
1965
|
+
const { oHash, iHash, finished, destroyed, blockLen, outputLen } = this;
|
|
1966
|
+
to = to;
|
|
1967
|
+
to.finished = finished;
|
|
1968
|
+
to.destroyed = destroyed;
|
|
1969
|
+
to.blockLen = blockLen;
|
|
1970
|
+
to.outputLen = outputLen;
|
|
1971
|
+
to.oHash = oHash._cloneInto(to.oHash);
|
|
1972
|
+
to.iHash = iHash._cloneInto(to.iHash);
|
|
1973
|
+
return to;
|
|
1974
|
+
}
|
|
1975
|
+
clone() {
|
|
1976
|
+
return this._cloneInto();
|
|
1977
|
+
}
|
|
1978
|
+
destroy() {
|
|
1979
|
+
this.destroyed = true;
|
|
1980
|
+
this.oHash.destroy();
|
|
1981
|
+
this.iHash.destroy();
|
|
1982
|
+
}
|
|
1983
|
+
};
|
|
1984
|
+
var hmac = (hash, key, message) => new _HMAC(hash, key).update(message).digest();
|
|
1985
|
+
hmac.create = (hash, key) => new _HMAC(hash, key);
|
|
1986
|
+
|
|
1987
|
+
// node_modules/@noble/curves/abstract/weierstrass.js
|
|
1988
|
+
var divNearest = (num, den) => (num + (num >= 0 ? den : -den) / _2n3) / den;
|
|
1989
|
+
function _splitEndoScalar(k, basis, n) {
|
|
1990
|
+
const [[a1, b1], [a2, b2]] = basis;
|
|
1991
|
+
const c1 = divNearest(b2 * k, n);
|
|
1992
|
+
const c2 = divNearest(-b1 * k, n);
|
|
1993
|
+
let k1 = k - c1 * a1 - c2 * a2;
|
|
1994
|
+
let k2 = -c1 * b1 - c2 * b2;
|
|
1995
|
+
const k1neg = k1 < _0n5;
|
|
1996
|
+
const k2neg = k2 < _0n5;
|
|
1997
|
+
if (k1neg)
|
|
1998
|
+
k1 = -k1;
|
|
1999
|
+
if (k2neg)
|
|
2000
|
+
k2 = -k2;
|
|
2001
|
+
const MAX_NUM = bitMask(Math.ceil(bitLen(n) / 2)) + _1n5;
|
|
2002
|
+
if (k1 < _0n5 || k1 >= MAX_NUM || k2 < _0n5 || k2 >= MAX_NUM) {
|
|
2003
|
+
throw new Error("splitScalar (endomorphism): failed, k=" + k);
|
|
2004
|
+
}
|
|
2005
|
+
return { k1neg, k1, k2neg, k2 };
|
|
2006
|
+
}
|
|
2007
|
+
function validateSigFormat(format) {
|
|
2008
|
+
if (!["compact", "recovered", "der"].includes(format))
|
|
2009
|
+
throw new Error('Signature format must be "compact", "recovered", or "der"');
|
|
2010
|
+
return format;
|
|
2011
|
+
}
|
|
2012
|
+
function validateSigOpts(opts, def) {
|
|
2013
|
+
const optsn = {};
|
|
2014
|
+
for (let optName of Object.keys(def)) {
|
|
2015
|
+
optsn[optName] = opts[optName] === void 0 ? def[optName] : opts[optName];
|
|
2016
|
+
}
|
|
2017
|
+
abool(optsn.lowS, "lowS");
|
|
2018
|
+
abool(optsn.prehash, "prehash");
|
|
2019
|
+
if (optsn.format !== void 0)
|
|
2020
|
+
validateSigFormat(optsn.format);
|
|
2021
|
+
return optsn;
|
|
2022
|
+
}
|
|
2023
|
+
var DERErr = class extends Error {
|
|
2024
|
+
constructor(m = "") {
|
|
2025
|
+
super(m);
|
|
2026
|
+
}
|
|
2027
|
+
};
|
|
2028
|
+
var DER = {
|
|
2029
|
+
// asn.1 DER encoding utils
|
|
2030
|
+
Err: DERErr,
|
|
2031
|
+
// Basic building block is TLV (Tag-Length-Value)
|
|
2032
|
+
_tlv: {
|
|
2033
|
+
encode: (tag, data) => {
|
|
2034
|
+
const { Err: E } = DER;
|
|
2035
|
+
if (tag < 0 || tag > 256)
|
|
2036
|
+
throw new E("tlv.encode: wrong tag");
|
|
2037
|
+
if (data.length & 1)
|
|
2038
|
+
throw new E("tlv.encode: unpadded data");
|
|
2039
|
+
const dataLen = data.length / 2;
|
|
2040
|
+
const len = numberToHexUnpadded(dataLen);
|
|
2041
|
+
if (len.length / 2 & 128)
|
|
2042
|
+
throw new E("tlv.encode: long form length too big");
|
|
2043
|
+
const lenLen = dataLen > 127 ? numberToHexUnpadded(len.length / 2 | 128) : "";
|
|
2044
|
+
const t = numberToHexUnpadded(tag);
|
|
2045
|
+
return t + lenLen + len + data;
|
|
2046
|
+
},
|
|
2047
|
+
// v - value, l - left bytes (unparsed)
|
|
2048
|
+
decode(tag, data) {
|
|
2049
|
+
const { Err: E } = DER;
|
|
2050
|
+
let pos = 0;
|
|
2051
|
+
if (tag < 0 || tag > 256)
|
|
2052
|
+
throw new E("tlv.encode: wrong tag");
|
|
2053
|
+
if (data.length < 2 || data[pos++] !== tag)
|
|
2054
|
+
throw new E("tlv.decode: wrong tlv");
|
|
2055
|
+
const first = data[pos++];
|
|
2056
|
+
const isLong = !!(first & 128);
|
|
2057
|
+
let length = 0;
|
|
2058
|
+
if (!isLong)
|
|
2059
|
+
length = first;
|
|
2060
|
+
else {
|
|
2061
|
+
const lenLen = first & 127;
|
|
2062
|
+
if (!lenLen)
|
|
2063
|
+
throw new E("tlv.decode(long): indefinite length not supported");
|
|
2064
|
+
if (lenLen > 4)
|
|
2065
|
+
throw new E("tlv.decode(long): byte length is too big");
|
|
2066
|
+
const lengthBytes = data.subarray(pos, pos + lenLen);
|
|
2067
|
+
if (lengthBytes.length !== lenLen)
|
|
2068
|
+
throw new E("tlv.decode: length bytes not complete");
|
|
2069
|
+
if (lengthBytes[0] === 0)
|
|
2070
|
+
throw new E("tlv.decode(long): zero leftmost byte");
|
|
2071
|
+
for (const b of lengthBytes)
|
|
2072
|
+
length = length << 8 | b;
|
|
2073
|
+
pos += lenLen;
|
|
2074
|
+
if (length < 128)
|
|
2075
|
+
throw new E("tlv.decode(long): not minimal encoding");
|
|
2076
|
+
}
|
|
2077
|
+
const v = data.subarray(pos, pos + length);
|
|
2078
|
+
if (v.length !== length)
|
|
2079
|
+
throw new E("tlv.decode: wrong value length");
|
|
2080
|
+
return { v, l: data.subarray(pos + length) };
|
|
2081
|
+
}
|
|
2082
|
+
},
|
|
2083
|
+
// https://crypto.stackexchange.com/a/57734 Leftmost bit of first byte is 'negative' flag,
|
|
2084
|
+
// since we always use positive integers here. It must always be empty:
|
|
2085
|
+
// - add zero byte if exists
|
|
2086
|
+
// - if next byte doesn't have a flag, leading zero is not allowed (minimal encoding)
|
|
2087
|
+
_int: {
|
|
2088
|
+
encode(num) {
|
|
2089
|
+
const { Err: E } = DER;
|
|
2090
|
+
if (num < _0n5)
|
|
2091
|
+
throw new E("integer: negative integers are not allowed");
|
|
2092
|
+
let hex = numberToHexUnpadded(num);
|
|
2093
|
+
if (Number.parseInt(hex[0], 16) & 8)
|
|
2094
|
+
hex = "00" + hex;
|
|
2095
|
+
if (hex.length & 1)
|
|
2096
|
+
throw new E("unexpected DER parsing assertion: unpadded hex");
|
|
2097
|
+
return hex;
|
|
2098
|
+
},
|
|
2099
|
+
decode(data) {
|
|
2100
|
+
const { Err: E } = DER;
|
|
2101
|
+
if (data[0] & 128)
|
|
2102
|
+
throw new E("invalid signature integer: negative");
|
|
2103
|
+
if (data[0] === 0 && !(data[1] & 128))
|
|
2104
|
+
throw new E("invalid signature integer: unnecessary leading zero");
|
|
2105
|
+
return bytesToNumberBE(data);
|
|
2106
|
+
}
|
|
2107
|
+
},
|
|
2108
|
+
toSig(bytes) {
|
|
2109
|
+
const { Err: E, _int: int, _tlv: tlv } = DER;
|
|
2110
|
+
const data = abytes(bytes, void 0, "signature");
|
|
2111
|
+
const { v: seqBytes, l: seqLeftBytes } = tlv.decode(48, data);
|
|
2112
|
+
if (seqLeftBytes.length)
|
|
2113
|
+
throw new E("invalid signature: left bytes after parsing");
|
|
2114
|
+
const { v: rBytes, l: rLeftBytes } = tlv.decode(2, seqBytes);
|
|
2115
|
+
const { v: sBytes, l: sLeftBytes } = tlv.decode(2, rLeftBytes);
|
|
2116
|
+
if (sLeftBytes.length)
|
|
2117
|
+
throw new E("invalid signature: left bytes after parsing");
|
|
2118
|
+
return { r: int.decode(rBytes), s: int.decode(sBytes) };
|
|
2119
|
+
},
|
|
2120
|
+
hexFromSig(sig) {
|
|
2121
|
+
const { _tlv: tlv, _int: int } = DER;
|
|
2122
|
+
const rs = tlv.encode(2, int.encode(sig.r));
|
|
2123
|
+
const ss = tlv.encode(2, int.encode(sig.s));
|
|
2124
|
+
const seq = rs + ss;
|
|
2125
|
+
return tlv.encode(48, seq);
|
|
2126
|
+
}
|
|
2127
|
+
};
|
|
2128
|
+
var _0n5 = BigInt(0);
|
|
2129
|
+
var _1n5 = BigInt(1);
|
|
2130
|
+
var _2n3 = BigInt(2);
|
|
2131
|
+
var _3n2 = BigInt(3);
|
|
2132
|
+
var _4n2 = BigInt(4);
|
|
2133
|
+
function weierstrass(params, extraOpts = {}) {
|
|
2134
|
+
const validated = createCurveFields("weierstrass", params, extraOpts);
|
|
2135
|
+
const { Fp, Fn } = validated;
|
|
2136
|
+
let CURVE = validated.CURVE;
|
|
2137
|
+
const { h: cofactor, n: CURVE_ORDER } = CURVE;
|
|
2138
|
+
validateObject(extraOpts, {}, {
|
|
2139
|
+
allowInfinityPoint: "boolean",
|
|
2140
|
+
clearCofactor: "function",
|
|
2141
|
+
isTorsionFree: "function",
|
|
2142
|
+
fromBytes: "function",
|
|
2143
|
+
toBytes: "function",
|
|
2144
|
+
endo: "object"
|
|
2145
|
+
});
|
|
2146
|
+
const { endo } = extraOpts;
|
|
2147
|
+
if (endo) {
|
|
2148
|
+
if (!Fp.is0(CURVE.a) || typeof endo.beta !== "bigint" || !Array.isArray(endo.basises)) {
|
|
2149
|
+
throw new Error('invalid endo: expected "beta": bigint and "basises": array');
|
|
2150
|
+
}
|
|
2151
|
+
}
|
|
2152
|
+
const lengths = getWLengths(Fp, Fn);
|
|
2153
|
+
function assertCompressionIsSupported() {
|
|
2154
|
+
if (!Fp.isOdd)
|
|
2155
|
+
throw new Error("compression is not supported: Field does not have .isOdd()");
|
|
2156
|
+
}
|
|
2157
|
+
function pointToBytes(_c, point, isCompressed) {
|
|
2158
|
+
const { x, y } = point.toAffine();
|
|
2159
|
+
const bx = Fp.toBytes(x);
|
|
2160
|
+
abool(isCompressed, "isCompressed");
|
|
2161
|
+
if (isCompressed) {
|
|
2162
|
+
assertCompressionIsSupported();
|
|
2163
|
+
const hasEvenY = !Fp.isOdd(y);
|
|
2164
|
+
return concatBytes(pprefix(hasEvenY), bx);
|
|
2165
|
+
} else {
|
|
2166
|
+
return concatBytes(Uint8Array.of(4), bx, Fp.toBytes(y));
|
|
2167
|
+
}
|
|
2168
|
+
}
|
|
2169
|
+
function pointFromBytes(bytes) {
|
|
2170
|
+
abytes(bytes, void 0, "Point");
|
|
2171
|
+
const { publicKey: comp, publicKeyUncompressed: uncomp } = lengths;
|
|
2172
|
+
const length = bytes.length;
|
|
2173
|
+
const head = bytes[0];
|
|
2174
|
+
const tail = bytes.subarray(1);
|
|
2175
|
+
if (length === comp && (head === 2 || head === 3)) {
|
|
2176
|
+
const x = Fp.fromBytes(tail);
|
|
2177
|
+
if (!Fp.isValid(x))
|
|
2178
|
+
throw new Error("bad point: is not on curve, wrong x");
|
|
2179
|
+
const y2 = weierstrassEquation(x);
|
|
2180
|
+
let y;
|
|
2181
|
+
try {
|
|
2182
|
+
y = Fp.sqrt(y2);
|
|
2183
|
+
} catch (sqrtError) {
|
|
2184
|
+
const err = sqrtError instanceof Error ? ": " + sqrtError.message : "";
|
|
2185
|
+
throw new Error("bad point: is not on curve, sqrt error" + err);
|
|
2186
|
+
}
|
|
2187
|
+
assertCompressionIsSupported();
|
|
2188
|
+
const evenY = Fp.isOdd(y);
|
|
2189
|
+
const evenH = (head & 1) === 1;
|
|
2190
|
+
if (evenH !== evenY)
|
|
2191
|
+
y = Fp.neg(y);
|
|
2192
|
+
return { x, y };
|
|
2193
|
+
} else if (length === uncomp && head === 4) {
|
|
2194
|
+
const L = Fp.BYTES;
|
|
2195
|
+
const x = Fp.fromBytes(tail.subarray(0, L));
|
|
2196
|
+
const y = Fp.fromBytes(tail.subarray(L, L * 2));
|
|
2197
|
+
if (!isValidXY(x, y))
|
|
2198
|
+
throw new Error("bad point: is not on curve");
|
|
2199
|
+
return { x, y };
|
|
2200
|
+
} else {
|
|
2201
|
+
throw new Error(`bad point: got length ${length}, expected compressed=${comp} or uncompressed=${uncomp}`);
|
|
2202
|
+
}
|
|
2203
|
+
}
|
|
2204
|
+
const encodePoint = extraOpts.toBytes || pointToBytes;
|
|
2205
|
+
const decodePoint = extraOpts.fromBytes || pointFromBytes;
|
|
2206
|
+
function weierstrassEquation(x) {
|
|
2207
|
+
const x2 = Fp.sqr(x);
|
|
2208
|
+
const x3 = Fp.mul(x2, x);
|
|
2209
|
+
return Fp.add(Fp.add(x3, Fp.mul(x, CURVE.a)), CURVE.b);
|
|
2210
|
+
}
|
|
2211
|
+
function isValidXY(x, y) {
|
|
2212
|
+
const left = Fp.sqr(y);
|
|
2213
|
+
const right = weierstrassEquation(x);
|
|
2214
|
+
return Fp.eql(left, right);
|
|
2215
|
+
}
|
|
2216
|
+
if (!isValidXY(CURVE.Gx, CURVE.Gy))
|
|
2217
|
+
throw new Error("bad curve params: generator point");
|
|
2218
|
+
const _4a3 = Fp.mul(Fp.pow(CURVE.a, _3n2), _4n2);
|
|
2219
|
+
const _27b2 = Fp.mul(Fp.sqr(CURVE.b), BigInt(27));
|
|
2220
|
+
if (Fp.is0(Fp.add(_4a3, _27b2)))
|
|
2221
|
+
throw new Error("bad curve params: a or b");
|
|
2222
|
+
function acoord(title, n, banZero = false) {
|
|
2223
|
+
if (!Fp.isValid(n) || banZero && Fp.is0(n))
|
|
2224
|
+
throw new Error(`bad point coordinate ${title}`);
|
|
2225
|
+
return n;
|
|
2226
|
+
}
|
|
2227
|
+
function aprjpoint(other) {
|
|
2228
|
+
if (!(other instanceof Point))
|
|
2229
|
+
throw new Error("Weierstrass Point expected");
|
|
2230
|
+
}
|
|
2231
|
+
function splitEndoScalarN(k) {
|
|
2232
|
+
if (!endo || !endo.basises)
|
|
2233
|
+
throw new Error("no endo");
|
|
2234
|
+
return _splitEndoScalar(k, endo.basises, Fn.ORDER);
|
|
2235
|
+
}
|
|
2236
|
+
const toAffineMemo = memoized((p, iz) => {
|
|
2237
|
+
const { X, Y, Z } = p;
|
|
2238
|
+
if (Fp.eql(Z, Fp.ONE))
|
|
2239
|
+
return { x: X, y: Y };
|
|
2240
|
+
const is0 = p.is0();
|
|
2241
|
+
if (iz == null)
|
|
2242
|
+
iz = is0 ? Fp.ONE : Fp.inv(Z);
|
|
2243
|
+
const x = Fp.mul(X, iz);
|
|
2244
|
+
const y = Fp.mul(Y, iz);
|
|
2245
|
+
const zz = Fp.mul(Z, iz);
|
|
2246
|
+
if (is0)
|
|
2247
|
+
return { x: Fp.ZERO, y: Fp.ZERO };
|
|
2248
|
+
if (!Fp.eql(zz, Fp.ONE))
|
|
2249
|
+
throw new Error("invZ was invalid");
|
|
2250
|
+
return { x, y };
|
|
2251
|
+
});
|
|
2252
|
+
const assertValidMemo = memoized((p) => {
|
|
2253
|
+
if (p.is0()) {
|
|
2254
|
+
if (extraOpts.allowInfinityPoint && !Fp.is0(p.Y))
|
|
2255
|
+
return;
|
|
2256
|
+
throw new Error("bad point: ZERO");
|
|
2257
|
+
}
|
|
2258
|
+
const { x, y } = p.toAffine();
|
|
2259
|
+
if (!Fp.isValid(x) || !Fp.isValid(y))
|
|
2260
|
+
throw new Error("bad point: x or y not field elements");
|
|
2261
|
+
if (!isValidXY(x, y))
|
|
2262
|
+
throw new Error("bad point: equation left != right");
|
|
2263
|
+
if (!p.isTorsionFree())
|
|
2264
|
+
throw new Error("bad point: not in prime-order subgroup");
|
|
2265
|
+
return true;
|
|
2266
|
+
});
|
|
2267
|
+
function finishEndo(endoBeta, k1p, k2p, k1neg, k2neg) {
|
|
2268
|
+
k2p = new Point(Fp.mul(k2p.X, endoBeta), k2p.Y, k2p.Z);
|
|
2269
|
+
k1p = negateCt(k1neg, k1p);
|
|
2270
|
+
k2p = negateCt(k2neg, k2p);
|
|
2271
|
+
return k1p.add(k2p);
|
|
2272
|
+
}
|
|
2273
|
+
class Point {
|
|
2274
|
+
// base / generator point
|
|
2275
|
+
static BASE = new Point(CURVE.Gx, CURVE.Gy, Fp.ONE);
|
|
2276
|
+
// zero / infinity / identity point
|
|
2277
|
+
static ZERO = new Point(Fp.ZERO, Fp.ONE, Fp.ZERO);
|
|
2278
|
+
// 0, 1, 0
|
|
2279
|
+
// math field
|
|
2280
|
+
static Fp = Fp;
|
|
2281
|
+
// scalar field
|
|
2282
|
+
static Fn = Fn;
|
|
2283
|
+
X;
|
|
2284
|
+
Y;
|
|
2285
|
+
Z;
|
|
2286
|
+
/** Does NOT validate if the point is valid. Use `.assertValidity()`. */
|
|
2287
|
+
constructor(X, Y, Z) {
|
|
2288
|
+
this.X = acoord("x", X);
|
|
2289
|
+
this.Y = acoord("y", Y, true);
|
|
2290
|
+
this.Z = acoord("z", Z);
|
|
2291
|
+
Object.freeze(this);
|
|
2292
|
+
}
|
|
2293
|
+
static CURVE() {
|
|
2294
|
+
return CURVE;
|
|
2295
|
+
}
|
|
2296
|
+
/** Does NOT validate if the point is valid. Use `.assertValidity()`. */
|
|
2297
|
+
static fromAffine(p) {
|
|
2298
|
+
const { x, y } = p || {};
|
|
2299
|
+
if (!p || !Fp.isValid(x) || !Fp.isValid(y))
|
|
2300
|
+
throw new Error("invalid affine point");
|
|
2301
|
+
if (p instanceof Point)
|
|
2302
|
+
throw new Error("projective point not allowed");
|
|
2303
|
+
if (Fp.is0(x) && Fp.is0(y))
|
|
2304
|
+
return Point.ZERO;
|
|
2305
|
+
return new Point(x, y, Fp.ONE);
|
|
2306
|
+
}
|
|
2307
|
+
static fromBytes(bytes) {
|
|
2308
|
+
const P = Point.fromAffine(decodePoint(abytes(bytes, void 0, "point")));
|
|
2309
|
+
P.assertValidity();
|
|
2310
|
+
return P;
|
|
2311
|
+
}
|
|
2312
|
+
static fromHex(hex) {
|
|
2313
|
+
return Point.fromBytes(hexToBytes(hex));
|
|
2314
|
+
}
|
|
2315
|
+
get x() {
|
|
2316
|
+
return this.toAffine().x;
|
|
2317
|
+
}
|
|
2318
|
+
get y() {
|
|
2319
|
+
return this.toAffine().y;
|
|
2320
|
+
}
|
|
2321
|
+
/**
|
|
2322
|
+
*
|
|
2323
|
+
* @param windowSize
|
|
2324
|
+
* @param isLazy true will defer table computation until the first multiplication
|
|
2325
|
+
* @returns
|
|
2326
|
+
*/
|
|
2327
|
+
precompute(windowSize = 8, isLazy = true) {
|
|
2328
|
+
wnaf.createCache(this, windowSize);
|
|
2329
|
+
if (!isLazy)
|
|
2330
|
+
this.multiply(_3n2);
|
|
2331
|
+
return this;
|
|
2332
|
+
}
|
|
2333
|
+
// TODO: return `this`
|
|
2334
|
+
/** A point on curve is valid if it conforms to equation. */
|
|
2335
|
+
assertValidity() {
|
|
2336
|
+
assertValidMemo(this);
|
|
2337
|
+
}
|
|
2338
|
+
hasEvenY() {
|
|
2339
|
+
const { y } = this.toAffine();
|
|
2340
|
+
if (!Fp.isOdd)
|
|
2341
|
+
throw new Error("Field doesn't support isOdd");
|
|
2342
|
+
return !Fp.isOdd(y);
|
|
2343
|
+
}
|
|
2344
|
+
/** Compare one point to another. */
|
|
2345
|
+
equals(other) {
|
|
2346
|
+
aprjpoint(other);
|
|
2347
|
+
const { X: X1, Y: Y1, Z: Z1 } = this;
|
|
2348
|
+
const { X: X2, Y: Y2, Z: Z2 } = other;
|
|
2349
|
+
const U1 = Fp.eql(Fp.mul(X1, Z2), Fp.mul(X2, Z1));
|
|
2350
|
+
const U2 = Fp.eql(Fp.mul(Y1, Z2), Fp.mul(Y2, Z1));
|
|
2351
|
+
return U1 && U2;
|
|
2352
|
+
}
|
|
2353
|
+
/** Flips point to one corresponding to (x, -y) in Affine coordinates. */
|
|
2354
|
+
negate() {
|
|
2355
|
+
return new Point(this.X, Fp.neg(this.Y), this.Z);
|
|
2356
|
+
}
|
|
2357
|
+
// Renes-Costello-Batina exception-free doubling formula.
|
|
2358
|
+
// There is 30% faster Jacobian formula, but it is not complete.
|
|
2359
|
+
// https://eprint.iacr.org/2015/1060, algorithm 3
|
|
2360
|
+
// Cost: 8M + 3S + 3*a + 2*b3 + 15add.
|
|
2361
|
+
double() {
|
|
2362
|
+
const { a, b } = CURVE;
|
|
2363
|
+
const b3 = Fp.mul(b, _3n2);
|
|
2364
|
+
const { X: X1, Y: Y1, Z: Z1 } = this;
|
|
2365
|
+
let X3 = Fp.ZERO, Y3 = Fp.ZERO, Z3 = Fp.ZERO;
|
|
2366
|
+
let t0 = Fp.mul(X1, X1);
|
|
2367
|
+
let t1 = Fp.mul(Y1, Y1);
|
|
2368
|
+
let t2 = Fp.mul(Z1, Z1);
|
|
2369
|
+
let t3 = Fp.mul(X1, Y1);
|
|
2370
|
+
t3 = Fp.add(t3, t3);
|
|
2371
|
+
Z3 = Fp.mul(X1, Z1);
|
|
2372
|
+
Z3 = Fp.add(Z3, Z3);
|
|
2373
|
+
X3 = Fp.mul(a, Z3);
|
|
2374
|
+
Y3 = Fp.mul(b3, t2);
|
|
2375
|
+
Y3 = Fp.add(X3, Y3);
|
|
2376
|
+
X3 = Fp.sub(t1, Y3);
|
|
2377
|
+
Y3 = Fp.add(t1, Y3);
|
|
2378
|
+
Y3 = Fp.mul(X3, Y3);
|
|
2379
|
+
X3 = Fp.mul(t3, X3);
|
|
2380
|
+
Z3 = Fp.mul(b3, Z3);
|
|
2381
|
+
t2 = Fp.mul(a, t2);
|
|
2382
|
+
t3 = Fp.sub(t0, t2);
|
|
2383
|
+
t3 = Fp.mul(a, t3);
|
|
2384
|
+
t3 = Fp.add(t3, Z3);
|
|
2385
|
+
Z3 = Fp.add(t0, t0);
|
|
2386
|
+
t0 = Fp.add(Z3, t0);
|
|
2387
|
+
t0 = Fp.add(t0, t2);
|
|
2388
|
+
t0 = Fp.mul(t0, t3);
|
|
2389
|
+
Y3 = Fp.add(Y3, t0);
|
|
2390
|
+
t2 = Fp.mul(Y1, Z1);
|
|
2391
|
+
t2 = Fp.add(t2, t2);
|
|
2392
|
+
t0 = Fp.mul(t2, t3);
|
|
2393
|
+
X3 = Fp.sub(X3, t0);
|
|
2394
|
+
Z3 = Fp.mul(t2, t1);
|
|
2395
|
+
Z3 = Fp.add(Z3, Z3);
|
|
2396
|
+
Z3 = Fp.add(Z3, Z3);
|
|
2397
|
+
return new Point(X3, Y3, Z3);
|
|
2398
|
+
}
|
|
2399
|
+
// Renes-Costello-Batina exception-free addition formula.
|
|
2400
|
+
// There is 30% faster Jacobian formula, but it is not complete.
|
|
2401
|
+
// https://eprint.iacr.org/2015/1060, algorithm 1
|
|
2402
|
+
// Cost: 12M + 0S + 3*a + 3*b3 + 23add.
|
|
2403
|
+
add(other) {
|
|
2404
|
+
aprjpoint(other);
|
|
2405
|
+
const { X: X1, Y: Y1, Z: Z1 } = this;
|
|
2406
|
+
const { X: X2, Y: Y2, Z: Z2 } = other;
|
|
2407
|
+
let X3 = Fp.ZERO, Y3 = Fp.ZERO, Z3 = Fp.ZERO;
|
|
2408
|
+
const a = CURVE.a;
|
|
2409
|
+
const b3 = Fp.mul(CURVE.b, _3n2);
|
|
2410
|
+
let t0 = Fp.mul(X1, X2);
|
|
2411
|
+
let t1 = Fp.mul(Y1, Y2);
|
|
2412
|
+
let t2 = Fp.mul(Z1, Z2);
|
|
2413
|
+
let t3 = Fp.add(X1, Y1);
|
|
2414
|
+
let t4 = Fp.add(X2, Y2);
|
|
2415
|
+
t3 = Fp.mul(t3, t4);
|
|
2416
|
+
t4 = Fp.add(t0, t1);
|
|
2417
|
+
t3 = Fp.sub(t3, t4);
|
|
2418
|
+
t4 = Fp.add(X1, Z1);
|
|
2419
|
+
let t5 = Fp.add(X2, Z2);
|
|
2420
|
+
t4 = Fp.mul(t4, t5);
|
|
2421
|
+
t5 = Fp.add(t0, t2);
|
|
2422
|
+
t4 = Fp.sub(t4, t5);
|
|
2423
|
+
t5 = Fp.add(Y1, Z1);
|
|
2424
|
+
X3 = Fp.add(Y2, Z2);
|
|
2425
|
+
t5 = Fp.mul(t5, X3);
|
|
2426
|
+
X3 = Fp.add(t1, t2);
|
|
2427
|
+
t5 = Fp.sub(t5, X3);
|
|
2428
|
+
Z3 = Fp.mul(a, t4);
|
|
2429
|
+
X3 = Fp.mul(b3, t2);
|
|
2430
|
+
Z3 = Fp.add(X3, Z3);
|
|
2431
|
+
X3 = Fp.sub(t1, Z3);
|
|
2432
|
+
Z3 = Fp.add(t1, Z3);
|
|
2433
|
+
Y3 = Fp.mul(X3, Z3);
|
|
2434
|
+
t1 = Fp.add(t0, t0);
|
|
2435
|
+
t1 = Fp.add(t1, t0);
|
|
2436
|
+
t2 = Fp.mul(a, t2);
|
|
2437
|
+
t4 = Fp.mul(b3, t4);
|
|
2438
|
+
t1 = Fp.add(t1, t2);
|
|
2439
|
+
t2 = Fp.sub(t0, t2);
|
|
2440
|
+
t2 = Fp.mul(a, t2);
|
|
2441
|
+
t4 = Fp.add(t4, t2);
|
|
2442
|
+
t0 = Fp.mul(t1, t4);
|
|
2443
|
+
Y3 = Fp.add(Y3, t0);
|
|
2444
|
+
t0 = Fp.mul(t5, t4);
|
|
2445
|
+
X3 = Fp.mul(t3, X3);
|
|
2446
|
+
X3 = Fp.sub(X3, t0);
|
|
2447
|
+
t0 = Fp.mul(t3, t1);
|
|
2448
|
+
Z3 = Fp.mul(t5, Z3);
|
|
2449
|
+
Z3 = Fp.add(Z3, t0);
|
|
2450
|
+
return new Point(X3, Y3, Z3);
|
|
2451
|
+
}
|
|
2452
|
+
subtract(other) {
|
|
2453
|
+
return this.add(other.negate());
|
|
2454
|
+
}
|
|
2455
|
+
is0() {
|
|
2456
|
+
return this.equals(Point.ZERO);
|
|
2457
|
+
}
|
|
2458
|
+
/**
|
|
2459
|
+
* Constant time multiplication.
|
|
2460
|
+
* Uses wNAF method. Windowed method may be 10% faster,
|
|
2461
|
+
* but takes 2x longer to generate and consumes 2x memory.
|
|
2462
|
+
* Uses precomputes when available.
|
|
2463
|
+
* Uses endomorphism for Koblitz curves.
|
|
2464
|
+
* @param scalar by which the point would be multiplied
|
|
2465
|
+
* @returns New point
|
|
2466
|
+
*/
|
|
2467
|
+
multiply(scalar) {
|
|
2468
|
+
const { endo: endo2 } = extraOpts;
|
|
2469
|
+
if (!Fn.isValidNot0(scalar))
|
|
2470
|
+
throw new Error("invalid scalar: out of range");
|
|
2471
|
+
let point, fake;
|
|
2472
|
+
const mul = (n) => wnaf.cached(this, n, (p) => normalizeZ(Point, p));
|
|
2473
|
+
if (endo2) {
|
|
2474
|
+
const { k1neg, k1, k2neg, k2 } = splitEndoScalarN(scalar);
|
|
2475
|
+
const { p: k1p, f: k1f } = mul(k1);
|
|
2476
|
+
const { p: k2p, f: k2f } = mul(k2);
|
|
2477
|
+
fake = k1f.add(k2f);
|
|
2478
|
+
point = finishEndo(endo2.beta, k1p, k2p, k1neg, k2neg);
|
|
2479
|
+
} else {
|
|
2480
|
+
const { p, f } = mul(scalar);
|
|
2481
|
+
point = p;
|
|
2482
|
+
fake = f;
|
|
2483
|
+
}
|
|
2484
|
+
return normalizeZ(Point, [point, fake])[0];
|
|
2485
|
+
}
|
|
2486
|
+
/**
|
|
2487
|
+
* Non-constant-time multiplication. Uses double-and-add algorithm.
|
|
2488
|
+
* It's faster, but should only be used when you don't care about
|
|
2489
|
+
* an exposed secret key e.g. sig verification, which works over *public* keys.
|
|
2490
|
+
*/
|
|
2491
|
+
multiplyUnsafe(sc) {
|
|
2492
|
+
const { endo: endo2 } = extraOpts;
|
|
2493
|
+
const p = this;
|
|
2494
|
+
if (!Fn.isValid(sc))
|
|
2495
|
+
throw new Error("invalid scalar: out of range");
|
|
2496
|
+
if (sc === _0n5 || p.is0())
|
|
2497
|
+
return Point.ZERO;
|
|
2498
|
+
if (sc === _1n5)
|
|
2499
|
+
return p;
|
|
2500
|
+
if (wnaf.hasCache(this))
|
|
2501
|
+
return this.multiply(sc);
|
|
2502
|
+
if (endo2) {
|
|
2503
|
+
const { k1neg, k1, k2neg, k2 } = splitEndoScalarN(sc);
|
|
2504
|
+
const { p1, p2 } = mulEndoUnsafe(Point, p, k1, k2);
|
|
2505
|
+
return finishEndo(endo2.beta, p1, p2, k1neg, k2neg);
|
|
2506
|
+
} else {
|
|
2507
|
+
return wnaf.unsafe(p, sc);
|
|
2508
|
+
}
|
|
2509
|
+
}
|
|
2510
|
+
/**
|
|
2511
|
+
* Converts Projective point to affine (x, y) coordinates.
|
|
2512
|
+
* @param invertedZ Z^-1 (inverted zero) - optional, precomputation is useful for invertBatch
|
|
2513
|
+
*/
|
|
2514
|
+
toAffine(invertedZ) {
|
|
2515
|
+
return toAffineMemo(this, invertedZ);
|
|
2516
|
+
}
|
|
2517
|
+
/**
|
|
2518
|
+
* Checks whether Point is free of torsion elements (is in prime subgroup).
|
|
2519
|
+
* Always torsion-free for cofactor=1 curves.
|
|
2520
|
+
*/
|
|
2521
|
+
isTorsionFree() {
|
|
2522
|
+
const { isTorsionFree } = extraOpts;
|
|
2523
|
+
if (cofactor === _1n5)
|
|
2524
|
+
return true;
|
|
2525
|
+
if (isTorsionFree)
|
|
2526
|
+
return isTorsionFree(Point, this);
|
|
2527
|
+
return wnaf.unsafe(this, CURVE_ORDER).is0();
|
|
2528
|
+
}
|
|
2529
|
+
clearCofactor() {
|
|
2530
|
+
const { clearCofactor } = extraOpts;
|
|
2531
|
+
if (cofactor === _1n5)
|
|
2532
|
+
return this;
|
|
2533
|
+
if (clearCofactor)
|
|
2534
|
+
return clearCofactor(Point, this);
|
|
2535
|
+
return this.multiplyUnsafe(cofactor);
|
|
2536
|
+
}
|
|
2537
|
+
isSmallOrder() {
|
|
2538
|
+
return this.multiplyUnsafe(cofactor).is0();
|
|
2539
|
+
}
|
|
2540
|
+
toBytes(isCompressed = true) {
|
|
2541
|
+
abool(isCompressed, "isCompressed");
|
|
2542
|
+
this.assertValidity();
|
|
2543
|
+
return encodePoint(Point, this, isCompressed);
|
|
2544
|
+
}
|
|
2545
|
+
toHex(isCompressed = true) {
|
|
2546
|
+
return bytesToHex(this.toBytes(isCompressed));
|
|
2547
|
+
}
|
|
2548
|
+
toString() {
|
|
2549
|
+
return `<Point ${this.is0() ? "ZERO" : this.toHex()}>`;
|
|
2550
|
+
}
|
|
2551
|
+
}
|
|
2552
|
+
const bits = Fn.BITS;
|
|
2553
|
+
const wnaf = new wNAF(Point, extraOpts.endo ? Math.ceil(bits / 2) : bits);
|
|
2554
|
+
Point.BASE.precompute(8);
|
|
2555
|
+
return Point;
|
|
2556
|
+
}
|
|
2557
|
+
function pprefix(hasEvenY) {
|
|
2558
|
+
return Uint8Array.of(hasEvenY ? 2 : 3);
|
|
2559
|
+
}
|
|
2560
|
+
function getWLengths(Fp, Fn) {
|
|
2561
|
+
return {
|
|
2562
|
+
secretKey: Fn.BYTES,
|
|
2563
|
+
publicKey: 1 + Fp.BYTES,
|
|
2564
|
+
publicKeyUncompressed: 1 + 2 * Fp.BYTES,
|
|
2565
|
+
publicKeyHasPrefix: true,
|
|
2566
|
+
signature: 2 * Fn.BYTES
|
|
2567
|
+
};
|
|
2568
|
+
}
|
|
2569
|
+
function ecdh(Point, ecdhOpts = {}) {
|
|
2570
|
+
const { Fn } = Point;
|
|
2571
|
+
const randomBytes_ = ecdhOpts.randomBytes || randomBytes;
|
|
2572
|
+
const lengths = Object.assign(getWLengths(Point.Fp, Fn), { seed: getMinHashLength(Fn.ORDER) });
|
|
2573
|
+
function isValidSecretKey(secretKey) {
|
|
2574
|
+
try {
|
|
2575
|
+
const num = Fn.fromBytes(secretKey);
|
|
2576
|
+
return Fn.isValidNot0(num);
|
|
2577
|
+
} catch (error) {
|
|
2578
|
+
return false;
|
|
2579
|
+
}
|
|
2580
|
+
}
|
|
2581
|
+
function isValidPublicKey(publicKey, isCompressed) {
|
|
2582
|
+
const { publicKey: comp, publicKeyUncompressed } = lengths;
|
|
2583
|
+
try {
|
|
2584
|
+
const l = publicKey.length;
|
|
2585
|
+
if (isCompressed === true && l !== comp)
|
|
2586
|
+
return false;
|
|
2587
|
+
if (isCompressed === false && l !== publicKeyUncompressed)
|
|
2588
|
+
return false;
|
|
2589
|
+
return !!Point.fromBytes(publicKey);
|
|
2590
|
+
} catch (error) {
|
|
2591
|
+
return false;
|
|
2592
|
+
}
|
|
2593
|
+
}
|
|
2594
|
+
function randomSecretKey(seed = randomBytes_(lengths.seed)) {
|
|
2595
|
+
return mapHashToField(abytes(seed, lengths.seed, "seed"), Fn.ORDER);
|
|
2596
|
+
}
|
|
2597
|
+
function getPublicKey(secretKey, isCompressed = true) {
|
|
2598
|
+
return Point.BASE.multiply(Fn.fromBytes(secretKey)).toBytes(isCompressed);
|
|
2599
|
+
}
|
|
2600
|
+
function isProbPub(item) {
|
|
2601
|
+
const { secretKey, publicKey, publicKeyUncompressed } = lengths;
|
|
2602
|
+
if (!isBytes(item))
|
|
2603
|
+
return void 0;
|
|
2604
|
+
if ("_lengths" in Fn && Fn._lengths || secretKey === publicKey)
|
|
2605
|
+
return void 0;
|
|
2606
|
+
const l = abytes(item, void 0, "key").length;
|
|
2607
|
+
return l === publicKey || l === publicKeyUncompressed;
|
|
2608
|
+
}
|
|
2609
|
+
function getSharedSecret(secretKeyA, publicKeyB, isCompressed = true) {
|
|
2610
|
+
if (isProbPub(secretKeyA) === true)
|
|
2611
|
+
throw new Error("first arg must be private key");
|
|
2612
|
+
if (isProbPub(publicKeyB) === false)
|
|
2613
|
+
throw new Error("second arg must be public key");
|
|
2614
|
+
const s = Fn.fromBytes(secretKeyA);
|
|
2615
|
+
const b = Point.fromBytes(publicKeyB);
|
|
2616
|
+
return b.multiply(s).toBytes(isCompressed);
|
|
2617
|
+
}
|
|
2618
|
+
const utils = {
|
|
2619
|
+
isValidSecretKey,
|
|
2620
|
+
isValidPublicKey,
|
|
2621
|
+
randomSecretKey
|
|
2622
|
+
};
|
|
2623
|
+
const keygen = createKeygen(randomSecretKey, getPublicKey);
|
|
2624
|
+
return Object.freeze({ getPublicKey, getSharedSecret, keygen, Point, utils, lengths });
|
|
2625
|
+
}
|
|
2626
|
+
function ecdsa(Point, hash, ecdsaOpts = {}) {
|
|
2627
|
+
ahash(hash);
|
|
2628
|
+
validateObject(ecdsaOpts, {}, {
|
|
2629
|
+
hmac: "function",
|
|
2630
|
+
lowS: "boolean",
|
|
2631
|
+
randomBytes: "function",
|
|
2632
|
+
bits2int: "function",
|
|
2633
|
+
bits2int_modN: "function"
|
|
2634
|
+
});
|
|
2635
|
+
ecdsaOpts = Object.assign({}, ecdsaOpts);
|
|
2636
|
+
const randomBytes2 = ecdsaOpts.randomBytes || randomBytes;
|
|
2637
|
+
const hmac2 = ecdsaOpts.hmac || ((key, msg) => hmac(hash, key, msg));
|
|
2638
|
+
const { Fp, Fn } = Point;
|
|
2639
|
+
const { ORDER: CURVE_ORDER, BITS: fnBits } = Fn;
|
|
2640
|
+
const { keygen, getPublicKey, getSharedSecret, utils, lengths } = ecdh(Point, ecdsaOpts);
|
|
2641
|
+
const defaultSigOpts = {
|
|
2642
|
+
prehash: true,
|
|
2643
|
+
lowS: typeof ecdsaOpts.lowS === "boolean" ? ecdsaOpts.lowS : true,
|
|
2644
|
+
format: "compact",
|
|
2645
|
+
extraEntropy: false
|
|
2646
|
+
};
|
|
2647
|
+
const hasLargeCofactor = CURVE_ORDER * _2n3 < Fp.ORDER;
|
|
2648
|
+
function isBiggerThanHalfOrder(number) {
|
|
2649
|
+
const HALF = CURVE_ORDER >> _1n5;
|
|
2650
|
+
return number > HALF;
|
|
2651
|
+
}
|
|
2652
|
+
function validateRS(title, num) {
|
|
2653
|
+
if (!Fn.isValidNot0(num))
|
|
2654
|
+
throw new Error(`invalid signature ${title}: out of range 1..Point.Fn.ORDER`);
|
|
2655
|
+
return num;
|
|
2656
|
+
}
|
|
2657
|
+
function assertSmallCofactor() {
|
|
2658
|
+
if (hasLargeCofactor)
|
|
2659
|
+
throw new Error('"recovered" sig type is not supported for cofactor >2 curves');
|
|
2660
|
+
}
|
|
2661
|
+
function validateSigLength(bytes, format) {
|
|
2662
|
+
validateSigFormat(format);
|
|
2663
|
+
const size = lengths.signature;
|
|
2664
|
+
const sizer = format === "compact" ? size : format === "recovered" ? size + 1 : void 0;
|
|
2665
|
+
return abytes(bytes, sizer);
|
|
2666
|
+
}
|
|
2667
|
+
class Signature {
|
|
2668
|
+
r;
|
|
2669
|
+
s;
|
|
2670
|
+
recovery;
|
|
2671
|
+
constructor(r, s, recovery) {
|
|
2672
|
+
this.r = validateRS("r", r);
|
|
2673
|
+
this.s = validateRS("s", s);
|
|
2674
|
+
if (recovery != null) {
|
|
2675
|
+
assertSmallCofactor();
|
|
2676
|
+
if (![0, 1, 2, 3].includes(recovery))
|
|
2677
|
+
throw new Error("invalid recovery id");
|
|
2678
|
+
this.recovery = recovery;
|
|
2679
|
+
}
|
|
2680
|
+
Object.freeze(this);
|
|
2681
|
+
}
|
|
2682
|
+
static fromBytes(bytes, format = defaultSigOpts.format) {
|
|
2683
|
+
validateSigLength(bytes, format);
|
|
2684
|
+
let recid;
|
|
2685
|
+
if (format === "der") {
|
|
2686
|
+
const { r: r2, s: s2 } = DER.toSig(abytes(bytes));
|
|
2687
|
+
return new Signature(r2, s2);
|
|
2688
|
+
}
|
|
2689
|
+
if (format === "recovered") {
|
|
2690
|
+
recid = bytes[0];
|
|
2691
|
+
format = "compact";
|
|
2692
|
+
bytes = bytes.subarray(1);
|
|
2693
|
+
}
|
|
2694
|
+
const L = lengths.signature / 2;
|
|
2695
|
+
const r = bytes.subarray(0, L);
|
|
2696
|
+
const s = bytes.subarray(L, L * 2);
|
|
2697
|
+
return new Signature(Fn.fromBytes(r), Fn.fromBytes(s), recid);
|
|
2698
|
+
}
|
|
2699
|
+
static fromHex(hex, format) {
|
|
2700
|
+
return this.fromBytes(hexToBytes(hex), format);
|
|
2701
|
+
}
|
|
2702
|
+
assertRecovery() {
|
|
2703
|
+
const { recovery } = this;
|
|
2704
|
+
if (recovery == null)
|
|
2705
|
+
throw new Error("invalid recovery id: must be present");
|
|
2706
|
+
return recovery;
|
|
2707
|
+
}
|
|
2708
|
+
addRecoveryBit(recovery) {
|
|
2709
|
+
return new Signature(this.r, this.s, recovery);
|
|
2710
|
+
}
|
|
2711
|
+
recoverPublicKey(messageHash) {
|
|
2712
|
+
const { r, s } = this;
|
|
2713
|
+
const recovery = this.assertRecovery();
|
|
2714
|
+
const radj = recovery === 2 || recovery === 3 ? r + CURVE_ORDER : r;
|
|
2715
|
+
if (!Fp.isValid(radj))
|
|
2716
|
+
throw new Error("invalid recovery id: sig.r+curve.n != R.x");
|
|
2717
|
+
const x = Fp.toBytes(radj);
|
|
2718
|
+
const R = Point.fromBytes(concatBytes(pprefix((recovery & 1) === 0), x));
|
|
2719
|
+
const ir = Fn.inv(radj);
|
|
2720
|
+
const h = bits2int_modN(abytes(messageHash, void 0, "msgHash"));
|
|
2721
|
+
const u1 = Fn.create(-h * ir);
|
|
2722
|
+
const u2 = Fn.create(s * ir);
|
|
2723
|
+
const Q = Point.BASE.multiplyUnsafe(u1).add(R.multiplyUnsafe(u2));
|
|
2724
|
+
if (Q.is0())
|
|
2725
|
+
throw new Error("invalid recovery: point at infinify");
|
|
2726
|
+
Q.assertValidity();
|
|
2727
|
+
return Q;
|
|
2728
|
+
}
|
|
2729
|
+
// Signatures should be low-s, to prevent malleability.
|
|
2730
|
+
hasHighS() {
|
|
2731
|
+
return isBiggerThanHalfOrder(this.s);
|
|
2732
|
+
}
|
|
2733
|
+
toBytes(format = defaultSigOpts.format) {
|
|
2734
|
+
validateSigFormat(format);
|
|
2735
|
+
if (format === "der")
|
|
2736
|
+
return hexToBytes(DER.hexFromSig(this));
|
|
2737
|
+
const { r, s } = this;
|
|
2738
|
+
const rb = Fn.toBytes(r);
|
|
2739
|
+
const sb = Fn.toBytes(s);
|
|
2740
|
+
if (format === "recovered") {
|
|
2741
|
+
assertSmallCofactor();
|
|
2742
|
+
return concatBytes(Uint8Array.of(this.assertRecovery()), rb, sb);
|
|
2743
|
+
}
|
|
2744
|
+
return concatBytes(rb, sb);
|
|
2745
|
+
}
|
|
2746
|
+
toHex(format) {
|
|
2747
|
+
return bytesToHex(this.toBytes(format));
|
|
2748
|
+
}
|
|
2749
|
+
}
|
|
2750
|
+
const bits2int = ecdsaOpts.bits2int || function bits2int_def(bytes) {
|
|
2751
|
+
if (bytes.length > 8192)
|
|
2752
|
+
throw new Error("input is too large");
|
|
2753
|
+
const num = bytesToNumberBE(bytes);
|
|
2754
|
+
const delta = bytes.length * 8 - fnBits;
|
|
2755
|
+
return delta > 0 ? num >> BigInt(delta) : num;
|
|
2756
|
+
};
|
|
2757
|
+
const bits2int_modN = ecdsaOpts.bits2int_modN || function bits2int_modN_def(bytes) {
|
|
2758
|
+
return Fn.create(bits2int(bytes));
|
|
2759
|
+
};
|
|
2760
|
+
const ORDER_MASK = bitMask(fnBits);
|
|
2761
|
+
function int2octets(num) {
|
|
2762
|
+
aInRange("num < 2^" + fnBits, num, _0n5, ORDER_MASK);
|
|
2763
|
+
return Fn.toBytes(num);
|
|
2764
|
+
}
|
|
2765
|
+
function validateMsgAndHash(message, prehash) {
|
|
2766
|
+
abytes(message, void 0, "message");
|
|
2767
|
+
return prehash ? abytes(hash(message), void 0, "prehashed message") : message;
|
|
2768
|
+
}
|
|
2769
|
+
function prepSig(message, secretKey, opts) {
|
|
2770
|
+
const { lowS, prehash, extraEntropy } = validateSigOpts(opts, defaultSigOpts);
|
|
2771
|
+
message = validateMsgAndHash(message, prehash);
|
|
2772
|
+
const h1int = bits2int_modN(message);
|
|
2773
|
+
const d = Fn.fromBytes(secretKey);
|
|
2774
|
+
if (!Fn.isValidNot0(d))
|
|
2775
|
+
throw new Error("invalid private key");
|
|
2776
|
+
const seedArgs = [int2octets(d), int2octets(h1int)];
|
|
2777
|
+
if (extraEntropy != null && extraEntropy !== false) {
|
|
2778
|
+
const e = extraEntropy === true ? randomBytes2(lengths.secretKey) : extraEntropy;
|
|
2779
|
+
seedArgs.push(abytes(e, void 0, "extraEntropy"));
|
|
2780
|
+
}
|
|
2781
|
+
const seed = concatBytes(...seedArgs);
|
|
2782
|
+
const m = h1int;
|
|
2783
|
+
function k2sig(kBytes) {
|
|
2784
|
+
const k = bits2int(kBytes);
|
|
2785
|
+
if (!Fn.isValidNot0(k))
|
|
2786
|
+
return;
|
|
2787
|
+
const ik = Fn.inv(k);
|
|
2788
|
+
const q = Point.BASE.multiply(k).toAffine();
|
|
2789
|
+
const r = Fn.create(q.x);
|
|
2790
|
+
if (r === _0n5)
|
|
2791
|
+
return;
|
|
2792
|
+
const s = Fn.create(ik * Fn.create(m + r * d));
|
|
2793
|
+
if (s === _0n5)
|
|
2794
|
+
return;
|
|
2795
|
+
let recovery = (q.x === r ? 0 : 2) | Number(q.y & _1n5);
|
|
2796
|
+
let normS = s;
|
|
2797
|
+
if (lowS && isBiggerThanHalfOrder(s)) {
|
|
2798
|
+
normS = Fn.neg(s);
|
|
2799
|
+
recovery ^= 1;
|
|
2800
|
+
}
|
|
2801
|
+
return new Signature(r, normS, hasLargeCofactor ? void 0 : recovery);
|
|
2802
|
+
}
|
|
2803
|
+
return { seed, k2sig };
|
|
2804
|
+
}
|
|
2805
|
+
function sign3(message, secretKey, opts = {}) {
|
|
2806
|
+
const { seed, k2sig } = prepSig(message, secretKey, opts);
|
|
2807
|
+
const drbg = createHmacDrbg(hash.outputLen, Fn.BYTES, hmac2);
|
|
2808
|
+
const sig = drbg(seed, k2sig);
|
|
2809
|
+
return sig.toBytes(opts.format);
|
|
2810
|
+
}
|
|
2811
|
+
function verify2(signature, message, publicKey, opts = {}) {
|
|
2812
|
+
const { lowS, prehash, format } = validateSigOpts(opts, defaultSigOpts);
|
|
2813
|
+
publicKey = abytes(publicKey, void 0, "publicKey");
|
|
2814
|
+
message = validateMsgAndHash(message, prehash);
|
|
2815
|
+
if (!isBytes(signature)) {
|
|
2816
|
+
const end = signature instanceof Signature ? ", use sig.toBytes()" : "";
|
|
2817
|
+
throw new Error("verify expects Uint8Array signature" + end);
|
|
2818
|
+
}
|
|
2819
|
+
validateSigLength(signature, format);
|
|
2820
|
+
try {
|
|
2821
|
+
const sig = Signature.fromBytes(signature, format);
|
|
2822
|
+
const P = Point.fromBytes(publicKey);
|
|
2823
|
+
if (lowS && sig.hasHighS())
|
|
2824
|
+
return false;
|
|
2825
|
+
const { r, s } = sig;
|
|
2826
|
+
const h = bits2int_modN(message);
|
|
2827
|
+
const is = Fn.inv(s);
|
|
2828
|
+
const u1 = Fn.create(h * is);
|
|
2829
|
+
const u2 = Fn.create(r * is);
|
|
2830
|
+
const R = Point.BASE.multiplyUnsafe(u1).add(P.multiplyUnsafe(u2));
|
|
2831
|
+
if (R.is0())
|
|
2832
|
+
return false;
|
|
2833
|
+
const v = Fn.create(R.x);
|
|
2834
|
+
return v === r;
|
|
2835
|
+
} catch (e) {
|
|
2836
|
+
return false;
|
|
2837
|
+
}
|
|
2838
|
+
}
|
|
2839
|
+
function recoverPublicKey(signature, message, opts = {}) {
|
|
2840
|
+
const { prehash } = validateSigOpts(opts, defaultSigOpts);
|
|
2841
|
+
message = validateMsgAndHash(message, prehash);
|
|
2842
|
+
return Signature.fromBytes(signature, "recovered").recoverPublicKey(message).toBytes();
|
|
2843
|
+
}
|
|
2844
|
+
return Object.freeze({
|
|
2845
|
+
keygen,
|
|
2846
|
+
getPublicKey,
|
|
2847
|
+
getSharedSecret,
|
|
2848
|
+
utils,
|
|
2849
|
+
lengths,
|
|
2850
|
+
Point,
|
|
2851
|
+
sign: sign3,
|
|
2852
|
+
verify: verify2,
|
|
2853
|
+
recoverPublicKey,
|
|
2854
|
+
Signature,
|
|
2855
|
+
hash
|
|
2856
|
+
});
|
|
2857
|
+
}
|
|
2858
|
+
|
|
2859
|
+
// node_modules/@noble/curves/secp256k1.js
|
|
2860
|
+
var secp256k1_CURVE = {
|
|
2861
|
+
p: BigInt("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"),
|
|
2862
|
+
n: BigInt("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"),
|
|
2863
|
+
h: BigInt(1),
|
|
2864
|
+
a: BigInt(0),
|
|
2865
|
+
b: BigInt(7),
|
|
2866
|
+
Gx: BigInt("0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"),
|
|
2867
|
+
Gy: BigInt("0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8")
|
|
2868
|
+
};
|
|
2869
|
+
var secp256k1_ENDO = {
|
|
2870
|
+
beta: BigInt("0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee"),
|
|
2871
|
+
basises: [
|
|
2872
|
+
[BigInt("0x3086d221a7d46bcde86c90e49284eb15"), -BigInt("0xe4437ed6010e88286f547fa90abfe4c3")],
|
|
2873
|
+
[BigInt("0x114ca50f7a8e2f3f657c1108d9d44cfd8"), BigInt("0x3086d221a7d46bcde86c90e49284eb15")]
|
|
2874
|
+
]
|
|
2875
|
+
};
|
|
2876
|
+
var _2n4 = /* @__PURE__ */ BigInt(2);
|
|
2877
|
+
function sqrtMod(y) {
|
|
2878
|
+
const P = secp256k1_CURVE.p;
|
|
2879
|
+
const _3n3 = BigInt(3), _6n = BigInt(6), _11n = BigInt(11), _22n = BigInt(22);
|
|
2880
|
+
const _23n = BigInt(23), _44n = BigInt(44), _88n = BigInt(88);
|
|
2881
|
+
const b2 = y * y * y % P;
|
|
2882
|
+
const b3 = b2 * b2 * y % P;
|
|
2883
|
+
const b6 = pow2(b3, _3n3, P) * b3 % P;
|
|
2884
|
+
const b9 = pow2(b6, _3n3, P) * b3 % P;
|
|
2885
|
+
const b11 = pow2(b9, _2n4, P) * b2 % P;
|
|
2886
|
+
const b22 = pow2(b11, _11n, P) * b11 % P;
|
|
2887
|
+
const b44 = pow2(b22, _22n, P) * b22 % P;
|
|
2888
|
+
const b88 = pow2(b44, _44n, P) * b44 % P;
|
|
2889
|
+
const b176 = pow2(b88, _88n, P) * b88 % P;
|
|
2890
|
+
const b220 = pow2(b176, _44n, P) * b44 % P;
|
|
2891
|
+
const b223 = pow2(b220, _3n3, P) * b3 % P;
|
|
2892
|
+
const t1 = pow2(b223, _23n, P) * b22 % P;
|
|
2893
|
+
const t2 = pow2(t1, _6n, P) * b2 % P;
|
|
2894
|
+
const root = pow2(t2, _2n4, P);
|
|
2895
|
+
if (!Fpk1.eql(Fpk1.sqr(root), y))
|
|
2896
|
+
throw new Error("Cannot find square root");
|
|
2897
|
+
return root;
|
|
2898
|
+
}
|
|
2899
|
+
var Fpk1 = Field(secp256k1_CURVE.p, { sqrt: sqrtMod });
|
|
2900
|
+
var Pointk1 = /* @__PURE__ */ weierstrass(secp256k1_CURVE, {
|
|
2901
|
+
Fp: Fpk1,
|
|
2902
|
+
endo: secp256k1_ENDO
|
|
2903
|
+
});
|
|
2904
|
+
var secp256k1 = /* @__PURE__ */ ecdsa(Pointk1, sha256);
|
|
2905
|
+
|
|
2906
|
+
// src/wallet.ts
|
|
2907
|
+
var BASE58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
2908
|
+
function base58Encode(bytes) {
|
|
2909
|
+
let leadingZeros = 0;
|
|
2910
|
+
for (const byte of bytes) {
|
|
2911
|
+
if (byte === 0) leadingZeros++;
|
|
2912
|
+
else break;
|
|
2913
|
+
}
|
|
2914
|
+
let num = 0n;
|
|
2915
|
+
for (const byte of bytes) {
|
|
2916
|
+
num = num * 256n + BigInt(byte);
|
|
2917
|
+
}
|
|
2918
|
+
let encoded = "";
|
|
2919
|
+
while (num > 0n) {
|
|
2920
|
+
encoded = BASE58_ALPHABET[Number(num % 58n)] + encoded;
|
|
2921
|
+
num = num / 58n;
|
|
2922
|
+
}
|
|
2923
|
+
return BASE58_ALPHABET[0].repeat(leadingZeros) + encoded;
|
|
2924
|
+
}
|
|
2925
|
+
function deriveSecp256k1Seed(ed25519Seed) {
|
|
2926
|
+
const hmac2 = createHmac("sha512", "secp256k1");
|
|
2927
|
+
hmac2.update(ed25519Seed);
|
|
2928
|
+
return hmac2.digest().subarray(0, 32);
|
|
2929
|
+
}
|
|
2930
|
+
function getSecp256k1PublicKey(privateKey) {
|
|
2931
|
+
const ecdh2 = createECDH("secp256k1");
|
|
2932
|
+
ecdh2.setPrivateKey(privateKey);
|
|
2933
|
+
return Buffer.from(ecdh2.getPublicKey());
|
|
2934
|
+
}
|
|
2935
|
+
function evmAddressFromPublicKey(uncompressedPubKey) {
|
|
2936
|
+
const pubKeyBody = uncompressedPubKey.subarray(1);
|
|
2937
|
+
const hash = keccak_256(pubKeyBody);
|
|
2938
|
+
const addressBytes = hash.slice(hash.length - 20);
|
|
2939
|
+
return "0x" + Buffer.from(addressBytes).toString("hex");
|
|
2940
|
+
}
|
|
2941
|
+
function checksumAddress(address) {
|
|
2942
|
+
const addr = address.slice(2).toLowerCase();
|
|
2943
|
+
const hash = Buffer.from(keccak_256(Buffer.from(addr, "utf-8"))).toString(
|
|
2944
|
+
"hex"
|
|
2945
|
+
);
|
|
2946
|
+
let checksummed = "0x";
|
|
2947
|
+
for (let i = 0; i < addr.length; i++) {
|
|
2948
|
+
checksummed += parseInt(hash[i], 16) >= 8 ? addr[i].toUpperCase() : addr[i];
|
|
2949
|
+
}
|
|
2950
|
+
return checksummed;
|
|
2951
|
+
}
|
|
2952
|
+
async function getSolanaAddress(nitDir) {
|
|
2953
|
+
const pubBase64 = await loadPublicKey(nitDir);
|
|
2954
|
+
const pubBytes = Buffer.from(pubBase64, "base64");
|
|
2955
|
+
return base58Encode(pubBytes);
|
|
2956
|
+
}
|
|
2957
|
+
async function getEvmAddress(nitDir) {
|
|
2958
|
+
const keyPath = join5(nitDir, "identity", "agent.key");
|
|
2959
|
+
const privBase64 = (await fs5.readFile(keyPath, "utf-8")).trim();
|
|
2960
|
+
const ed25519Seed = Buffer.from(privBase64, "base64");
|
|
2961
|
+
const secp256k1PrivKey = deriveSecp256k1Seed(ed25519Seed);
|
|
2962
|
+
const secp256k1PubKey = getSecp256k1PublicKey(secp256k1PrivKey);
|
|
2963
|
+
const rawAddress = evmAddressFromPublicKey(secp256k1PubKey);
|
|
2964
|
+
return checksumAddress(rawAddress);
|
|
2965
|
+
}
|
|
2966
|
+
async function getWalletAddresses(nitDir) {
|
|
2967
|
+
const [solana, ethereum] = await Promise.all([
|
|
2968
|
+
getSolanaAddress(nitDir),
|
|
2969
|
+
getEvmAddress(nitDir)
|
|
2970
|
+
]);
|
|
2971
|
+
return { solana, ethereum };
|
|
2972
|
+
}
|
|
2973
|
+
async function loadSecp256k1RawKeyPair(nitDir) {
|
|
2974
|
+
const keyPath = join5(nitDir, "identity", "agent.key");
|
|
2975
|
+
const privBase64 = (await fs5.readFile(keyPath, "utf-8")).trim();
|
|
2976
|
+
const ed25519Seed = Buffer.from(privBase64, "base64");
|
|
2977
|
+
const secp256k1PrivKey = deriveSecp256k1Seed(ed25519Seed);
|
|
2978
|
+
const secp256k1PubKey = getSecp256k1PublicKey(secp256k1PrivKey);
|
|
2979
|
+
const keypair = new Uint8Array(64);
|
|
2980
|
+
keypair.set(secp256k1PrivKey, 0);
|
|
2981
|
+
keypair.set(secp256k1PubKey.subarray(1, 33), 32);
|
|
2982
|
+
return keypair;
|
|
2983
|
+
}
|
|
2984
|
+
async function signEvmHash(nitDir, hash) {
|
|
2985
|
+
if (hash.length !== 32) {
|
|
2986
|
+
throw new Error(`Expected 32-byte hash, got ${hash.length} bytes`);
|
|
2987
|
+
}
|
|
2988
|
+
const keyPath = join5(nitDir, "identity", "agent.key");
|
|
2989
|
+
const privBase64 = (await fs5.readFile(keyPath, "utf-8")).trim();
|
|
2990
|
+
const ed25519Seed = Buffer.from(privBase64, "base64");
|
|
2991
|
+
const privKey = deriveSecp256k1Seed(ed25519Seed);
|
|
2992
|
+
const sigBytes = secp256k1.sign(hash, privKey, { prehash: false, format: "recovered" });
|
|
2993
|
+
const sigObj = secp256k1.Signature.fromBytes(sigBytes, "recovered");
|
|
2994
|
+
const r = sigObj.r.toString(16).padStart(64, "0");
|
|
2995
|
+
const s = sigObj.s.toString(16).padStart(64, "0");
|
|
2996
|
+
const recovery = sigObj.recovery;
|
|
2997
|
+
const v = 27 + recovery;
|
|
2998
|
+
const signature = "0x" + r + s + v.toString(16).padStart(2, "0");
|
|
2999
|
+
return { r: "0x" + r, s: "0x" + s, v, recovery, signature };
|
|
3000
|
+
}
|
|
3001
|
+
async function signSolanaBytes(nitDir, message) {
|
|
3002
|
+
const privateKey = await loadPrivateKey(nitDir);
|
|
3003
|
+
const sig = cryptoSign(null, Buffer.from(message), privateKey);
|
|
3004
|
+
return new Uint8Array(sig);
|
|
3005
|
+
}
|
|
3006
|
+
|
|
3007
|
+
// src/diff.ts
|
|
3008
|
+
function diffCards(oldCard, newCard) {
|
|
3009
|
+
const fields = [];
|
|
3010
|
+
const scalarFields = [
|
|
3011
|
+
"protocolVersion",
|
|
3012
|
+
"name",
|
|
3013
|
+
"description",
|
|
3014
|
+
"version",
|
|
3015
|
+
"url",
|
|
3016
|
+
"publicKey",
|
|
3017
|
+
"iconUrl",
|
|
3018
|
+
"documentationUrl"
|
|
3019
|
+
];
|
|
3020
|
+
for (const field of scalarFields) {
|
|
3021
|
+
const oldVal = oldCard[field];
|
|
3022
|
+
const newVal = newCard[field];
|
|
3023
|
+
if (oldVal !== newVal) {
|
|
3024
|
+
fields.push({ field, old: oldVal, new: newVal });
|
|
3025
|
+
}
|
|
3026
|
+
}
|
|
3027
|
+
const oldProvider = JSON.stringify(oldCard.provider ?? null);
|
|
3028
|
+
const newProvider = JSON.stringify(newCard.provider ?? null);
|
|
3029
|
+
if (oldProvider !== newProvider) {
|
|
3030
|
+
fields.push({ field: "provider", old: oldCard.provider, new: newCard.provider });
|
|
3031
|
+
}
|
|
3032
|
+
const arrayFields = [
|
|
3033
|
+
"defaultInputModes",
|
|
3034
|
+
"defaultOutputModes"
|
|
3035
|
+
];
|
|
3036
|
+
for (const field of arrayFields) {
|
|
3037
|
+
const oldArr = JSON.stringify(oldCard[field]);
|
|
3038
|
+
const newArr = JSON.stringify(newCard[field]);
|
|
3039
|
+
if (oldArr !== newArr) {
|
|
3040
|
+
fields.push({ field, old: oldCard[field], new: newCard[field] });
|
|
3041
|
+
}
|
|
3042
|
+
}
|
|
3043
|
+
const oldSkillMap = new Map(oldCard.skills.map((s) => [s.id, s]));
|
|
3044
|
+
const newSkillMap = new Map(newCard.skills.map((s) => [s.id, s]));
|
|
3045
|
+
const skillsAdded = [];
|
|
3046
|
+
const skillsRemoved = [];
|
|
3047
|
+
const skillsModified = [];
|
|
3048
|
+
for (const [id] of newSkillMap) {
|
|
3049
|
+
if (!oldSkillMap.has(id)) {
|
|
3050
|
+
skillsAdded.push(id);
|
|
3051
|
+
}
|
|
3052
|
+
}
|
|
3053
|
+
for (const [id] of oldSkillMap) {
|
|
3054
|
+
if (!newSkillMap.has(id)) {
|
|
3055
|
+
skillsRemoved.push(id);
|
|
3056
|
+
}
|
|
3057
|
+
}
|
|
3058
|
+
for (const [id, newSkill] of newSkillMap) {
|
|
3059
|
+
const oldSkill = oldSkillMap.get(id);
|
|
3060
|
+
if (oldSkill && !skillsEqual(oldSkill, newSkill)) {
|
|
3061
|
+
skillsModified.push(id);
|
|
3062
|
+
}
|
|
3063
|
+
}
|
|
3064
|
+
const changed = fields.length > 0 || skillsAdded.length > 0 || skillsRemoved.length > 0 || skillsModified.length > 0;
|
|
3065
|
+
return { changed, fields, skillsAdded, skillsRemoved, skillsModified };
|
|
3066
|
+
}
|
|
3067
|
+
function formatDiff(diff2) {
|
|
3068
|
+
if (!diff2.changed) {
|
|
3069
|
+
return "No changes.";
|
|
3070
|
+
}
|
|
3071
|
+
const lines = [];
|
|
3072
|
+
for (const fd of diff2.fields) {
|
|
3073
|
+
const oldStr = formatValue(fd.old);
|
|
3074
|
+
const newStr = formatValue(fd.new);
|
|
3075
|
+
lines.push(` ${fd.field}:`);
|
|
3076
|
+
lines.push(`\x1B[31m - ${oldStr}\x1B[0m`);
|
|
3077
|
+
lines.push(`\x1B[32m + ${newStr}\x1B[0m`);
|
|
3078
|
+
}
|
|
3079
|
+
for (const id of diff2.skillsAdded) {
|
|
3080
|
+
lines.push(`\x1B[32m + skill: ${id}\x1B[0m`);
|
|
3081
|
+
}
|
|
3082
|
+
for (const id of diff2.skillsRemoved) {
|
|
3083
|
+
lines.push(`\x1B[31m - skill: ${id}\x1B[0m`);
|
|
3084
|
+
}
|
|
3085
|
+
for (const id of diff2.skillsModified) {
|
|
3086
|
+
lines.push(`\x1B[33m ~ skill: ${id} (modified)\x1B[0m`);
|
|
3087
|
+
}
|
|
3088
|
+
return lines.join("\n");
|
|
3089
|
+
}
|
|
3090
|
+
function skillsEqual(a, b) {
|
|
3091
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
3092
|
+
}
|
|
3093
|
+
function formatValue(val) {
|
|
3094
|
+
if (val === void 0) return "(unset)";
|
|
3095
|
+
if (val === null) return "(null)";
|
|
3096
|
+
if (typeof val === "string") return val;
|
|
3097
|
+
return JSON.stringify(val);
|
|
3098
|
+
}
|
|
3099
|
+
|
|
3100
|
+
// src/remote.ts
|
|
3101
|
+
import { createHash as createHash3 } from "crypto";
|
|
3102
|
+
function sha256Hex(data) {
|
|
3103
|
+
return createHash3("sha256").update(data, "utf-8").digest("hex");
|
|
3104
|
+
}
|
|
3105
|
+
async function buildAuthHeaders(nitDir, method, path, body) {
|
|
3106
|
+
const agentId = await loadAgentId(nitDir);
|
|
3107
|
+
const timestamp = Math.floor(Date.now() / 1e3).toString();
|
|
3108
|
+
let message = `${method}
|
|
3109
|
+
${path}
|
|
3110
|
+
${agentId}
|
|
3111
|
+
${timestamp}`;
|
|
3112
|
+
if (body !== void 0) {
|
|
3113
|
+
message += `
|
|
3114
|
+
${sha256Hex(body)}`;
|
|
3115
|
+
}
|
|
3116
|
+
const signature = await signMessage(nitDir, message);
|
|
3117
|
+
return {
|
|
3118
|
+
"X-Nit-Agent-Id": agentId,
|
|
3119
|
+
"X-Nit-Timestamp": timestamp,
|
|
3120
|
+
"X-Nit-Signature": signature
|
|
3121
|
+
};
|
|
3122
|
+
}
|
|
3123
|
+
async function pushBranch(nitDir, apiBase, branch2, cardJson, commitHash) {
|
|
3124
|
+
const path = `/agent-card/branches/${encodeURIComponent(branch2)}`;
|
|
3125
|
+
const body = JSON.stringify({ card_json: cardJson, commit_hash: commitHash });
|
|
3126
|
+
try {
|
|
3127
|
+
const authHeaders = await buildAuthHeaders(nitDir, "PUT", path, body);
|
|
3128
|
+
const res = await fetch(`${apiBase}${path}`, {
|
|
3129
|
+
method: "PUT",
|
|
3130
|
+
headers: {
|
|
3131
|
+
"Content-Type": "application/json",
|
|
3132
|
+
...authHeaders
|
|
3133
|
+
},
|
|
3134
|
+
body
|
|
3135
|
+
});
|
|
3136
|
+
if (!res.ok) {
|
|
3137
|
+
const text = await res.text();
|
|
3138
|
+
return {
|
|
3139
|
+
branch: branch2,
|
|
3140
|
+
commitHash,
|
|
3141
|
+
remoteUrl: apiBase,
|
|
3142
|
+
success: false,
|
|
3143
|
+
error: `HTTP ${res.status}: ${text}`
|
|
3144
|
+
};
|
|
3145
|
+
}
|
|
3146
|
+
return { branch: branch2, commitHash, remoteUrl: apiBase, success: true };
|
|
3147
|
+
} catch (err) {
|
|
3148
|
+
return {
|
|
3149
|
+
branch: branch2,
|
|
3150
|
+
commitHash,
|
|
3151
|
+
remoteUrl: apiBase,
|
|
3152
|
+
success: false,
|
|
3153
|
+
error: err instanceof Error ? err.message : String(err)
|
|
3154
|
+
};
|
|
3155
|
+
}
|
|
3156
|
+
}
|
|
3157
|
+
async function fetchBranchCard(cardUrl, branch2, nitDir) {
|
|
3158
|
+
const baseUrl = cardUrl.replace(/\/$/, "");
|
|
3159
|
+
let url = `${baseUrl}/.well-known/agent-card.json`;
|
|
3160
|
+
if (branch2 !== "main") {
|
|
3161
|
+
url += `?branch=${encodeURIComponent(branch2)}`;
|
|
3162
|
+
}
|
|
3163
|
+
const res = await fetch(url);
|
|
3164
|
+
if (res.ok) {
|
|
3165
|
+
return await res.json();
|
|
3166
|
+
}
|
|
3167
|
+
if (res.status === 401 && branch2 !== "main") {
|
|
3168
|
+
if (!nitDir) {
|
|
3169
|
+
throw new Error(
|
|
3170
|
+
`Branch "${branch2}" requires authentication. Provide nitDir for signing.`
|
|
3171
|
+
);
|
|
3172
|
+
}
|
|
3173
|
+
const challengeData = await res.json();
|
|
3174
|
+
const signature = await signChallenge(nitDir, challengeData.challenge);
|
|
3175
|
+
const authRes = await fetch(url, {
|
|
3176
|
+
headers: {
|
|
3177
|
+
"X-Nit-Challenge": challengeData.challenge,
|
|
3178
|
+
"X-Nit-Signature": signature
|
|
3179
|
+
}
|
|
3180
|
+
});
|
|
3181
|
+
if (!authRes.ok) {
|
|
3182
|
+
const body = await authRes.text();
|
|
3183
|
+
throw new Error(
|
|
3184
|
+
`Failed to fetch branch "${branch2}" after challenge: HTTP ${authRes.status} ${body}`
|
|
3185
|
+
);
|
|
3186
|
+
}
|
|
3187
|
+
return await authRes.json();
|
|
3188
|
+
}
|
|
3189
|
+
throw new Error(`Failed to fetch card: HTTP ${res.status}`);
|
|
3190
|
+
}
|
|
3191
|
+
|
|
3192
|
+
// src/config.ts
|
|
3193
|
+
import { promises as fs6 } from "fs";
|
|
3194
|
+
import { join as join6 } from "path";
|
|
3195
|
+
var CONFIG_FILE = "config";
|
|
3196
|
+
async function readConfig(nitDir) {
|
|
3197
|
+
const configPath = join6(nitDir, CONFIG_FILE);
|
|
3198
|
+
let raw;
|
|
3199
|
+
try {
|
|
3200
|
+
raw = await fs6.readFile(configPath, "utf-8");
|
|
3201
|
+
} catch {
|
|
3202
|
+
return { remotes: {} };
|
|
3203
|
+
}
|
|
3204
|
+
return parseConfig(raw);
|
|
3205
|
+
}
|
|
3206
|
+
async function writeConfig(nitDir, config) {
|
|
3207
|
+
const configPath = join6(nitDir, CONFIG_FILE);
|
|
3208
|
+
await fs6.writeFile(configPath, serializeConfig(config), "utf-8");
|
|
3209
|
+
}
|
|
3210
|
+
async function getRemoteUrl(nitDir, remoteName) {
|
|
3211
|
+
const config = await readConfig(nitDir);
|
|
3212
|
+
return config.remotes[remoteName]?.url ?? null;
|
|
3213
|
+
}
|
|
3214
|
+
async function getSkillsDir(nitDir) {
|
|
3215
|
+
const config = await readConfig(nitDir);
|
|
3216
|
+
return config.skillsDir ?? null;
|
|
3217
|
+
}
|
|
3218
|
+
async function setRpcUrl(nitDir, chain, url) {
|
|
3219
|
+
const config = await readConfig(nitDir);
|
|
3220
|
+
if (!config.rpc) {
|
|
3221
|
+
config.rpc = {};
|
|
3222
|
+
}
|
|
3223
|
+
config.rpc[chain] = { url };
|
|
3224
|
+
await writeConfig(nitDir, config);
|
|
3225
|
+
}
|
|
3226
|
+
function parseConfig(raw) {
|
|
3227
|
+
const remotes = {};
|
|
3228
|
+
const rpc = {};
|
|
3229
|
+
let currentSection = null;
|
|
3230
|
+
let currentRemote = null;
|
|
3231
|
+
let currentRpcChain = null;
|
|
3232
|
+
let skillsDir;
|
|
3233
|
+
for (const line of raw.split("\n")) {
|
|
3234
|
+
const trimmed = line.trim();
|
|
3235
|
+
if (trimmed === "" || trimmed.startsWith("#")) continue;
|
|
3236
|
+
const remoteMatch = trimmed.match(/^\[remote\s+"([^"]+)"\]$/);
|
|
3237
|
+
if (remoteMatch) {
|
|
3238
|
+
currentSection = "remote";
|
|
3239
|
+
currentRemote = remoteMatch[1];
|
|
3240
|
+
currentRpcChain = null;
|
|
3241
|
+
if (!remotes[currentRemote]) {
|
|
3242
|
+
remotes[currentRemote] = {};
|
|
3243
|
+
}
|
|
3244
|
+
continue;
|
|
3245
|
+
}
|
|
3246
|
+
const rpcMatch = trimmed.match(/^\[rpc\s+"([^"]+)"\]$/);
|
|
3247
|
+
if (rpcMatch) {
|
|
3248
|
+
currentSection = "rpc";
|
|
3249
|
+
currentRpcChain = rpcMatch[1];
|
|
3250
|
+
currentRemote = null;
|
|
3251
|
+
continue;
|
|
3252
|
+
}
|
|
3253
|
+
if (trimmed === "[skills]") {
|
|
3254
|
+
currentSection = "skills";
|
|
3255
|
+
currentRemote = null;
|
|
3256
|
+
currentRpcChain = null;
|
|
3257
|
+
continue;
|
|
3258
|
+
}
|
|
3259
|
+
const kvMatch = trimmed.match(/^(\w+)\s*=\s*(.+)$/);
|
|
3260
|
+
if (kvMatch) {
|
|
3261
|
+
const [, key, value] = kvMatch;
|
|
3262
|
+
if (currentSection === "remote" && currentRemote !== null) {
|
|
3263
|
+
if (key === "url") {
|
|
3264
|
+
remotes[currentRemote].url = value.trim();
|
|
3265
|
+
} else if (key === "credential") {
|
|
3266
|
+
remotes[currentRemote].credential = value.trim();
|
|
3267
|
+
}
|
|
3268
|
+
} else if (currentSection === "rpc" && currentRpcChain !== null) {
|
|
3269
|
+
if (key === "url") {
|
|
3270
|
+
rpc[currentRpcChain] = { url: value.trim() };
|
|
3271
|
+
}
|
|
3272
|
+
} else if (currentSection === "skills") {
|
|
3273
|
+
if (key === "dir") {
|
|
3274
|
+
skillsDir = value.trim();
|
|
3275
|
+
}
|
|
3276
|
+
}
|
|
3277
|
+
}
|
|
3278
|
+
}
|
|
3279
|
+
const config = { remotes, skillsDir };
|
|
3280
|
+
if (Object.keys(rpc).length > 0) {
|
|
3281
|
+
config.rpc = rpc;
|
|
3282
|
+
}
|
|
3283
|
+
return config;
|
|
3284
|
+
}
|
|
3285
|
+
function serializeConfig(config) {
|
|
3286
|
+
const lines = [];
|
|
3287
|
+
for (const [name, remote2] of Object.entries(config.remotes)) {
|
|
3288
|
+
lines.push(`[remote "${name}"]`);
|
|
3289
|
+
if (remote2.url) {
|
|
3290
|
+
lines.push(` url = ${remote2.url}`);
|
|
3291
|
+
}
|
|
3292
|
+
if (remote2.credential) {
|
|
3293
|
+
lines.push(` credential = ${remote2.credential}`);
|
|
3294
|
+
}
|
|
3295
|
+
lines.push("");
|
|
3296
|
+
}
|
|
3297
|
+
if (config.rpc) {
|
|
3298
|
+
for (const [chain, rpcConfig] of Object.entries(config.rpc)) {
|
|
3299
|
+
lines.push(`[rpc "${chain}"]`);
|
|
3300
|
+
lines.push(` url = ${rpcConfig.url}`);
|
|
3301
|
+
lines.push("");
|
|
3302
|
+
}
|
|
3303
|
+
}
|
|
3304
|
+
if (config.skillsDir) {
|
|
3305
|
+
lines.push("[skills]");
|
|
3306
|
+
lines.push(` dir = ${config.skillsDir}`);
|
|
3307
|
+
lines.push("");
|
|
3308
|
+
}
|
|
3309
|
+
return lines.join("\n");
|
|
3310
|
+
}
|
|
3311
|
+
|
|
3312
|
+
// src/tx.ts
|
|
3313
|
+
async function signTx(nitDir, chain, data) {
|
|
3314
|
+
const hex = data.startsWith("0x") ? data.slice(2) : data;
|
|
3315
|
+
const bytes = Buffer.from(hex, "hex");
|
|
3316
|
+
if (chain === "evm") {
|
|
3317
|
+
const result = await signEvmHash(nitDir, bytes);
|
|
3318
|
+
const address2 = await getEvmAddress(nitDir);
|
|
3319
|
+
return {
|
|
3320
|
+
chain: "evm",
|
|
3321
|
+
signature: result.signature,
|
|
3322
|
+
recovery: result.recovery,
|
|
3323
|
+
address: address2
|
|
3324
|
+
};
|
|
3325
|
+
}
|
|
3326
|
+
const sig = await signSolanaBytes(nitDir, bytes);
|
|
3327
|
+
const address = await getSolanaAddress(nitDir);
|
|
3328
|
+
return {
|
|
3329
|
+
chain: "solana",
|
|
3330
|
+
signature: Buffer.from(sig).toString("base64"),
|
|
3331
|
+
address
|
|
3332
|
+
};
|
|
3333
|
+
}
|
|
3334
|
+
async function broadcast(nitDir, chain, signedTx, rpcUrl) {
|
|
3335
|
+
if (!rpcUrl) {
|
|
3336
|
+
const config = await readConfig(nitDir);
|
|
3337
|
+
rpcUrl = config.rpc?.[chain]?.url;
|
|
3338
|
+
if (!rpcUrl) {
|
|
3339
|
+
throw new Error(
|
|
3340
|
+
`No RPC endpoint configured for '${chain}'. Run: nit rpc set-url ${chain} <url>`
|
|
3341
|
+
);
|
|
3342
|
+
}
|
|
3343
|
+
}
|
|
3344
|
+
const body = chain === "evm" ? {
|
|
3345
|
+
jsonrpc: "2.0",
|
|
3346
|
+
id: 1,
|
|
3347
|
+
method: "eth_sendRawTransaction",
|
|
3348
|
+
params: [signedTx.startsWith("0x") ? signedTx : "0x" + signedTx]
|
|
3349
|
+
} : {
|
|
3350
|
+
jsonrpc: "2.0",
|
|
3351
|
+
id: 1,
|
|
3352
|
+
method: "sendTransaction",
|
|
3353
|
+
params: [signedTx, { encoding: "base64" }]
|
|
3354
|
+
};
|
|
3355
|
+
const res = await fetch(rpcUrl, {
|
|
3356
|
+
method: "POST",
|
|
3357
|
+
headers: { "Content-Type": "application/json" },
|
|
3358
|
+
body: JSON.stringify(body)
|
|
3359
|
+
});
|
|
3360
|
+
if (!res.ok) {
|
|
3361
|
+
throw new Error(`RPC request failed: ${res.status} ${res.statusText}`);
|
|
3362
|
+
}
|
|
3363
|
+
const json = await res.json();
|
|
3364
|
+
if (json.error) {
|
|
3365
|
+
throw new Error(`RPC error: ${json.error.message}`);
|
|
3366
|
+
}
|
|
3367
|
+
if (!json.result) {
|
|
3368
|
+
throw new Error("RPC returned no result");
|
|
3369
|
+
}
|
|
3370
|
+
return { chain, txHash: json.result, rpcUrl };
|
|
3371
|
+
}
|
|
3372
|
+
|
|
3373
|
+
// src/index.ts
|
|
3374
|
+
var NIT_DIR = ".nit";
|
|
3375
|
+
var CARD_FILE = "agent-card.json";
|
|
3376
|
+
var DEFAULT_API_BASE = "https://api.newtype-ai.org";
|
|
3377
|
+
function findNitDir(startDir) {
|
|
3378
|
+
let dir = resolve2(startDir || process.cwd());
|
|
3379
|
+
while (true) {
|
|
3380
|
+
const candidate = join7(dir, NIT_DIR);
|
|
3381
|
+
try {
|
|
3382
|
+
const s = statSync(candidate);
|
|
3383
|
+
if (s.isDirectory()) return candidate;
|
|
3384
|
+
} catch {
|
|
3385
|
+
}
|
|
3386
|
+
const parent = resolve2(dir, "..");
|
|
3387
|
+
if (parent === dir) {
|
|
3388
|
+
throw new Error(
|
|
3389
|
+
"Not a nit repository (or any parent directory). Run `nit init` first."
|
|
3390
|
+
);
|
|
3391
|
+
}
|
|
3392
|
+
dir = parent;
|
|
3393
|
+
}
|
|
3394
|
+
}
|
|
3395
|
+
function projectDir(nitDir) {
|
|
3396
|
+
return resolve2(nitDir, "..");
|
|
3397
|
+
}
|
|
3398
|
+
async function readWorkingCard(nitDir) {
|
|
3399
|
+
const cardPath = join7(projectDir(nitDir), CARD_FILE);
|
|
3400
|
+
try {
|
|
3401
|
+
const raw = await fs7.readFile(cardPath, "utf-8");
|
|
3402
|
+
return JSON.parse(raw);
|
|
3403
|
+
} catch {
|
|
3404
|
+
throw new Error(`Cannot read ${CARD_FILE}. Does it exist?`);
|
|
3405
|
+
}
|
|
3406
|
+
}
|
|
3407
|
+
async function writeWorkingCard(nitDir, card) {
|
|
3408
|
+
const cardPath = join7(projectDir(nitDir), CARD_FILE);
|
|
3409
|
+
await fs7.writeFile(cardPath, JSON.stringify(card, null, 2) + "\n", "utf-8");
|
|
3410
|
+
}
|
|
3411
|
+
async function getCardAtCommit(nitDir, commitHash) {
|
|
3412
|
+
const commitRaw = await readObject(nitDir, commitHash);
|
|
3413
|
+
const commit2 = parseCommit(commitHash, commitRaw);
|
|
3414
|
+
const cardRaw = await readObject(nitDir, commit2.card);
|
|
3415
|
+
return JSON.parse(cardRaw);
|
|
3416
|
+
}
|
|
3417
|
+
async function getAuthorName(nitDir) {
|
|
3418
|
+
try {
|
|
3419
|
+
const card = await readWorkingCard(nitDir);
|
|
3420
|
+
return card.name || basename2(projectDir(nitDir));
|
|
3421
|
+
} catch {
|
|
3422
|
+
return basename2(projectDir(nitDir));
|
|
3423
|
+
}
|
|
3424
|
+
}
|
|
3425
|
+
async function init(options) {
|
|
3426
|
+
const projDir = resolve2(options?.projectDir || process.cwd());
|
|
3427
|
+
const nitDir = join7(projDir, NIT_DIR);
|
|
3428
|
+
try {
|
|
3429
|
+
await fs7.access(nitDir);
|
|
3430
|
+
throw new Error("Already initialized. .nit/ directory exists.");
|
|
3431
|
+
} catch (err) {
|
|
3432
|
+
if (err instanceof Error && err.message.startsWith("Already")) throw err;
|
|
3433
|
+
}
|
|
3434
|
+
await fs7.mkdir(join7(nitDir, "objects"), { recursive: true });
|
|
3435
|
+
await fs7.mkdir(join7(nitDir, "refs", "heads"), { recursive: true });
|
|
3436
|
+
await fs7.mkdir(join7(nitDir, "refs", "remote"), { recursive: true });
|
|
3437
|
+
await fs7.mkdir(join7(nitDir, "identity"), { recursive: true });
|
|
3438
|
+
await fs7.mkdir(join7(nitDir, "logs"), { recursive: true });
|
|
3439
|
+
const { publicKey: pubBase64 } = await generateKeypair(nitDir);
|
|
3440
|
+
const publicKeyField = formatPublicKeyField(pubBase64);
|
|
3441
|
+
const agentId = deriveAgentId(publicKeyField);
|
|
3442
|
+
await saveAgentId(nitDir, agentId);
|
|
3443
|
+
const cardPath = join7(projDir, CARD_FILE);
|
|
3444
|
+
let card;
|
|
3445
|
+
let skillsFound = [];
|
|
3446
|
+
try {
|
|
3447
|
+
const raw = await fs7.readFile(cardPath, "utf-8");
|
|
3448
|
+
card = JSON.parse(raw);
|
|
3449
|
+
card.publicKey = publicKeyField;
|
|
3450
|
+
skillsFound = card.skills.map((s) => s.id);
|
|
3451
|
+
} catch {
|
|
3452
|
+
const discovered = await discoverSkills(projDir);
|
|
3453
|
+
skillsFound = discovered.map((s) => s.id);
|
|
3454
|
+
card = {
|
|
3455
|
+
protocolVersion: "0.3.0",
|
|
3456
|
+
name: basename2(projDir),
|
|
3457
|
+
description: `AI agent working in ${basename2(projDir)}`,
|
|
3458
|
+
version: "1.0.0",
|
|
3459
|
+
url: "",
|
|
3460
|
+
publicKey: publicKeyField,
|
|
3461
|
+
defaultInputModes: ["text/plain"],
|
|
3462
|
+
defaultOutputModes: ["text/plain"],
|
|
3463
|
+
skills: discovered.map((s) => ({
|
|
3464
|
+
id: s.id,
|
|
3465
|
+
name: s.name,
|
|
3466
|
+
description: s.description
|
|
3467
|
+
}))
|
|
3468
|
+
};
|
|
3469
|
+
}
|
|
3470
|
+
if (!card.url) {
|
|
3471
|
+
card.url = `https://agent-${agentId}.newtype-ai.org`;
|
|
3472
|
+
}
|
|
3473
|
+
await writeWorkingCard(nitDir, card);
|
|
3474
|
+
const cardJson = JSON.stringify(card, null, 2);
|
|
3475
|
+
const cardHash = await writeObject(nitDir, "card", cardJson);
|
|
3476
|
+
const commitContent = serializeCommit({
|
|
3477
|
+
card: cardHash,
|
|
3478
|
+
parent: null,
|
|
3479
|
+
author: card.name,
|
|
3480
|
+
timestamp: Math.floor(Date.now() / 1e3),
|
|
3481
|
+
message: "Initial commit"
|
|
3482
|
+
});
|
|
3483
|
+
const commitHash = await writeObject(nitDir, "commit", commitContent);
|
|
3484
|
+
await setBranch(nitDir, "main", commitHash);
|
|
3485
|
+
await setHead(nitDir, "main");
|
|
3486
|
+
await fs7.writeFile(join7(nitDir, "logs", "HEAD"), "", "utf-8");
|
|
3487
|
+
const skillsDir = await discoverSkillsDir(projDir);
|
|
3488
|
+
await writeConfig(nitDir, {
|
|
3489
|
+
remotes: { origin: { url: DEFAULT_API_BASE } },
|
|
3490
|
+
skillsDir
|
|
3491
|
+
});
|
|
3492
|
+
const walletAddresses = await getWalletAddresses(nitDir);
|
|
3493
|
+
return {
|
|
3494
|
+
agentId,
|
|
3495
|
+
publicKey: publicKeyField,
|
|
3496
|
+
cardUrl: card.url,
|
|
3497
|
+
walletAddresses,
|
|
3498
|
+
skillsFound,
|
|
3499
|
+
skillsDir
|
|
3500
|
+
};
|
|
3501
|
+
}
|
|
3502
|
+
async function status(options) {
|
|
3503
|
+
const nitDir = findNitDir(options?.projectDir);
|
|
3504
|
+
const currentBranch = await getCurrentBranch(nitDir);
|
|
3505
|
+
const pubBase64 = await loadPublicKey(nitDir);
|
|
3506
|
+
const publicKey = formatPublicKeyField(pubBase64);
|
|
3507
|
+
const agentId = await loadAgentId(nitDir);
|
|
3508
|
+
const workingCard = await readWorkingCard(nitDir);
|
|
3509
|
+
const cardUrl = workingCard.url || `https://agent-${agentId}.newtype-ai.org`;
|
|
3510
|
+
let uncommittedChanges = null;
|
|
3511
|
+
try {
|
|
3512
|
+
const headHash = await resolveHead(nitDir);
|
|
3513
|
+
const headCard = await getCardAtCommit(nitDir, headHash);
|
|
3514
|
+
const workingCard2 = await readWorkingCard(nitDir);
|
|
3515
|
+
const d = diffCards(headCard, workingCard2);
|
|
3516
|
+
if (d.changed) {
|
|
3517
|
+
uncommittedChanges = d;
|
|
3518
|
+
}
|
|
3519
|
+
} catch {
|
|
3520
|
+
}
|
|
3521
|
+
const branches = await listBranches(nitDir);
|
|
3522
|
+
const branchStatus = [];
|
|
3523
|
+
for (const b of branches) {
|
|
3524
|
+
const remoteHash = await getRemoteRef(nitDir, "origin", b.name);
|
|
3525
|
+
let ahead = 0;
|
|
3526
|
+
if (remoteHash && remoteHash !== b.commitHash) {
|
|
3527
|
+
let hash = b.commitHash;
|
|
3528
|
+
while (hash && hash !== remoteHash) {
|
|
3529
|
+
ahead++;
|
|
3530
|
+
try {
|
|
3531
|
+
const raw = await readObject(nitDir, hash);
|
|
3532
|
+
const c = parseCommit(hash, raw);
|
|
3533
|
+
hash = c.parent;
|
|
3534
|
+
} catch {
|
|
3535
|
+
break;
|
|
3536
|
+
}
|
|
3537
|
+
}
|
|
3538
|
+
} else if (!remoteHash) {
|
|
3539
|
+
let hash = b.commitHash;
|
|
3540
|
+
while (hash) {
|
|
3541
|
+
ahead++;
|
|
3542
|
+
try {
|
|
3543
|
+
const raw = await readObject(nitDir, hash);
|
|
3544
|
+
const c = parseCommit(hash, raw);
|
|
3545
|
+
hash = c.parent;
|
|
3546
|
+
} catch {
|
|
3547
|
+
break;
|
|
3548
|
+
}
|
|
3549
|
+
}
|
|
3550
|
+
}
|
|
3551
|
+
branchStatus.push({ name: b.name, ahead, behind: 0 });
|
|
3552
|
+
}
|
|
3553
|
+
const walletAddresses = await getWalletAddresses(nitDir);
|
|
3554
|
+
return {
|
|
3555
|
+
agentId,
|
|
3556
|
+
cardUrl,
|
|
3557
|
+
branch: currentBranch,
|
|
3558
|
+
publicKey,
|
|
3559
|
+
walletAddresses,
|
|
3560
|
+
uncommittedChanges,
|
|
3561
|
+
branches: branchStatus
|
|
3562
|
+
};
|
|
3563
|
+
}
|
|
3564
|
+
async function sign2(message, options) {
|
|
3565
|
+
const nitDir = findNitDir(options?.projectDir);
|
|
3566
|
+
return signMessage(nitDir, message);
|
|
3567
|
+
}
|
|
3568
|
+
async function loginPayload(domain, options) {
|
|
3569
|
+
const nitDir = findNitDir(options?.projectDir);
|
|
3570
|
+
let switchedBranch;
|
|
3571
|
+
let createdSkill;
|
|
3572
|
+
const currentBranch = await getCurrentBranch(nitDir);
|
|
3573
|
+
if (currentBranch !== domain) {
|
|
3574
|
+
const isNew = !await getBranch(nitDir, domain);
|
|
3575
|
+
if (isNew) {
|
|
3576
|
+
const headHash = await resolveHead(nitDir);
|
|
3577
|
+
await setBranch(nitDir, domain, headHash);
|
|
3578
|
+
}
|
|
3579
|
+
await checkout(domain, options);
|
|
3580
|
+
switchedBranch = domain;
|
|
3581
|
+
}
|
|
3582
|
+
const projectDir2 = dirname2(nitDir);
|
|
3583
|
+
const skillsDir = await getSkillsDir(nitDir) ?? await discoverSkillsDir(projectDir2);
|
|
3584
|
+
if (skillsDir) {
|
|
3585
|
+
const skillId = await createSkillTemplate(skillsDir, domain);
|
|
3586
|
+
const card = await readWorkingCard(nitDir);
|
|
3587
|
+
if (!card.skills.some((s) => s.id === skillId)) {
|
|
3588
|
+
card.skills.push({ id: skillId });
|
|
3589
|
+
await writeWorkingCard(nitDir, card);
|
|
3590
|
+
createdSkill = skillId;
|
|
3591
|
+
}
|
|
3592
|
+
}
|
|
3593
|
+
const agentId = await loadAgentId(nitDir);
|
|
3594
|
+
const timestamp = Math.floor(Date.now() / 1e3);
|
|
3595
|
+
const message = `${agentId}
|
|
3596
|
+
${domain}
|
|
3597
|
+
${timestamp}`;
|
|
3598
|
+
const signature = await signMessage(nitDir, message);
|
|
3599
|
+
return { agent_id: agentId, domain, timestamp, signature, switchedBranch, createdSkill };
|
|
3600
|
+
}
|
|
3601
|
+
async function commit(message, options) {
|
|
3602
|
+
const nitDir = findNitDir(options?.projectDir);
|
|
3603
|
+
const projDir = projectDir(nitDir);
|
|
3604
|
+
let card = await readWorkingCard(nitDir);
|
|
3605
|
+
card = await resolveSkillPointers(card, projDir);
|
|
3606
|
+
const pubBase64 = await loadPublicKey(nitDir);
|
|
3607
|
+
card.publicKey = formatPublicKeyField(pubBase64);
|
|
3608
|
+
await writeWorkingCard(nitDir, card);
|
|
3609
|
+
const cardJson = JSON.stringify(card, null, 2);
|
|
3610
|
+
const cardHash = await writeObject(nitDir, "card", cardJson);
|
|
3611
|
+
const currentBranch = await getCurrentBranch(nitDir);
|
|
3612
|
+
const parentHash = await getBranch(nitDir, currentBranch);
|
|
3613
|
+
if (parentHash) {
|
|
3614
|
+
const parentRaw = await readObject(nitDir, parentHash);
|
|
3615
|
+
const parentCommit = parseCommit(parentHash, parentRaw);
|
|
3616
|
+
if (parentCommit.card === cardHash) {
|
|
3617
|
+
throw new Error("Nothing to commit \u2014 agent card is unchanged.");
|
|
3618
|
+
}
|
|
3619
|
+
}
|
|
3620
|
+
const author = await getAuthorName(nitDir);
|
|
3621
|
+
const commitContent = serializeCommit({
|
|
3622
|
+
card: cardHash,
|
|
3623
|
+
parent: parentHash,
|
|
3624
|
+
author,
|
|
3625
|
+
timestamp: Math.floor(Date.now() / 1e3),
|
|
3626
|
+
message
|
|
3627
|
+
});
|
|
3628
|
+
const commitHash = await writeObject(nitDir, "commit", commitContent);
|
|
3629
|
+
await setBranch(nitDir, currentBranch, commitHash);
|
|
3630
|
+
return {
|
|
3631
|
+
type: "commit",
|
|
3632
|
+
hash: commitHash,
|
|
3633
|
+
card: cardHash,
|
|
3634
|
+
parent: parentHash,
|
|
3635
|
+
author,
|
|
3636
|
+
timestamp: Math.floor(Date.now() / 1e3),
|
|
3637
|
+
message
|
|
3638
|
+
};
|
|
3639
|
+
}
|
|
3640
|
+
async function log(options) {
|
|
3641
|
+
const nitDir = findNitDir(options?.projectDir);
|
|
3642
|
+
const currentBranch = await getCurrentBranch(nitDir);
|
|
3643
|
+
let hash = await getBranch(nitDir, currentBranch);
|
|
3644
|
+
const commits = [];
|
|
3645
|
+
const limit = options?.count ?? 50;
|
|
3646
|
+
while (hash && commits.length < limit) {
|
|
3647
|
+
const raw = await readObject(nitDir, hash);
|
|
3648
|
+
const c = parseCommit(hash, raw);
|
|
3649
|
+
commits.push(c);
|
|
3650
|
+
hash = c.parent;
|
|
3651
|
+
}
|
|
3652
|
+
return commits;
|
|
3653
|
+
}
|
|
3654
|
+
async function diff(target, options) {
|
|
3655
|
+
const nitDir = findNitDir(options?.projectDir);
|
|
3656
|
+
if (!target) {
|
|
3657
|
+
const headHash2 = await resolveHead(nitDir);
|
|
3658
|
+
const headCard2 = await getCardAtCommit(nitDir, headHash2);
|
|
3659
|
+
const workingCard = await readWorkingCard(nitDir);
|
|
3660
|
+
return diffCards(headCard2, workingCard);
|
|
3661
|
+
}
|
|
3662
|
+
const targetBranchHash = await getBranch(nitDir, target);
|
|
3663
|
+
const headHash = await resolveHead(nitDir);
|
|
3664
|
+
const headCard = await getCardAtCommit(nitDir, headHash);
|
|
3665
|
+
if (targetBranchHash) {
|
|
3666
|
+
const targetCard = await getCardAtCommit(nitDir, targetBranchHash);
|
|
3667
|
+
return diffCards(headCard, targetCard);
|
|
3668
|
+
}
|
|
3669
|
+
if (/^[0-9a-f]{64}$/.test(target)) {
|
|
3670
|
+
const targetCard = await getCardAtCommit(nitDir, target);
|
|
3671
|
+
return diffCards(headCard, targetCard);
|
|
3672
|
+
}
|
|
3673
|
+
throw new Error(
|
|
3674
|
+
`Unknown target "${target}". Provide a branch name or commit hash.`
|
|
3675
|
+
);
|
|
3676
|
+
}
|
|
3677
|
+
async function branch(name, options) {
|
|
3678
|
+
const nitDir = findNitDir(options?.projectDir);
|
|
3679
|
+
if (name) {
|
|
3680
|
+
const existing = await getBranch(nitDir, name);
|
|
3681
|
+
if (existing) {
|
|
3682
|
+
throw new Error(`Branch "${name}" already exists.`);
|
|
3683
|
+
}
|
|
3684
|
+
const headHash = await resolveHead(nitDir);
|
|
3685
|
+
await setBranch(nitDir, name, headHash);
|
|
3686
|
+
}
|
|
3687
|
+
return listBranches(nitDir);
|
|
3688
|
+
}
|
|
3689
|
+
async function checkout(branchName, options) {
|
|
3690
|
+
const nitDir = findNitDir(options?.projectDir);
|
|
3691
|
+
try {
|
|
3692
|
+
const headHash = await resolveHead(nitDir);
|
|
3693
|
+
const headCard = await getCardAtCommit(nitDir, headHash);
|
|
3694
|
+
const workingCard = await readWorkingCard(nitDir);
|
|
3695
|
+
const d = diffCards(headCard, workingCard);
|
|
3696
|
+
if (d.changed) {
|
|
3697
|
+
throw new Error(
|
|
3698
|
+
"You have uncommitted changes. Commit or discard them before switching branches."
|
|
3699
|
+
);
|
|
3700
|
+
}
|
|
3701
|
+
} catch (err) {
|
|
3702
|
+
if (err instanceof Error && err.message.includes("uncommitted changes")) {
|
|
3703
|
+
throw err;
|
|
3704
|
+
}
|
|
3705
|
+
}
|
|
3706
|
+
const targetHash = await getBranch(nitDir, branchName);
|
|
3707
|
+
if (!targetHash) {
|
|
3708
|
+
throw new Error(`Branch "${branchName}" does not exist.`);
|
|
3709
|
+
}
|
|
3710
|
+
const targetCard = await getCardAtCommit(nitDir, targetHash);
|
|
3711
|
+
await writeWorkingCard(nitDir, targetCard);
|
|
3712
|
+
await setHead(nitDir, branchName);
|
|
3713
|
+
}
|
|
3714
|
+
async function push(options) {
|
|
3715
|
+
const nitDir = findNitDir(options?.projectDir);
|
|
3716
|
+
const remoteName = options?.remoteName || "origin";
|
|
3717
|
+
const apiBase = await getRemoteUrl(nitDir, remoteName) || DEFAULT_API_BASE;
|
|
3718
|
+
const branches = await listBranches(nitDir);
|
|
3719
|
+
const currentBranch = await getCurrentBranch(nitDir);
|
|
3720
|
+
const toPush = options?.all ? branches : branches.filter((b) => b.name === currentBranch);
|
|
3721
|
+
if (toPush.length === 0) {
|
|
3722
|
+
throw new Error("No branches to push.");
|
|
3723
|
+
}
|
|
3724
|
+
const results = [];
|
|
3725
|
+
for (const b of toPush) {
|
|
3726
|
+
const commitRaw = await readObject(nitDir, b.commitHash);
|
|
3727
|
+
const c = parseCommit(b.commitHash, commitRaw);
|
|
3728
|
+
const cardJson = await readObject(nitDir, c.card);
|
|
3729
|
+
const result = await pushBranch(
|
|
3730
|
+
nitDir,
|
|
3731
|
+
apiBase,
|
|
3732
|
+
b.name,
|
|
3733
|
+
cardJson,
|
|
3734
|
+
b.commitHash
|
|
3735
|
+
);
|
|
3736
|
+
if (result.success) {
|
|
3737
|
+
await setRemoteRef(nitDir, remoteName, b.name, b.commitHash);
|
|
3738
|
+
}
|
|
3739
|
+
results.push(result);
|
|
3740
|
+
}
|
|
3741
|
+
return results;
|
|
3742
|
+
}
|
|
3743
|
+
async function remote(options) {
|
|
3744
|
+
const nitDir = findNitDir(options?.projectDir);
|
|
3745
|
+
const remoteUrl = await getRemoteUrl(nitDir, "origin");
|
|
3746
|
+
const agentId = await loadAgentId(nitDir);
|
|
3747
|
+
return {
|
|
3748
|
+
name: "origin",
|
|
3749
|
+
url: remoteUrl || DEFAULT_API_BASE,
|
|
3750
|
+
agentId
|
|
3751
|
+
};
|
|
3752
|
+
}
|
|
3753
|
+
async function remoteAdd(name, url, options) {
|
|
3754
|
+
const nitDir = findNitDir(options?.projectDir);
|
|
3755
|
+
const config = await readConfig(nitDir);
|
|
3756
|
+
if (config.remotes[name]) {
|
|
3757
|
+
throw new Error(
|
|
3758
|
+
`Remote "${name}" already exists. Use 'nit remote set-url ${name} <url>' to change it.`
|
|
3759
|
+
);
|
|
3760
|
+
}
|
|
3761
|
+
config.remotes[name] = { url };
|
|
3762
|
+
await writeConfig(nitDir, config);
|
|
3763
|
+
}
|
|
3764
|
+
async function remoteSetUrl(name, url, options) {
|
|
3765
|
+
const nitDir = findNitDir(options?.projectDir);
|
|
3766
|
+
const config = await readConfig(nitDir);
|
|
3767
|
+
if (!config.remotes[name]) {
|
|
3768
|
+
throw new Error(
|
|
3769
|
+
`Remote "${name}" does not exist. Use 'nit remote add ${name} <url>' to create it.`
|
|
3770
|
+
);
|
|
3771
|
+
}
|
|
3772
|
+
config.remotes[name].url = url;
|
|
3773
|
+
await writeConfig(nitDir, config);
|
|
3774
|
+
}
|
|
3775
|
+
async function signTx2(chain, data, options) {
|
|
3776
|
+
const nitDir = findNitDir(options?.projectDir);
|
|
3777
|
+
return signTx(nitDir, chain, data);
|
|
3778
|
+
}
|
|
3779
|
+
async function broadcast2(chain, signedTx, options) {
|
|
3780
|
+
const nitDir = findNitDir(options?.projectDir);
|
|
3781
|
+
return broadcast(nitDir, chain, signedTx, options?.rpcUrl);
|
|
3782
|
+
}
|
|
3783
|
+
async function rpcSetUrl(chain, url, options) {
|
|
3784
|
+
const nitDir = findNitDir(options?.projectDir);
|
|
3785
|
+
await setRpcUrl(nitDir, chain, url);
|
|
3786
|
+
}
|
|
3787
|
+
async function rpcInfo(options) {
|
|
3788
|
+
const nitDir = findNitDir(options?.projectDir);
|
|
3789
|
+
const config = await readConfig(nitDir);
|
|
3790
|
+
return config.rpc ?? {};
|
|
3791
|
+
}
|
|
3792
|
+
|
|
3793
|
+
export {
|
|
3794
|
+
loadRawKeyPair,
|
|
3795
|
+
formatPublicKeyField,
|
|
3796
|
+
parsePublicKeyField,
|
|
3797
|
+
signChallenge,
|
|
3798
|
+
signMessage,
|
|
3799
|
+
NIT_NAMESPACE,
|
|
3800
|
+
deriveAgentId,
|
|
3801
|
+
loadAgentId,
|
|
3802
|
+
base58Encode,
|
|
3803
|
+
getSolanaAddress,
|
|
3804
|
+
getEvmAddress,
|
|
3805
|
+
getWalletAddresses,
|
|
3806
|
+
loadSecp256k1RawKeyPair,
|
|
3807
|
+
signEvmHash,
|
|
3808
|
+
signSolanaBytes,
|
|
3809
|
+
diffCards,
|
|
3810
|
+
formatDiff,
|
|
3811
|
+
fetchBranchCard,
|
|
3812
|
+
findNitDir,
|
|
3813
|
+
init,
|
|
3814
|
+
status,
|
|
3815
|
+
sign2 as sign,
|
|
3816
|
+
loginPayload,
|
|
3817
|
+
commit,
|
|
3818
|
+
log,
|
|
3819
|
+
diff,
|
|
3820
|
+
branch,
|
|
3821
|
+
checkout,
|
|
3822
|
+
push,
|
|
3823
|
+
remote,
|
|
3824
|
+
remoteAdd,
|
|
3825
|
+
remoteSetUrl,
|
|
3826
|
+
signTx2 as signTx,
|
|
3827
|
+
broadcast2 as broadcast,
|
|
3828
|
+
rpcSetUrl,
|
|
3829
|
+
rpcInfo
|
|
3830
|
+
};
|
|
3831
|
+
/*! Bundled license information:
|
|
3832
|
+
|
|
3833
|
+
@noble/hashes/utils.js:
|
|
3834
|
+
(*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) *)
|
|
3835
|
+
|
|
3836
|
+
@noble/curves/utils.js:
|
|
3837
|
+
@noble/curves/abstract/modular.js:
|
|
3838
|
+
@noble/curves/abstract/curve.js:
|
|
3839
|
+
@noble/curves/abstract/weierstrass.js:
|
|
3840
|
+
@noble/curves/secp256k1.js:
|
|
3841
|
+
(*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) *)
|
|
3842
|
+
*/
|