@provablehq/sdk 0.9.16-rc → 0.9.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/mainnet/account.d.ts +18 -3
- package/dist/mainnet/browser.d.ts +26 -7
- package/dist/mainnet/browser.js +1198 -248
- package/dist/mainnet/browser.js.map +1 -1
- package/dist/mainnet/keys/keystore/error.d.ts +23 -0
- package/dist/mainnet/keys/keystore/file.d.ts +207 -13
- package/dist/mainnet/keys/keystore/interface.d.ts +85 -0
- package/dist/mainnet/keys/provider/interface.d.ts +170 -0
- package/dist/{testnet/keys/provider/function-key-provider.d.ts → mainnet/keys/provider/memory.d.ts} +14 -180
- package/dist/{testnet/keys/provider/offline-key-provider.d.ts → mainnet/keys/provider/offline.d.ts} +4 -4
- package/dist/mainnet/keys/verifier/interface.d.ts +70 -0
- package/dist/mainnet/keys/verifier/memory.d.ts +37 -0
- package/dist/mainnet/models/cryptoBoxPubkey.d.ts +4 -0
- package/dist/mainnet/models/encryptedProvingRequest.d.ts +4 -0
- package/dist/mainnet/models/provingResponse.d.ts +48 -2
- package/dist/mainnet/models/record-scanner/encryptedRecordsResult.d.ts +7 -0
- package/dist/mainnet/models/record-scanner/encryptedRegistrationRequest.d.ts +8 -0
- package/dist/mainnet/models/record-scanner/error.d.ts +47 -0
- package/dist/mainnet/models/record-scanner/ownedFilter.d.ts +0 -2
- package/dist/mainnet/models/record-scanner/ownedRecordsResult.d.ts +13 -0
- package/dist/mainnet/models/record-scanner/registrationResponse.d.ts +0 -2
- package/dist/mainnet/models/record-scanner/registrationResult.d.ts +9 -0
- package/dist/mainnet/models/record-scanner/revokeResult.d.ts +17 -0
- package/dist/mainnet/models/record-scanner/serialNumbersResult.d.ts +15 -0
- package/dist/mainnet/models/record-scanner/statusResult.d.ts +13 -0
- package/dist/mainnet/models/record-scanner/tagsResult.d.ts +12 -0
- package/dist/mainnet/network-client.d.ts +81 -35
- package/dist/mainnet/node.js +345 -75
- package/dist/mainnet/node.js.map +1 -1
- package/dist/mainnet/program-manager.d.ts +54 -48
- package/dist/mainnet/record-provider.d.ts +7 -7
- package/dist/mainnet/record-scanner.d.ts +247 -31
- package/dist/mainnet/security.d.ts +38 -0
- package/dist/mainnet/utils.d.ts +1 -0
- package/dist/testnet/account.d.ts +18 -3
- package/dist/testnet/browser.d.ts +26 -7
- package/dist/testnet/browser.js +1198 -248
- package/dist/testnet/browser.js.map +1 -1
- package/dist/testnet/keys/keystore/error.d.ts +23 -0
- package/dist/testnet/keys/keystore/file.d.ts +207 -13
- package/dist/testnet/keys/keystore/interface.d.ts +85 -0
- package/dist/testnet/keys/provider/interface.d.ts +170 -0
- package/dist/{mainnet/keys/provider/function-key-provider.d.ts → testnet/keys/provider/memory.d.ts} +14 -180
- package/dist/{mainnet/keys/provider/offline-key-provider.d.ts → testnet/keys/provider/offline.d.ts} +4 -4
- package/dist/testnet/keys/verifier/interface.d.ts +70 -0
- package/dist/testnet/keys/verifier/memory.d.ts +37 -0
- package/dist/testnet/models/cryptoBoxPubkey.d.ts +4 -0
- package/dist/testnet/models/encryptedProvingRequest.d.ts +4 -0
- package/dist/testnet/models/provingResponse.d.ts +48 -2
- package/dist/testnet/models/record-scanner/encryptedRecordsResult.d.ts +7 -0
- package/dist/testnet/models/record-scanner/encryptedRegistrationRequest.d.ts +8 -0
- package/dist/testnet/models/record-scanner/error.d.ts +47 -0
- package/dist/testnet/models/record-scanner/ownedFilter.d.ts +0 -2
- package/dist/testnet/models/record-scanner/ownedRecordsResult.d.ts +13 -0
- package/dist/testnet/models/record-scanner/registrationResponse.d.ts +0 -2
- package/dist/testnet/models/record-scanner/registrationResult.d.ts +9 -0
- package/dist/testnet/models/record-scanner/revokeResult.d.ts +17 -0
- package/dist/testnet/models/record-scanner/serialNumbersResult.d.ts +15 -0
- package/dist/testnet/models/record-scanner/statusResult.d.ts +13 -0
- package/dist/testnet/models/record-scanner/tagsResult.d.ts +12 -0
- package/dist/testnet/network-client.d.ts +81 -35
- package/dist/testnet/node.js +345 -75
- package/dist/testnet/node.js.map +1 -1
- package/dist/testnet/program-manager.d.ts +54 -48
- package/dist/testnet/record-provider.d.ts +7 -7
- package/dist/testnet/record-scanner.d.ts +247 -31
- package/dist/testnet/security.d.ts +38 -0
- package/dist/testnet/utils.d.ts +1 -0
- package/package.json +4 -3
- package/dist/mainnet/keys/keystore/keystore.d.ts +0 -81
- package/dist/mainnet/keys/keystore/memory.d.ts +0 -8
- package/dist/testnet/keys/keystore/keystore.d.ts +0 -81
- package/dist/testnet/keys/keystore/memory.d.ts +0 -8
package/dist/testnet/node.js
CHANGED
|
@@ -1,32 +1,105 @@
|
|
|
1
1
|
import './node-polyfill.js';
|
|
2
2
|
import * as fs from 'node:fs/promises';
|
|
3
|
+
import * as $fs from 'node:fs';
|
|
3
4
|
import * as path from 'path';
|
|
5
|
+
import { MemKeyVerifier, InvalidLocatorError } from './browser.js';
|
|
6
|
+
export { Account, AleoKeyProvider, AleoKeyProviderParams, AleoNetworkClient, BlockHeightSearch, CREDITS_PROGRAM_KEYS, KeyVerificationError as ChecksumMismatchError, DecryptionNotEnabledError, KEY_STORE, KeyVerificationError, NetworkRecordProvider, OfflineKeyProvider, OfflineSearchParams, PRIVATE_TO_PUBLIC_TRANSFER, PRIVATE_TRANSFER, PRIVATE_TRANSFER_TYPES, PUBLIC_TO_PRIVATE_TRANSFER, PUBLIC_TRANSFER, PUBLIC_TRANSFER_AS_SIGNER, ProgramManager, RECORD_DOMAIN, RecordNotFoundError, RecordScanner, RecordScannerRequestError, SealanceMerkleTree, UUIDError, VALID_TRANSFER_TYPES, ViewKeyNotStoredError, encryptAuthorization, encryptProvingRequest, encryptRegistrationRequest, encryptViewKey, initializeWasm, isProveApiErrorBody, isProvingResponse, logAndThrow, sha256Hex } from './browser.js';
|
|
4
7
|
import { ProvingKey, VerifyingKey } from '@provablehq/wasm/testnet.js';
|
|
5
8
|
export { Address, Authorization, BHP1024, BHP256, BHP512, BHP768, Boolean, Ciphertext, ComputeKey, EncryptionToolkit, ExecutionRequest, ExecutionResponse, Field, Execution as FunctionExecution, GraphKey, Group, I128, I16, I32, I64, I8, OfflineQuery, Pedersen128, Pedersen64, Plaintext, Poseidon2, Poseidon4, Poseidon8, PrivateKey, PrivateKeyCiphertext, Program, ProgramManager as ProgramManagerBase, ProvingKey, ProvingRequest, RecordCiphertext, RecordPlaintext, Scalar, Signature, Transaction, Transition, U128, U16, U32, U64, U8, VerifyingKey, ViewKey, getOrInitConsensusVersionTestHeights, initThreadPool, verifyFunctionExecution } from '@provablehq/wasm/testnet.js';
|
|
6
|
-
export { Account, AleoKeyProvider, AleoKeyProviderParams, AleoNetworkClient, BlockHeightSearch, CREDITS_PROGRAM_KEYS, KEY_STORE, NetworkRecordProvider, OfflineKeyProvider, OfflineSearchParams, PRIVATE_TO_PUBLIC_TRANSFER, PRIVATE_TRANSFER, PRIVATE_TRANSFER_TYPES, PUBLIC_TO_PRIVATE_TRANSFER, PUBLIC_TRANSFER, PUBLIC_TRANSFER_AS_SIGNER, ProgramManager, RECORD_DOMAIN, RecordScanner, SealanceMerkleTree, VALID_TRANSFER_TYPES, initializeWasm, logAndThrow, promoteMapToKeyStore } from './browser.js';
|
|
7
9
|
import 'core-js/proposals/json-parse-with-source.js';
|
|
8
10
|
import 'node:crypto';
|
|
9
|
-
import 'node:fs';
|
|
10
11
|
import 'mime/lite';
|
|
11
12
|
import 'xmlhttprequest-ssl';
|
|
12
13
|
import 'node:worker_threads';
|
|
13
14
|
import 'node:os';
|
|
15
|
+
import 'libsodium-wrappers';
|
|
14
16
|
import '@scure/base';
|
|
15
17
|
|
|
16
18
|
class LocalFileKeyStore {
|
|
17
19
|
directory;
|
|
20
|
+
keyVerifier = new MemKeyVerifier();
|
|
21
|
+
/**
|
|
22
|
+
* Creates a new directory at the given path or CURRENTDIR/.aleo if none is provided to store keys.
|
|
23
|
+
* If a custom directory is passed and its last path segment is not ".aleo", ".aleo" is appended
|
|
24
|
+
* so keys are stored under that subdirectory (e.g. /home/project → /home/project/.aleo).
|
|
25
|
+
*
|
|
26
|
+
* @param {string} [directory] - Optional custom directory path for key storage. Defaults to ".aleo" in current working directory.
|
|
27
|
+
* @throws {Error} If directory creation fails.
|
|
28
|
+
*/
|
|
18
29
|
constructor(directory) {
|
|
19
|
-
this.directory = directory ?? path.join(process.cwd(), "
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
});
|
|
30
|
+
this.directory = directory ?? path.join(process.cwd(), ".aleo");
|
|
31
|
+
if (directory !== undefined && path.basename(this.directory) !== ".aleo") {
|
|
32
|
+
this.directory = path.join(this.directory, ".aleo");
|
|
33
|
+
}
|
|
34
|
+
$fs.mkdirSync(this.directory, { recursive: true });
|
|
24
35
|
}
|
|
25
|
-
|
|
26
|
-
|
|
36
|
+
/**
|
|
37
|
+
* Validates that a locator is a safe filesystem identifier.
|
|
38
|
+
*
|
|
39
|
+
* @private
|
|
40
|
+
* @param {string} locator - Unique identifier used to derive a metadata file path.
|
|
41
|
+
* @throws {InvalidLocatorError} If the locator could cause path traversal.
|
|
42
|
+
*/
|
|
43
|
+
validateLocator(locator) {
|
|
44
|
+
// Reject empty and reserved names that could resolve to the directory or parent
|
|
45
|
+
if (locator === "" || locator === "." || locator === "..") {
|
|
46
|
+
throw new InvalidLocatorError(`Invalid locator: reserved or empty name "${locator}"`, locator, "reserved_name");
|
|
47
|
+
}
|
|
48
|
+
// Explicitly block traversal attempts
|
|
49
|
+
if (locator.includes("..")) {
|
|
50
|
+
throw new InvalidLocatorError("Invalid locator: path traversal detected", locator, "path_traversal");
|
|
51
|
+
}
|
|
52
|
+
// Block path separators and null byte
|
|
53
|
+
if (locator.includes("/") || locator.includes("\\") || locator.includes("\0")) {
|
|
54
|
+
throw new InvalidLocatorError("Invalid locator: path separator or null byte not allowed", locator, "path_separator");
|
|
55
|
+
}
|
|
27
56
|
}
|
|
28
|
-
|
|
29
|
-
|
|
57
|
+
/**
|
|
58
|
+
* Generates the path for a key metadata file based on the locator.
|
|
59
|
+
*
|
|
60
|
+
* @private
|
|
61
|
+
* @param {string} locator - Unique identifier for the key.
|
|
62
|
+
* @returns {string} Full filesystem path to the metadata file.
|
|
63
|
+
*/
|
|
64
|
+
metadataPath(locator) {
|
|
65
|
+
return path.join(this.directory, `${locator}.metadata`);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Reads and parses the key fingerprint metadata from storage.
|
|
69
|
+
*
|
|
70
|
+
* @private
|
|
71
|
+
* @param {string} locator - Unique identifier for the key.
|
|
72
|
+
* @returns {Promise<KeyFingerprint | null>} The key fingerprint if found, null if file doesn't exist.
|
|
73
|
+
* @throws {Error} If file read fails for any reason other than not found.
|
|
74
|
+
*/
|
|
75
|
+
async readKeyMetadata(locator) {
|
|
76
|
+
try {
|
|
77
|
+
const data = await fs.readFile(this.metadataPath(locator), "utf-8");
|
|
78
|
+
return JSON.parse(data);
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
if (err &&
|
|
82
|
+
typeof err === "object" &&
|
|
83
|
+
"code" in err &&
|
|
84
|
+
err.code === "ENOENT")
|
|
85
|
+
return null;
|
|
86
|
+
throw err;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Writes key fingerprint metadata to storage.
|
|
91
|
+
*
|
|
92
|
+
* @private
|
|
93
|
+
* @param {string} locator - Unique identifier for the key.
|
|
94
|
+
* @param {KeyFingerprint} metadata - Key fingerprint metadata to store.
|
|
95
|
+
* @returns {Promise<void>}
|
|
96
|
+
* @throws {Error} If directory creation or file write fails.
|
|
97
|
+
*/
|
|
98
|
+
async writeKeyMetadata(locator, metadata) {
|
|
99
|
+
await fs.mkdir(path.dirname(this.metadataPath(locator)), {
|
|
100
|
+
recursive: true,
|
|
101
|
+
});
|
|
102
|
+
await fs.writeFile(this.metadataPath(locator), JSON.stringify(metadata, null, 0), "utf-8");
|
|
30
103
|
}
|
|
31
104
|
async readFileOptional(filepath) {
|
|
32
105
|
try {
|
|
@@ -39,102 +112,299 @@ class LocalFileKeyStore {
|
|
|
39
112
|
throw err;
|
|
40
113
|
}
|
|
41
114
|
}
|
|
115
|
+
/**
|
|
116
|
+
* Atomically writes data to a file, ensuring the parent directories exist.
|
|
117
|
+
*
|
|
118
|
+
* @private
|
|
119
|
+
* @param {string} filepath - Full path to the file to write
|
|
120
|
+
* @param {Uint8Array} data - Binary data to write to the file
|
|
121
|
+
* @returns {Promise<void>} Resolves when write is complete
|
|
122
|
+
* @throws {Error} If directory creation or file write fails
|
|
123
|
+
*/
|
|
42
124
|
async writeFileAtomic(filepath, data) {
|
|
43
|
-
|
|
44
|
-
await fs.mkdir(
|
|
45
|
-
|
|
125
|
+
const dir = path.dirname(filepath);
|
|
126
|
+
await fs.mkdir(dir, { recursive: true });
|
|
127
|
+
const tempPath = path.join(dir, `.${path.basename(filepath)}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`);
|
|
128
|
+
await fs.writeFile(tempPath, data);
|
|
129
|
+
try {
|
|
130
|
+
await fs.rename(tempPath, filepath);
|
|
131
|
+
}
|
|
132
|
+
catch (err) {
|
|
133
|
+
const code = err && typeof err === "object" && "code" in err ? err.code : undefined;
|
|
134
|
+
// Windows often throws EEXIST when target exists; EPERM/EACCES happen with locks/AV.
|
|
135
|
+
if (code === "EEXIST" || code === "EPERM" || code === "EACCES") {
|
|
136
|
+
await fs.unlink(filepath).catch(() => { });
|
|
137
|
+
try {
|
|
138
|
+
await fs.rename(tempPath, filepath);
|
|
139
|
+
}
|
|
140
|
+
catch (err2) {
|
|
141
|
+
await fs.unlink(tempPath).catch(() => { });
|
|
142
|
+
throw err2;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
await fs.unlink(tempPath).catch(() => { });
|
|
147
|
+
throw err;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
46
150
|
}
|
|
47
|
-
|
|
48
|
-
|
|
151
|
+
/**
|
|
152
|
+
* Recursively removes all files and subdirectories under the given directory, then removes the directory itself.
|
|
153
|
+
* Uses fs.rm with recursive: true and force: true so that symbolic links are removed without following them,
|
|
154
|
+
* avoiding deletion of content outside the keystore.
|
|
155
|
+
*
|
|
156
|
+
* @private
|
|
157
|
+
* @param {string} dir - Directory path to clear
|
|
158
|
+
* @returns {Promise<void>} Resolves when clearing is complete
|
|
159
|
+
* @throws {Error} If directory removal fails for reasons other than non-existence
|
|
160
|
+
*/
|
|
161
|
+
async clearDirectory(dir) {
|
|
49
162
|
try {
|
|
50
|
-
|
|
163
|
+
await fs.rm(dir, { recursive: true, force: true });
|
|
51
164
|
}
|
|
52
165
|
catch (err) {
|
|
53
|
-
|
|
166
|
+
const code = err && typeof err === "object" && "code" in err ? err.code : undefined;
|
|
167
|
+
if (code === "ENOENT") {
|
|
54
168
|
return;
|
|
55
169
|
}
|
|
56
170
|
throw err;
|
|
57
171
|
}
|
|
58
|
-
await Promise.all(entries.map(async (name) => {
|
|
59
|
-
const full = path.join(dir, name);
|
|
60
|
-
let isDirectory = false;
|
|
61
|
-
try {
|
|
62
|
-
const stat = await fs.stat(full);
|
|
63
|
-
isDirectory = stat.isDirectory();
|
|
64
|
-
}
|
|
65
|
-
catch {
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
if (isDirectory) {
|
|
69
|
-
await this.clearRecursive(full);
|
|
70
|
-
}
|
|
71
|
-
else if (name.endsWith(".prover") || name.endsWith(".verifier")) {
|
|
72
|
-
await fs.unlink(full).catch(() => { });
|
|
73
|
-
}
|
|
74
|
-
}));
|
|
75
172
|
}
|
|
76
173
|
// -------------------------------------------------------
|
|
77
174
|
// KEYSTORE INTERFACE
|
|
78
175
|
// -------------------------------------------------------
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
176
|
+
/**
|
|
177
|
+
* Retrieves the key bytes from storage and optionally verifies them against a fingerprint.
|
|
178
|
+
*
|
|
179
|
+
* @param {KeyLocator} locator - Object containing a locator string for the key + optional fingerprint for verification.
|
|
180
|
+
* @returns {Promise<Uint8Array | null>} The key bytes if found and verified (if fingerprint provided), null if not found.
|
|
181
|
+
* @throws {KeyVerificationError} If fingerprint verification fails.
|
|
182
|
+
* @example
|
|
183
|
+
* const keyBytes = await getKeyBytes({
|
|
184
|
+
* locator: 'transfer_private.prover.421e5a5',
|
|
185
|
+
* fingerprint: { checksum: '421e5a52f01a1eeb068bbf56d15e19477ff7290e4b988d1013e15563f2b77801', size: 116746954 }
|
|
186
|
+
* });
|
|
187
|
+
* if (keyBytes) {
|
|
188
|
+
* // Use the verified key bytes
|
|
189
|
+
* }
|
|
190
|
+
*/
|
|
86
191
|
async getKeyBytes(locator) {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
192
|
+
this.validateLocator(locator.locator);
|
|
193
|
+
// Attempt to read key bytes from storage (under this.directory).
|
|
194
|
+
const keyBytes = await this.readFileOptional(path.join(this.directory, locator.locator));
|
|
195
|
+
// If no key bytes were found, return null.
|
|
196
|
+
if (!keyBytes)
|
|
90
197
|
return null;
|
|
91
|
-
|
|
198
|
+
// Use caller-provided fingerprint or metadata stored on disk for verification.
|
|
199
|
+
const fingerprint = locator.fingerprint ?? (await this.getKeyMetadata(locator.locator));
|
|
200
|
+
if (fingerprint) {
|
|
201
|
+
await this.keyVerifier.verifyKeyBytes({
|
|
202
|
+
keyBytes,
|
|
203
|
+
locator: locator.locator,
|
|
204
|
+
fingerprint,
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
// Return the verified key bytes.
|
|
208
|
+
return keyBytes;
|
|
92
209
|
}
|
|
210
|
+
/**
|
|
211
|
+
* Retrieves and verifies a proving key from storage.
|
|
212
|
+
*
|
|
213
|
+
* @param {KeyLocator} locator - Object containing the proving key location and optional fingerprint.
|
|
214
|
+
* @returns {Promise<ProvingKey | null>} The proving key if found and verified, null if not found.
|
|
215
|
+
* @throws {KeyVerificationError} If fingerprint verification fails.
|
|
216
|
+
* @throws {Error} If key bytes cannot be parsed into a valid ProvingKey.
|
|
217
|
+
*
|
|
218
|
+
* @example
|
|
219
|
+
* try {
|
|
220
|
+
* const key = await getProvingKey({
|
|
221
|
+
* locator: 'transfer_private.prover.421e5a5'
|
|
222
|
+
* });
|
|
223
|
+
* if (key) {
|
|
224
|
+
* // Use the verified proving key
|
|
225
|
+
* }
|
|
226
|
+
* } catch (err) {
|
|
227
|
+
* if (err instanceof KeyVerificationError) {
|
|
228
|
+
* // Handle verification failure.
|
|
229
|
+
* } else {
|
|
230
|
+
* // Handle key parsing error.
|
|
231
|
+
* }
|
|
232
|
+
* }
|
|
233
|
+
*/
|
|
93
234
|
async getProvingKey(locator) {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
235
|
+
// Get the key bytes from storage.
|
|
236
|
+
const proverBytes = await this.getKeyBytes(locator);
|
|
237
|
+
if (!proverBytes)
|
|
238
|
+
return null;
|
|
239
|
+
// Attempt to parse the key bytes as a WASM ProvingKey (throws if invalid).
|
|
240
|
+
return ProvingKey.fromBytes(proverBytes);
|
|
99
241
|
}
|
|
242
|
+
/**
|
|
243
|
+
* Retrieves and verifies a verifying key from storage.
|
|
244
|
+
*
|
|
245
|
+
* @param {KeyLocator} locator - Object containing the verifying key location and optional fingerprint.
|
|
246
|
+
* @returns {Promise<VerifyingKey | null>} The verifying key if found and verified, null if not found.
|
|
247
|
+
* @throws {KeyVerificationError} If fingerprint verification fails.
|
|
248
|
+
* @throws {Error} If key bytes cannot be parsed into a valid VerifyingKey.
|
|
249
|
+
*
|
|
250
|
+
* @example
|
|
251
|
+
* try {
|
|
252
|
+
* const key = await getVerifyingKey({
|
|
253
|
+
* locator: 'transfer_private.verifier.4ac2f71'
|
|
254
|
+
* });
|
|
255
|
+
* if (key) {
|
|
256
|
+
* // Use the verified verifying key
|
|
257
|
+
* }
|
|
258
|
+
* } catch (err) {
|
|
259
|
+
* if (err instanceof KeyVerificationError) {
|
|
260
|
+
* // Handle verification failure.
|
|
261
|
+
* } else {
|
|
262
|
+
* // Handle key parsing error.
|
|
263
|
+
* }
|
|
264
|
+
* }
|
|
265
|
+
*/
|
|
100
266
|
async getVerifyingKey(locator) {
|
|
101
|
-
|
|
102
|
-
|
|
267
|
+
// Get the key bytes from storage.
|
|
268
|
+
const verifierBytes = await this.getKeyBytes(locator);
|
|
269
|
+
if (!verifierBytes)
|
|
270
|
+
return null;
|
|
271
|
+
// Attempt to parse the key bytes as a WASM VerifyingKey (throws if invalid).
|
|
272
|
+
return VerifyingKey.fromBytes(verifierBytes);
|
|
103
273
|
}
|
|
104
|
-
|
|
105
|
-
|
|
274
|
+
/**
|
|
275
|
+
* Stores proving and verifying keys in key storage.
|
|
276
|
+
*
|
|
277
|
+
* @param {KeyLocator} proverLocator The unique locator for the desired proving key.
|
|
278
|
+
* @param {KeyLocator} verifierLocator The unique locator for the desired verifying key.
|
|
279
|
+
* @param {FunctionKeyPair} keys The proving and verifying keys.
|
|
280
|
+
*
|
|
281
|
+
* @example
|
|
282
|
+
* const keys = await generateKeys();
|
|
283
|
+
* await setKeys(
|
|
284
|
+
* { locator: 'transfer_private.prover' },
|
|
285
|
+
* { locator: 'transfer_private.verifier' },
|
|
286
|
+
* keys
|
|
287
|
+
* );
|
|
288
|
+
*/
|
|
289
|
+
async setKeys(proverLocator, verifierLocator, keys) {
|
|
290
|
+
this.validateLocator(proverLocator.locator);
|
|
291
|
+
this.validateLocator(verifierLocator.locator);
|
|
292
|
+
// Convert the WASM keys to raw bytes.
|
|
293
|
+
const [provingKey, verifyingKey] = keys;
|
|
294
|
+
const [provingKeyBytes, verifyingKeyBytes] = [
|
|
295
|
+
provingKey.toBytes(),
|
|
296
|
+
verifyingKey.toBytes(),
|
|
297
|
+
];
|
|
298
|
+
// Compute the fingerprints for the proving and verifying keys, verify against expected fingerprints if provided.
|
|
299
|
+
const [proverFingerPrint, verifierFingerPrint] = await Promise.all([
|
|
300
|
+
this.keyVerifier.computeKeyMetadata({
|
|
301
|
+
keyBytes: provingKeyBytes,
|
|
302
|
+
locator: proverLocator.locator,
|
|
303
|
+
fingerprint: proverLocator.fingerprint,
|
|
304
|
+
}),
|
|
305
|
+
this.keyVerifier.computeKeyMetadata({
|
|
306
|
+
keyBytes: verifyingKeyBytes,
|
|
307
|
+
locator: verifierLocator.locator,
|
|
308
|
+
fingerprint: verifierLocator.fingerprint,
|
|
309
|
+
}),
|
|
310
|
+
]);
|
|
311
|
+
// Write the proving and verifying key bytes and their metadata to storage (under this.directory).
|
|
312
|
+
await this.writeFileAtomic(path.join(this.directory, proverLocator.locator), provingKeyBytes);
|
|
313
|
+
await this.writeFileAtomic(path.join(this.directory, verifierLocator.locator), verifyingKeyBytes);
|
|
314
|
+
await this.writeKeyMetadata(proverLocator.locator, proverFingerPrint);
|
|
315
|
+
await this.writeKeyMetadata(verifierLocator.locator, verifierFingerPrint);
|
|
106
316
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
317
|
+
/**
|
|
318
|
+
* Store a raw proving or verifying key in storage along with its fingerprint metadata for future verification.
|
|
319
|
+
*
|
|
320
|
+
* @param {Uint8Array} keyBytes The raw proving and verifying key bytes.
|
|
321
|
+
* @param {KeyLocator} locator The unique locator for the desired key pair.
|
|
322
|
+
* @returns {Promise<void>}
|
|
323
|
+
* @throws {Error} If computing key metadata or writing to storage fails
|
|
324
|
+
*
|
|
325
|
+
* @example
|
|
326
|
+
* const keys = await generateKeys();
|
|
327
|
+
* await setKeyBytes(keys.provingKey.toBytes(), { locator: 'transfer_private.prover' });
|
|
328
|
+
*/
|
|
329
|
+
async setKeyBytes(keyBytes, locator) {
|
|
330
|
+
this.validateLocator(locator.locator);
|
|
331
|
+
// Compute the key metadata including fingerprint
|
|
332
|
+
const computedMetadata = await this.keyVerifier.computeKeyMetadata({
|
|
333
|
+
keyBytes: keyBytes,
|
|
334
|
+
locator: locator.locator,
|
|
335
|
+
fingerprint: locator.fingerprint,
|
|
336
|
+
});
|
|
337
|
+
// Write the key bytes and metadata atomically (key file under this.directory).
|
|
338
|
+
await this.writeFileAtomic(path.join(this.directory, locator.locator), keyBytes);
|
|
339
|
+
await this.writeKeyMetadata(locator.locator, computedMetadata);
|
|
111
340
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
341
|
+
/**
|
|
342
|
+
* Returns stored metadata for a key, if any.
|
|
343
|
+
*
|
|
344
|
+
* @param {string} locator The unique locator for the key.
|
|
345
|
+
* @returns {Promise<KeyFingerprint | null>} The stored fingerprint metadata for that locator, or null if none exists.
|
|
346
|
+
*
|
|
347
|
+
* @example
|
|
348
|
+
* const metadata = await getKeyMetadata('transfer_private.prover.421e5a5');
|
|
349
|
+
* if (metadata) {
|
|
350
|
+
* // Use the stored metadata.
|
|
351
|
+
* }
|
|
352
|
+
*/
|
|
353
|
+
async getKeyMetadata(locator) {
|
|
354
|
+
this.validateLocator(locator);
|
|
355
|
+
return this.readKeyMetadata(locator);
|
|
116
356
|
}
|
|
357
|
+
/**
|
|
358
|
+
* Checks if a key exists at the specified locator path.
|
|
359
|
+
*
|
|
360
|
+
* @param {string} locator - Unique identifier for the key location.
|
|
361
|
+
* @returns {Promise<boolean>} True if key exists at location, false otherwise.
|
|
362
|
+
*
|
|
363
|
+
* @example
|
|
364
|
+
* const exists = await has('transfer_private.prover.421e5a5');
|
|
365
|
+
* if (exists) {
|
|
366
|
+
* // Key exists at location.
|
|
367
|
+
* } else {
|
|
368
|
+
* // Key does not exist at location.
|
|
369
|
+
* }
|
|
370
|
+
*/
|
|
117
371
|
async has(locator) {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
.
|
|
122
|
-
const verifierExists = await fs
|
|
123
|
-
.access(this.verifierPath(locator))
|
|
372
|
+
this.validateLocator(locator);
|
|
373
|
+
const keyPath = path.join(this.directory, locator);
|
|
374
|
+
return await fs
|
|
375
|
+
.access(keyPath)
|
|
124
376
|
.then(() => true)
|
|
125
377
|
.catch(() => false);
|
|
126
|
-
return proverExists && verifierExists;
|
|
127
378
|
}
|
|
379
|
+
/**
|
|
380
|
+
* Deletes a key and its associated metadata from storage. Silently ignores errors if files don't exist.
|
|
381
|
+
*
|
|
382
|
+
* @param {string} locator - Unique identifier for the key to delete.
|
|
383
|
+
* @returns {Promise<void>}
|
|
384
|
+
*
|
|
385
|
+
* @example
|
|
386
|
+
* await delete('transfer_private.prover.421e5a5');
|
|
387
|
+
*/
|
|
128
388
|
async delete(locator) {
|
|
129
|
-
|
|
130
|
-
const
|
|
389
|
+
this.validateLocator(locator);
|
|
390
|
+
const p = path.join(this.directory, locator);
|
|
391
|
+
const m = this.metadataPath(locator);
|
|
131
392
|
await fs.unlink(p).catch(() => { });
|
|
132
|
-
await fs.unlink(
|
|
393
|
+
await fs.unlink(m).catch(() => { });
|
|
133
394
|
}
|
|
395
|
+
/**
|
|
396
|
+
* Clears the key storage directory by recursively removing all files and subdirectories under it, then removes the keystore directory itself.
|
|
397
|
+
*
|
|
398
|
+
* @returns {Promise<void>}
|
|
399
|
+
* @throws {Error} If directory listing fails for reasons other than non-existence.
|
|
400
|
+
*
|
|
401
|
+
* @example
|
|
402
|
+
* await clear(); // Removes all files under the keystore directory.
|
|
403
|
+
*/
|
|
134
404
|
async clear() {
|
|
135
|
-
await this.
|
|
405
|
+
await this.clearDirectory(this.directory);
|
|
136
406
|
}
|
|
137
407
|
}
|
|
138
408
|
|
|
139
|
-
export { LocalFileKeyStore };
|
|
409
|
+
export { InvalidLocatorError, LocalFileKeyStore, MemKeyVerifier };
|
|
140
410
|
//# sourceMappingURL=node.js.map
|
package/dist/testnet/node.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node.js","sources":["../../src/keys/keystore/file.ts"],"sourcesContent":["import * as fs from \"node:fs/promises\";\nimport * as path from \"path\";\n\nimport { CachedKeyPair, FunctionKeyPair } from \"../../models/keyPair.js\";\nimport { KeyStore } from \"./keystore.js\";\nimport { ProvingKey, VerifyingKey } from \"../../wasm.js\";\n\nexport class LocalFileKeyStore implements KeyStore {\n\n private directory: string;\n\n constructor(directory?: string) {\n this.directory = directory ?? path.join(process.cwd(), \"keystore\");\n\n // Ensure directory exists\n fs.mkdir(this.directory, { recursive: true }).catch((err) => {\n console.error(\"Failed to create keystore directory:\", err);\n });\n }\n\n private proverPath(locator: string): string {\n return path.join(this.directory, `${locator}.prover`);\n }\n\n private verifierPath(locator: string): string {\n return path.join(this.directory, `${locator}.verifier`);\n }\n\n private async readFileOptional(filepath: string): Promise<Uint8Array | null> {\n try {\n const data = await fs.readFile(filepath);\n return new Uint8Array(data);\n } catch (err: any) {\n if (err.code === \"ENOENT\") return null;\n throw err;\n }\n }\n\n private async writeFileAtomic(filepath: string, data: Uint8Array): Promise<void> {\n // Ensure parent directories for nested locators exist\n await fs.mkdir(path.dirname(filepath), { recursive: true });\n await fs.writeFile(filepath, data);\n }\n\n private async clearRecursive(dir: string): Promise<void> {\n let entries: string[];\n try {\n entries = await fs.readdir(dir);\n } catch (err: any) {\n if (err.code === \"ENOENT\") {\n return;\n }\n throw err;\n }\n\n await Promise.all(entries.map(async (name) => {\n const full = path.join(dir, name);\n let isDirectory = false;\n try {\n const stat = await fs.stat(full);\n isDirectory = stat.isDirectory();\n } catch {\n return;\n }\n\n if (isDirectory) {\n await this.clearRecursive(full);\n } else if (name.endsWith(\".prover\") || name.endsWith(\".verifier\")) {\n await fs.unlink(full).catch(() => {});\n }\n }));\n }\n\n // -------------------------------------------------------\n // KEYSTORE INTERFACE\n // -------------------------------------------------------\n\n async getKeys(locator: string): Promise<FunctionKeyPair | null> {\n const prover = await this.getProvingKey(locator);\n const verifier = await this.getVerifyingKey(locator);\n if (!prover || !verifier) return null;\n return [prover, verifier];\n }\n\n async getKeyBytes(locator: string): Promise<CachedKeyPair | null> {\n const prover = await this.getProvingKeyBytes(locator);\n const verifier = await this.getVerifyingKeyBytes(locator);\n if (!prover || !verifier) return null;\n return [prover, verifier];\n }\n\n async getProvingKey(locator: string): Promise<ProvingKey | null> {\n const bytes = await this.getProvingKeyBytes(locator);\n return bytes ? ProvingKey.fromBytes(bytes) : null;\n }\n\n async getProvingKeyBytes(locator: string): Promise<Uint8Array | null> {\n return this.readFileOptional(this.proverPath(locator));\n }\n\n async getVerifyingKey(locator: string): Promise<VerifyingKey | null> {\n const bytes = await this.getVerifyingKeyBytes(locator);\n return bytes ? VerifyingKey.fromBytes(bytes) : null;\n }\n\n async getVerifyingKeyBytes(locator: string): Promise<Uint8Array | null> {\n return this.readFileOptional(this.verifierPath(locator));\n }\n\n async setKeys(locator: string, keys: FunctionKeyPair): Promise<void> {\n const [p, v] = keys;\n await this.writeFileAtomic(this.proverPath(locator), p.toBytes());\n await this.writeFileAtomic(this.verifierPath(locator), v.toBytes());\n }\n\n async setKeyBytes(locator: string, keys: CachedKeyPair): Promise<void> {\n const [proverBytes, verifierBytes] = keys;\n await this.writeFileAtomic(this.proverPath(locator), proverBytes);\n await this.writeFileAtomic(this.verifierPath(locator), verifierBytes);\n }\n\n async has(locator: string): Promise<boolean> {\n const proverExists = await fs\n .access(this.proverPath(locator))\n .then(() => true)\n .catch(() => false);\n\n const verifierExists = await fs\n .access(this.verifierPath(locator))\n .then(() => true)\n .catch(() => false);\n\n return proverExists && verifierExists;\n }\n\n async delete(locator: string): Promise<void> {\n const p = this.proverPath(locator);\n const v = this.verifierPath(locator);\n\n await fs.unlink(p).catch(() => {});\n await fs.unlink(v).catch(() => {});\n }\n\n async clear(): Promise<void> {\n await this.clearRecursive(this.directory);\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"node.js","sources":["../../src/keys/keystore/file.ts"],"sourcesContent":["import * as fs from \"node:fs/promises\";\nimport * as fsSync from \"node:fs\";\nimport * as path from \"path\";\n\nimport { FunctionKeyPair } from \"../../models/keyPair.js\";\nimport { KeyFingerprint } from \"../verifier/interface.js\";\nimport { InvalidLocatorError } from \"./error.js\";\nimport { KeyLocator, KeyStore } from \"./interface.js\";\nimport { MemKeyVerifier } from \"../verifier/memory.js\";\nimport { ProvingKey, VerifyingKey } from \"../../wasm.js\";\n\nexport class LocalFileKeyStore implements KeyStore {\n private directory: string;\n private readonly keyVerifier = new MemKeyVerifier();\n\n /**\n * Creates a new directory at the given path or CURRENTDIR/.aleo if none is provided to store keys.\n * If a custom directory is passed and its last path segment is not \".aleo\", \".aleo\" is appended\n * so keys are stored under that subdirectory (e.g. /home/project → /home/project/.aleo).\n *\n * @param {string} [directory] - Optional custom directory path for key storage. Defaults to \".aleo\" in current working directory.\n * @throws {Error} If directory creation fails.\n */\n constructor(directory?: string) {\n this.directory = directory ?? path.join(process.cwd(), \".aleo\");\n if (directory !== undefined && path.basename(this.directory) !== \".aleo\") {\n this.directory = path.join(this.directory, \".aleo\");\n }\n fsSync.mkdirSync(this.directory, { recursive: true });\n }\n\n /**\n * Validates that a locator is a safe filesystem identifier.\n *\n * @private\n * @param {string} locator - Unique identifier used to derive a metadata file path.\n * @throws {InvalidLocatorError} If the locator could cause path traversal.\n */\n private validateLocator(locator: string): void {\n // Reject empty and reserved names that could resolve to the directory or parent\n if (locator === \"\" || locator === \".\" || locator === \"..\") {\n throw new InvalidLocatorError(\n `Invalid locator: reserved or empty name \"${locator}\"`,\n locator,\n \"reserved_name\"\n );\n }\n\n // Explicitly block traversal attempts\n if (locator.includes(\"..\")) {\n throw new InvalidLocatorError(\n \"Invalid locator: path traversal detected\",\n locator,\n \"path_traversal\"\n );\n }\n\n // Block path separators and null byte\n if (locator.includes(\"/\") || locator.includes(\"\\\\\") || locator.includes(\"\\0\")) {\n throw new InvalidLocatorError(\n \"Invalid locator: path separator or null byte not allowed\",\n locator,\n \"path_separator\"\n );\n }\n }\n\n /**\n * Generates the path for a key metadata file based on the locator.\n *\n * @private\n * @param {string} locator - Unique identifier for the key.\n * @returns {string} Full filesystem path to the metadata file.\n */\n private metadataPath(locator: string): string {\n return path.join(this.directory, `${locator}.metadata`);\n }\n\n /**\n * Reads and parses the key fingerprint metadata from storage.\n *\n * @private\n * @param {string} locator - Unique identifier for the key.\n * @returns {Promise<KeyFingerprint | null>} The key fingerprint if found, null if file doesn't exist.\n * @throws {Error} If file read fails for any reason other than not found.\n */\n private async readKeyMetadata(\n locator: string,\n ): Promise<KeyFingerprint | null> {\n try {\n const data = await fs.readFile(this.metadataPath(locator), \"utf-8\");\n return JSON.parse(data) as KeyFingerprint;\n } catch (err: unknown) {\n if (\n err &&\n typeof err === \"object\" &&\n \"code\" in err &&\n err.code === \"ENOENT\"\n )\n return null;\n throw err;\n }\n }\n\n /**\n * Writes key fingerprint metadata to storage.\n *\n * @private\n * @param {string} locator - Unique identifier for the key.\n * @param {KeyFingerprint} metadata - Key fingerprint metadata to store.\n * @returns {Promise<void>}\n * @throws {Error} If directory creation or file write fails.\n */\n private async writeKeyMetadata(\n locator: string,\n metadata: KeyFingerprint,\n ): Promise<void> {\n await fs.mkdir(path.dirname(this.metadataPath(locator)), {\n recursive: true,\n });\n await fs.writeFile(\n this.metadataPath(locator),\n JSON.stringify(metadata, null, 0),\n \"utf-8\",\n );\n }\n\n private async readFileOptional(\n filepath: string,\n ): Promise<Uint8Array | null> {\n try {\n const data = await fs.readFile(filepath);\n return new Uint8Array(data);\n } catch (err: any) {\n if (err.code === \"ENOENT\") return null;\n throw err;\n }\n }\n \n /**\n * Atomically writes data to a file, ensuring the parent directories exist.\n *\n * @private\n * @param {string} filepath - Full path to the file to write\n * @param {Uint8Array} data - Binary data to write to the file\n * @returns {Promise<void>} Resolves when write is complete\n * @throws {Error} If directory creation or file write fails\n */\n private async writeFileAtomic(\n filepath: string,\n data: Uint8Array,\n ): Promise<void> {\n const dir = path.dirname(filepath);\n await fs.mkdir(dir, { recursive: true });\n const tempPath = path.join(\n dir,\n `.${path.basename(filepath)}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`\n );\n await fs.writeFile(tempPath, data);\n try {\n await fs.rename(tempPath, filepath);\n } catch (err: unknown) {\n const code = err && typeof err === \"object\" && \"code\" in err ? (err as NodeJS.ErrnoException).code : undefined;\n // Windows often throws EEXIST when target exists; EPERM/EACCES happen with locks/AV.\n if (code === \"EEXIST\" || code === \"EPERM\" || code === \"EACCES\") {\n await fs.unlink(filepath).catch(() => {});\n try {\n await fs.rename(tempPath, filepath);\n } catch (err2) {\n await fs.unlink(tempPath).catch(() => {});\n throw err2;\n }\n } else {\n await fs.unlink(tempPath).catch(() => {});\n throw err;\n }\n }\n }\n\n /**\n * Recursively removes all files and subdirectories under the given directory, then removes the directory itself.\n * Uses fs.rm with recursive: true and force: true so that symbolic links are removed without following them,\n * avoiding deletion of content outside the keystore.\n *\n * @private\n * @param {string} dir - Directory path to clear\n * @returns {Promise<void>} Resolves when clearing is complete\n * @throws {Error} If directory removal fails for reasons other than non-existence\n */\n private async clearDirectory(dir: string): Promise<void> {\n try {\n await fs.rm(dir, { recursive: true, force: true });\n } catch (err: unknown) {\n const code = err && typeof err === \"object\" && \"code\" in err ? (err as NodeJS.ErrnoException).code : undefined;\n if (code === \"ENOENT\") {\n return;\n }\n throw err;\n }\n }\n\n // -------------------------------------------------------\n // KEYSTORE INTERFACE\n // -------------------------------------------------------\n\n /**\n * Retrieves the key bytes from storage and optionally verifies them against a fingerprint.\n *\n * @param {KeyLocator} locator - Object containing a locator string for the key + optional fingerprint for verification.\n * @returns {Promise<Uint8Array | null>} The key bytes if found and verified (if fingerprint provided), null if not found.\n * @throws {KeyVerificationError} If fingerprint verification fails.\n * @example\n * const keyBytes = await getKeyBytes({\n * locator: 'transfer_private.prover.421e5a5',\n * fingerprint: { checksum: '421e5a52f01a1eeb068bbf56d15e19477ff7290e4b988d1013e15563f2b77801', size: 116746954 }\n * });\n * if (keyBytes) {\n * // Use the verified key bytes\n * }\n */\n async getKeyBytes(locator: KeyLocator): Promise<Uint8Array | null> {\n this.validateLocator(locator.locator);\n // Attempt to read key bytes from storage (under this.directory).\n const keyBytes = await this.readFileOptional(path.join(this.directory, locator.locator));\n\n // If no key bytes were found, return null.\n if (!keyBytes) return null;\n\n // Use caller-provided fingerprint or metadata stored on disk for verification.\n const fingerprint =\n locator.fingerprint ?? (await this.getKeyMetadata(locator.locator));\n if (fingerprint) {\n await this.keyVerifier.verifyKeyBytes({\n keyBytes,\n locator: locator.locator,\n fingerprint,\n });\n }\n\n // Return the verified key bytes.\n return keyBytes;\n }\n\n /**\n * Retrieves and verifies a proving key from storage.\n *\n * @param {KeyLocator} locator - Object containing the proving key location and optional fingerprint.\n * @returns {Promise<ProvingKey | null>} The proving key if found and verified, null if not found.\n * @throws {KeyVerificationError} If fingerprint verification fails.\n * @throws {Error} If key bytes cannot be parsed into a valid ProvingKey.\n *\n * @example\n * try {\n * const key = await getProvingKey({\n * locator: 'transfer_private.prover.421e5a5'\n * });\n * if (key) {\n * // Use the verified proving key\n * }\n * } catch (err) {\n * if (err instanceof KeyVerificationError) {\n * // Handle verification failure.\n * } else {\n * // Handle key parsing error.\n * }\n * }\n */\n async getProvingKey(locator: KeyLocator): Promise<ProvingKey | null> {\n // Get the key bytes from storage.\n const proverBytes = await this.getKeyBytes(locator);\n if (!proverBytes) return null;\n\n // Attempt to parse the key bytes as a WASM ProvingKey (throws if invalid).\n return ProvingKey.fromBytes(proverBytes);\n }\n\n /**\n * Retrieves and verifies a verifying key from storage.\n *\n * @param {KeyLocator} locator - Object containing the verifying key location and optional fingerprint.\n * @returns {Promise<VerifyingKey | null>} The verifying key if found and verified, null if not found.\n * @throws {KeyVerificationError} If fingerprint verification fails.\n * @throws {Error} If key bytes cannot be parsed into a valid VerifyingKey.\n *\n * @example\n * try {\n * const key = await getVerifyingKey({\n * locator: 'transfer_private.verifier.4ac2f71'\n * });\n * if (key) {\n * // Use the verified verifying key\n * }\n * } catch (err) {\n * if (err instanceof KeyVerificationError) {\n * // Handle verification failure.\n * } else {\n * // Handle key parsing error.\n * }\n * }\n */\n async getVerifyingKey(locator: KeyLocator): Promise<VerifyingKey | null> {\n // Get the key bytes from storage.\n const verifierBytes = await this.getKeyBytes(locator);\n if (!verifierBytes) return null;\n\n // Attempt to parse the key bytes as a WASM VerifyingKey (throws if invalid).\n return VerifyingKey.fromBytes(verifierBytes);\n }\n\n /**\n * Stores proving and verifying keys in key storage.\n *\n * @param {KeyLocator} proverLocator The unique locator for the desired proving key.\n * @param {KeyLocator} verifierLocator The unique locator for the desired verifying key.\n * @param {FunctionKeyPair} keys The proving and verifying keys.\n *\n * @example\n * const keys = await generateKeys();\n * await setKeys(\n * { locator: 'transfer_private.prover' },\n * { locator: 'transfer_private.verifier' },\n * keys\n * );\n */\n async setKeys(\n proverLocator: KeyLocator,\n verifierLocator: KeyLocator,\n keys: FunctionKeyPair,\n ): Promise<void> {\n this.validateLocator(proverLocator.locator);\n this.validateLocator(verifierLocator.locator);\n // Convert the WASM keys to raw bytes.\n const [provingKey, verifyingKey] = keys;\n const [provingKeyBytes, verifyingKeyBytes] = [\n provingKey.toBytes(),\n verifyingKey.toBytes(),\n ];\n\n // Compute the fingerprints for the proving and verifying keys, verify against expected fingerprints if provided.\n const [proverFingerPrint, verifierFingerPrint] = await Promise.all([\n this.keyVerifier.computeKeyMetadata({\n keyBytes: provingKeyBytes,\n locator: proverLocator.locator,\n fingerprint: proverLocator.fingerprint,\n }),\n this.keyVerifier.computeKeyMetadata({\n keyBytes: verifyingKeyBytes,\n locator: verifierLocator.locator,\n fingerprint: verifierLocator.fingerprint,\n }),\n ]);\n\n // Write the proving and verifying key bytes and their metadata to storage (under this.directory).\n await this.writeFileAtomic(path.join(this.directory, proverLocator.locator), provingKeyBytes);\n await this.writeFileAtomic(path.join(this.directory, verifierLocator.locator), verifyingKeyBytes);\n await this.writeKeyMetadata(proverLocator.locator, proverFingerPrint);\n await this.writeKeyMetadata(\n verifierLocator.locator,\n verifierFingerPrint,\n );\n }\n\n /**\n * Store a raw proving or verifying key in storage along with its fingerprint metadata for future verification.\n *\n * @param {Uint8Array} keyBytes The raw proving and verifying key bytes.\n * @param {KeyLocator} locator The unique locator for the desired key pair.\n * @returns {Promise<void>}\n * @throws {Error} If computing key metadata or writing to storage fails\n *\n * @example\n * const keys = await generateKeys();\n * await setKeyBytes(keys.provingKey.toBytes(), { locator: 'transfer_private.prover' });\n */\n async setKeyBytes(keyBytes: Uint8Array, locator: KeyLocator): Promise<void> {\n this.validateLocator(locator.locator);\n // Compute the key metadata including fingerprint\n const computedMetadata = await this.keyVerifier.computeKeyMetadata({\n keyBytes: keyBytes,\n locator: locator.locator,\n fingerprint: locator.fingerprint,\n });\n\n // Write the key bytes and metadata atomically (key file under this.directory).\n await this.writeFileAtomic(path.join(this.directory, locator.locator), keyBytes);\n await this.writeKeyMetadata(locator.locator, computedMetadata);\n }\n\n /**\n * Returns stored metadata for a key, if any.\n *\n * @param {string} locator The unique locator for the key.\n * @returns {Promise<KeyFingerprint | null>} The stored fingerprint metadata for that locator, or null if none exists.\n *\n * @example\n * const metadata = await getKeyMetadata('transfer_private.prover.421e5a5');\n * if (metadata) {\n * // Use the stored metadata.\n * }\n */\n async getKeyMetadata(locator: string): Promise<KeyFingerprint | null> {\n this.validateLocator(locator);\n return this.readKeyMetadata(locator);\n }\n\n /**\n * Checks if a key exists at the specified locator path.\n *\n * @param {string} locator - Unique identifier for the key location.\n * @returns {Promise<boolean>} True if key exists at location, false otherwise.\n *\n * @example\n * const exists = await has('transfer_private.prover.421e5a5');\n * if (exists) {\n * // Key exists at location.\n * } else {\n * // Key does not exist at location.\n * }\n */\n async has(locator: string): Promise<boolean> {\n this.validateLocator(locator);\n const keyPath = path.join(this.directory, locator);\n return await fs\n .access(keyPath)\n .then(() => true)\n .catch(() => false);\n }\n\n /**\n * Deletes a key and its associated metadata from storage. Silently ignores errors if files don't exist.\n *\n * @param {string} locator - Unique identifier for the key to delete.\n * @returns {Promise<void>}\n *\n * @example\n * await delete('transfer_private.prover.421e5a5');\n */\n async delete(locator: string): Promise<void> {\n this.validateLocator(locator);\n const p = path.join(this.directory, locator);\n const m = this.metadataPath(locator);\n\n await fs.unlink(p).catch(() => {});\n await fs.unlink(m).catch(() => {});\n }\n\n /**\n * Clears the key storage directory by recursively removing all files and subdirectories under it, then removes the keystore directory itself.\n *\n * @returns {Promise<void>}\n * @throws {Error} If directory listing fails for reasons other than non-existence.\n *\n * @example\n * await clear(); // Removes all files under the keystore directory.\n */\n async clear(): Promise<void> {\n await this.clearDirectory(this.directory);\n }\n}"],"names":["fsSync"],"mappings":";;;;;;;;;;;;;;;;;MAWa,iBAAiB,CAAA;AAClB,IAAA,SAAS;AACA,IAAA,WAAW,GAAG,IAAI,cAAc,EAAE;AAEnD;;;;;;;AAOG;AACH,IAAA,WAAA,CAAY,SAAkB,EAAA;AAC1B,QAAA,IAAI,CAAC,SAAS,GAAG,SAAS,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC;AAC/D,QAAA,IAAI,SAAS,KAAK,SAAS,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,OAAO,EAAE;AACtE,YAAA,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC;QACvD;AACA,QAAAA,GAAM,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;IACzD;AAEA;;;;;;AAMG;AACK,IAAA,eAAe,CAAC,OAAe,EAAA;;AAEnC,QAAA,IAAI,OAAO,KAAK,EAAE,IAAI,OAAO,KAAK,GAAG,IAAI,OAAO,KAAK,IAAI,EAAE;YACvD,MAAM,IAAI,mBAAmB,CACzB,CAAA,yCAAA,EAA4C,OAAO,CAAA,CAAA,CAAG,EACtD,OAAO,EACP,eAAe,CAClB;QACL;;AAGA,QAAA,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;YACxB,MAAM,IAAI,mBAAmB,CACzB,0CAA0C,EAC1C,OAAO,EACP,gBAAgB,CACnB;QACL;;QAGA,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;YAC3E,MAAM,IAAI,mBAAmB,CACzB,0DAA0D,EAC1D,OAAO,EACP,gBAAgB,CACnB;QACL;IACJ;AAEA;;;;;;AAMG;AACK,IAAA,YAAY,CAAC,OAAe,EAAA;AAChC,QAAA,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAA,EAAG,OAAO,CAAA,SAAA,CAAW,CAAC;IAC3D;AAEA;;;;;;;AAOG;IACK,MAAM,eAAe,CACzB,OAAe,EAAA;AAEf,QAAA,IAAI;AACA,YAAA,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;AACnE,YAAA,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAmB;QAC7C;QAAE,OAAO,GAAY,EAAE;AACnB,YAAA,IACI,GAAG;gBACH,OAAO,GAAG,KAAK,QAAQ;AACvB,gBAAA,MAAM,IAAI,GAAG;gBACb,GAAG,CAAC,IAAI,KAAK,QAAQ;AAErB,gBAAA,OAAO,IAAI;AACf,YAAA,MAAM,GAAG;QACb;IACJ;AAEA;;;;;;;;AAQG;AACK,IAAA,MAAM,gBAAgB,CAC1B,OAAe,EACf,QAAwB,EAAA;AAExB,QAAA,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,EAAE;AACrD,YAAA,SAAS,EAAE,IAAI;AAClB,SAAA,CAAC;QACF,MAAM,EAAE,CAAC,SAAS,CACd,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,EAC1B,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,EACjC,OAAO,CACV;IACL;IAEQ,MAAM,gBAAgB,CAC1B,QAAgB,EAAA;AAEhB,QAAA,IAAI;YACA,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC;AACxC,YAAA,OAAO,IAAI,UAAU,CAAC,IAAI,CAAC;QAC/B;QAAE,OAAO,GAAQ,EAAE;AACf,YAAA,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ;AAAE,gBAAA,OAAO,IAAI;AACtC,YAAA,MAAM,GAAG;QACb;IACJ;AAEA;;;;;;;;AAQG;AACK,IAAA,MAAM,eAAe,CACzB,QAAgB,EAChB,IAAgB,EAAA;QAEhB,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;AAClC,QAAA,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;AACxC,QAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CACtB,GAAG,EACH,CAAA,CAAA,EAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA,CAAA,EAAI,OAAO,CAAC,GAAG,CAAA,CAAA,EAAI,IAAI,CAAC,GAAG,EAAE,CAAA,CAAA,EAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA,IAAA,CAAM,CACxG;QACD,MAAM,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC;AAClC,QAAA,IAAI;YACA,MAAM,EAAE,CAAC,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC;QACvC;QAAE,OAAO,GAAY,EAAE;YACnB,MAAM,IAAI,GAAG,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,MAAM,IAAI,GAAG,GAAI,GAA6B,CAAC,IAAI,GAAG,SAAS;;AAE9G,YAAA,IAAI,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,QAAQ,EAAE;AAC5D,gBAAA,MAAM,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,MAAK,EAAE,CAAC,CAAC;AACzC,gBAAA,IAAI;oBACA,MAAM,EAAE,CAAC,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC;gBACvC;gBAAE,OAAO,IAAI,EAAE;AACX,oBAAA,MAAM,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,MAAK,EAAE,CAAC,CAAC;AACzC,oBAAA,MAAM,IAAI;gBACd;YACJ;iBAAO;AACH,gBAAA,MAAM,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,MAAK,EAAE,CAAC,CAAC;AACzC,gBAAA,MAAM,GAAG;YACb;QACJ;IACJ;AAEA;;;;;;;;;AASG;IACK,MAAM,cAAc,CAAC,GAAW,EAAA;AACpC,QAAA,IAAI;AACA,YAAA,MAAM,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QACtD;QAAE,OAAO,GAAY,EAAE;YACnB,MAAM,IAAI,GAAG,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,MAAM,IAAI,GAAG,GAAI,GAA6B,CAAC,IAAI,GAAG,SAAS;AAC9G,YAAA,IAAI,IAAI,KAAK,QAAQ,EAAE;gBACnB;YACJ;AACA,YAAA,MAAM,GAAG;QACb;IACJ;;;;AAMA;;;;;;;;;;;;;;AAcG;IACH,MAAM,WAAW,CAAC,OAAmB,EAAA;AACjC,QAAA,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,OAAO,CAAC;;QAErC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;;AAGxF,QAAA,IAAI,CAAC,QAAQ;AAAE,YAAA,OAAO,IAAI;;AAG1B,QAAA,MAAM,WAAW,GACb,OAAO,CAAC,WAAW,KAAK,MAAM,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACvE,IAAI,WAAW,EAAE;AACb,YAAA,MAAM,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC;gBAClC,QAAQ;gBACR,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,WAAW;AACd,aAAA,CAAC;QACN;;AAGA,QAAA,OAAO,QAAQ;IACnB;AAEA;;;;;;;;;;;;;;;;;;;;;;;AAuBG;IACH,MAAM,aAAa,CAAC,OAAmB,EAAA;;QAEnC,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC;AACnD,QAAA,IAAI,CAAC,WAAW;AAAE,YAAA,OAAO,IAAI;;AAG7B,QAAA,OAAO,UAAU,CAAC,SAAS,CAAC,WAAW,CAAC;IAC5C;AAEA;;;;;;;;;;;;;;;;;;;;;;;AAuBG;IACH,MAAM,eAAe,CAAC,OAAmB,EAAA;;QAErC,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC;AACrD,QAAA,IAAI,CAAC,aAAa;AAAE,YAAA,OAAO,IAAI;;AAG/B,QAAA,OAAO,YAAY,CAAC,SAAS,CAAC,aAAa,CAAC;IAChD;AAEA;;;;;;;;;;;;;;AAcG;AACH,IAAA,MAAM,OAAO,CACT,aAAyB,EACzB,eAA2B,EAC3B,IAAqB,EAAA;AAErB,QAAA,IAAI,CAAC,eAAe,CAAC,aAAa,CAAC,OAAO,CAAC;AAC3C,QAAA,IAAI,CAAC,eAAe,CAAC,eAAe,CAAC,OAAO,CAAC;;AAE7C,QAAA,MAAM,CAAC,UAAU,EAAE,YAAY,CAAC,GAAG,IAAI;AACvC,QAAA,MAAM,CAAC,eAAe,EAAE,iBAAiB,CAAC,GAAG;YACzC,UAAU,CAAC,OAAO,EAAE;YACpB,YAAY,CAAC,OAAO,EAAE;SACzB;;QAGD,MAAM,CAAC,iBAAiB,EAAE,mBAAmB,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;AAC/D,YAAA,IAAI,CAAC,WAAW,CAAC,kBAAkB,CAAC;AAChC,gBAAA,QAAQ,EAAE,eAAe;gBACzB,OAAO,EAAE,aAAa,CAAC,OAAO;gBAC9B,WAAW,EAAE,aAAa,CAAC,WAAW;aACzC,CAAC;AACF,YAAA,IAAI,CAAC,WAAW,CAAC,kBAAkB,CAAC;AAChC,gBAAA,QAAQ,EAAE,iBAAiB;gBAC3B,OAAO,EAAE,eAAe,CAAC,OAAO;gBAChC,WAAW,EAAE,eAAe,CAAC,WAAW;aAC3C,CAAC;AACL,SAAA,CAAC;;AAGF,QAAA,MAAM,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,OAAO,CAAC,EAAE,eAAe,CAAC;AAC7F,QAAA,MAAM,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,eAAe,CAAC,OAAO,CAAC,EAAE,iBAAiB,CAAC;QACjG,MAAM,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,OAAO,EAAE,iBAAiB,CAAC;QACrE,MAAM,IAAI,CAAC,gBAAgB,CACvB,eAAe,CAAC,OAAO,EACvB,mBAAmB,CACtB;IACL;AAEA;;;;;;;;;;;AAWG;AACH,IAAA,MAAM,WAAW,CAAC,QAAoB,EAAE,OAAmB,EAAA;AACvD,QAAA,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,OAAO,CAAC;;QAErC,MAAM,gBAAgB,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,kBAAkB,CAAC;AAC/D,YAAA,QAAQ,EAAE,QAAQ;YAClB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,WAAW,EAAE,OAAO,CAAC,WAAW;AACnC,SAAA,CAAC;;AAGF,QAAA,MAAM,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC;QAChF,MAAM,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,OAAO,EAAE,gBAAgB,CAAC;IAClE;AAEA;;;;;;;;;;;AAWG;IACH,MAAM,cAAc,CAAC,OAAe,EAAA;AAChC,QAAA,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC;AAC7B,QAAA,OAAO,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC;IACxC;AAEA;;;;;;;;;;;;;AAaG;IACH,MAAM,GAAG,CAAC,OAAe,EAAA;AACrB,QAAA,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC;AAC7B,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC;AAClD,QAAA,OAAO,MAAM;aACR,MAAM,CAAC,OAAO;AACd,aAAA,IAAI,CAAC,MAAM,IAAI;AACf,aAAA,KAAK,CAAC,MAAM,KAAK,CAAC;IAC3B;AAEA;;;;;;;;AAQG;IACH,MAAM,MAAM,CAAC,OAAe,EAAA;AACxB,QAAA,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC;AAC7B,QAAA,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC;QAC5C,MAAM,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC;AAEpC,QAAA,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAK,EAAE,CAAC,CAAC;AAClC,QAAA,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAK,EAAE,CAAC,CAAC;IACtC;AAEA;;;;;;;;AAQG;AACH,IAAA,MAAM,KAAK,GAAA;QACP,MAAM,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC;IAC7C;AACH;;;;"}
|