@provablehq/sdk 0.9.16 → 0.9.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/dist/mainnet/account.d.ts +43 -3
  2. package/dist/mainnet/browser.d.ts +11 -4
  3. package/dist/mainnet/browser.js +460 -109
  4. package/dist/mainnet/browser.js.map +1 -1
  5. package/dist/mainnet/keys/keystore/error.d.ts +23 -0
  6. package/dist/mainnet/keys/keystore/file.d.ts +217 -0
  7. package/dist/mainnet/keys/keystore/interface.d.ts +85 -0
  8. package/dist/mainnet/keys/provider/interface.d.ts +170 -0
  9. package/dist/mainnet/{function-key-provider.d.ts → keys/provider/memory.d.ts} +9 -167
  10. package/dist/mainnet/{offline-key-provider.d.ts → keys/provider/offline.d.ts} +6 -3
  11. package/dist/mainnet/keys/verifier/interface.d.ts +70 -0
  12. package/dist/mainnet/keys/verifier/memory.d.ts +37 -0
  13. package/dist/mainnet/models/keyHolder.d.ts +2 -0
  14. package/dist/mainnet/models/keyPair.d.ts +4 -0
  15. package/dist/mainnet/models/record-scanner/error.d.ts +1 -1
  16. package/dist/mainnet/models/record-scanner/revokeResult.d.ts +17 -0
  17. package/dist/mainnet/node.d.ts +1 -0
  18. package/dist/mainnet/node.js +399 -2
  19. package/dist/mainnet/node.js.map +1 -1
  20. package/dist/mainnet/program-manager.d.ts +4 -3
  21. package/dist/mainnet/record-scanner.d.ts +16 -0
  22. package/dist/mainnet/security.d.ts +24 -0
  23. package/dist/testnet/account.d.ts +43 -3
  24. package/dist/testnet/browser.d.ts +11 -4
  25. package/dist/testnet/browser.js +460 -109
  26. package/dist/testnet/browser.js.map +1 -1
  27. package/dist/testnet/keys/keystore/error.d.ts +23 -0
  28. package/dist/testnet/keys/keystore/file.d.ts +217 -0
  29. package/dist/testnet/keys/keystore/interface.d.ts +85 -0
  30. package/dist/testnet/keys/provider/interface.d.ts +170 -0
  31. package/dist/testnet/{function-key-provider.d.ts → keys/provider/memory.d.ts} +9 -167
  32. package/dist/testnet/{offline-key-provider.d.ts → keys/provider/offline.d.ts} +6 -3
  33. package/dist/testnet/keys/verifier/interface.d.ts +70 -0
  34. package/dist/testnet/keys/verifier/memory.d.ts +37 -0
  35. package/dist/testnet/models/keyHolder.d.ts +2 -0
  36. package/dist/testnet/models/keyPair.d.ts +4 -0
  37. package/dist/testnet/models/record-scanner/error.d.ts +1 -1
  38. package/dist/testnet/models/record-scanner/revokeResult.d.ts +17 -0
  39. package/dist/testnet/node.d.ts +1 -0
  40. package/dist/testnet/node.js +399 -2
  41. package/dist/testnet/node.js.map +1 -1
  42. package/dist/testnet/program-manager.d.ts +4 -3
  43. package/dist/testnet/record-scanner.d.ts +16 -0
  44. package/dist/testnet/security.d.ts +24 -0
  45. package/package.json +3 -3
@@ -1,13 +1,410 @@
1
1
  import './node-polyfill.js';
2
- export { Account, AleoKeyProvider, AleoKeyProviderParams, AleoNetworkClient, BlockHeightSearch, CREDITS_PROGRAM_KEYS, DecryptionNotEnabledError, 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, RecordNotFoundError, RecordScanner, RecordScannerRequestError, SealanceMerkleTree, UUIDError, VALID_TRANSFER_TYPES, ViewKeyNotStoredError, encryptAuthorization, encryptProvingRequest, encryptRegistrationRequest, encryptViewKey, initializeWasm, isProveApiErrorBody, isProvingResponse, logAndThrow } from './browser.js';
2
+ import * as fs from 'node:fs/promises';
3
+ import * as $fs from 'node:fs';
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, zeroizeBytes } from './browser.js';
7
+ import { ProvingKey, VerifyingKey } from '@provablehq/wasm/mainnet.js';
3
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/mainnet.js';
4
9
  import 'core-js/proposals/json-parse-with-source.js';
5
10
  import 'node:crypto';
6
- import 'node:fs';
7
11
  import 'mime/lite';
8
12
  import 'xmlhttprequest-ssl';
9
13
  import 'node:worker_threads';
10
14
  import 'node:os';
11
15
  import 'libsodium-wrappers';
12
16
  import '@scure/base';
17
+
18
+ class LocalFileKeyStore {
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
+ */
29
+ constructor(directory) {
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 });
35
+ }
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
+ }
56
+ }
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");
103
+ }
104
+ async readFileOptional(filepath) {
105
+ try {
106
+ const data = await fs.readFile(filepath);
107
+ return new Uint8Array(data);
108
+ }
109
+ catch (err) {
110
+ if (err.code === "ENOENT")
111
+ return null;
112
+ throw err;
113
+ }
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
+ */
124
+ async writeFileAtomic(filepath, data) {
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
+ }
150
+ }
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) {
162
+ try {
163
+ await fs.rm(dir, { recursive: true, force: true });
164
+ }
165
+ catch (err) {
166
+ const code = err && typeof err === "object" && "code" in err ? err.code : undefined;
167
+ if (code === "ENOENT") {
168
+ return;
169
+ }
170
+ throw err;
171
+ }
172
+ }
173
+ // -------------------------------------------------------
174
+ // KEYSTORE INTERFACE
175
+ // -------------------------------------------------------
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
+ */
191
+ async getKeyBytes(locator) {
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)
197
+ return null;
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;
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
+ */
234
+ async getProvingKey(locator) {
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);
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
+ */
266
+ async getVerifyingKey(locator) {
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);
273
+ }
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);
316
+ }
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);
340
+ }
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);
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
+ */
371
+ async has(locator) {
372
+ this.validateLocator(locator);
373
+ const keyPath = path.join(this.directory, locator);
374
+ return await fs
375
+ .access(keyPath)
376
+ .then(() => true)
377
+ .catch(() => false);
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
+ */
388
+ async delete(locator) {
389
+ this.validateLocator(locator);
390
+ const p = path.join(this.directory, locator);
391
+ const m = this.metadataPath(locator);
392
+ await fs.unlink(p).catch(() => { });
393
+ await fs.unlink(m).catch(() => { });
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
+ */
404
+ async clear() {
405
+ await this.clearDirectory(this.directory);
406
+ }
407
+ }
408
+
409
+ export { InvalidLocatorError, LocalFileKeyStore, MemKeyVerifier };
13
410
  //# sourceMappingURL=node.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"node.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;"}
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":"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"}
@@ -3,7 +3,8 @@ import { AleoNetworkClient, AleoNetworkClientOptions, ProgramImports } from "./n
3
3
  import { ImportedPrograms, ImportedVerifyingKeys } from "./models/imports.js";
4
4
  import { RecordProvider } from "./record-provider.js";
5
5
  import { RecordSearchParams } from "./models/record-provider/recordSearchParams.js";
6
- import { FunctionKeyPair, FunctionKeyProvider, KeySearchParams } from "./function-key-provider.js";
6
+ import { FunctionKeyProvider, KeySearchParams } from "./keys/provider/interface.js";
7
+ import { FunctionKeyPair } from "./models/keyPair.js";
7
8
  import { Authorization, ExecutionResponse, OfflineQuery, RecordPlaintext, PrivateKey, Program, ProvingKey, ProvingRequest, VerifyingKey, Transaction } from "./wasm.js";
8
9
  /**
9
10
  * Represents the options for deploying and upgrading a transaction in the Aleo network.
@@ -1369,7 +1370,7 @@ declare class ProgramManager {
1369
1370
  * import { AleoKeyProvider, getOrInitConsensusVersionTestHeights, ProgramManager, NetworkRecordProvider } from "@provablehq/sdk/mainnet.js";
1370
1371
  *
1371
1372
  * // Initialize the development consensus heights in order to work with devnode.
1372
- * getOrInitConsensusVersionTestHeights("0,1,2,3,4,5,6,7,8,9,10,11");
1373
+ * getOrInitConsensusVersionTestHeights("0,1,2,3,4,5,6,7,8,9,10,11,12");
1373
1374
  *
1374
1375
  * // Create a new NetworkClient and RecordProvider.
1375
1376
  * const recordProvider = new NetworkRecordProvider(account, networkClient);
@@ -1410,7 +1411,7 @@ declare class ProgramManager {
1410
1411
  * import { ProgramManager, NetworkRecordProvider, getOrInitConsensusVersionTestHeights } from "@provablehq/sdk/mainnet.js";
1411
1412
  *
1412
1413
  * // Initialize the development consensus heights in order to work with a local devnode.
1413
- * getOrInitConsensusVersionTestHeights("0,1,2,3,4,5,6,7,8,9,10,11");
1414
+ * getOrInitConsensusVersionTestHeights("0,1,2,3,4,5,6,7,8,9,10,11,12");
1414
1415
  *
1415
1416
  * // Create a new NetworkClient, and RecordProvider
1416
1417
  * const recordProvider = new NetworkRecordProvider(account, networkClient);
@@ -6,6 +6,7 @@ import { RecordProvider } from "./record-provider";
6
6
  import { Field, ViewKey } from "./wasm";
7
7
  import { RecordsFilter } from "./models/record-scanner/recordsFilter";
8
8
  import { RegisterResult } from "./models/record-scanner/registrationResult.js";
9
+ import { RevokeResult } from "./models/record-scanner/revokeResult.js";
9
10
  import { TagsResult } from "./models/record-scanner/tagsResult.js";
10
11
  import { SerialNumbersResult } from "./models/record-scanner/serialNumbersResult.js";
11
12
  import { StatusResult } from "./models/record-scanner/statusResult.js";
@@ -218,6 +219,21 @@ declare class RecordScanner implements RecordProvider {
218
219
  * @returns {Promise<RegisterResult>} `{ ok: true, data }` on success, or `{ ok: false, status, error }` on failure.
219
220
  */
220
221
  registerEncrypted(viewKey: ViewKey, startBlock: number): Promise<RegisterResult>;
222
+ /**
223
+ * Remove all local scanner state associated with the given UUID (stored uuid, viewKeys entry, account if it matches).
224
+ * Called after a successful revoke so the scanner does not retain view keys or account for a revoked registration.
225
+ */
226
+ private clearLocalStateForUuid;
227
+ /**
228
+ * Revoke the account registration with the record scanning service (POST /revoke). On success, also removes
229
+ * all local state for that UUID: the stored UUID (if it matches), the view key for that UUID, and the
230
+ * account (if its view key corresponds to that UUID).
231
+ *
232
+ * @param {string | Field | undefined} uuid The UUID to revoke. If omitted, uses the UUID configured on the scanner.
233
+ * @returns {Promise<RevokeResult>} `{ ok: true, data: { status } }` on success, or `{ ok: false, status, error }` on failure.
234
+ * @throws {UUIDError} When no UUID is configured and none provided, or when the UUID string is invalid.
235
+ */
236
+ revoke(uuid?: string | Field): Promise<RevokeResult>;
221
237
  /**
222
238
  * Get encrypted records from the record scanning service. This is a safe variant of /records/encrypted that returns
223
239
  * a result instead of throwing on HTTP error.
@@ -36,3 +36,27 @@ export declare function encryptViewKey(publicKey: string, viewKey: ViewKey): str
36
36
  * @returns {string} the encrypted view key in RFC 4648 standard Base64.
37
37
  */
38
38
  export declare function encryptRegistrationRequest(publicKey: string, viewKey: ViewKey, start: number): string;
39
+ /**
40
+ * Best-effort zeroization of a byte array by overwriting all bytes with zeros.
41
+ * Use this to clear sensitive data (e.g., key bytes) from memory when working
42
+ * with Uint8Array representations of keys or other secrets.
43
+ *
44
+ * This is best-effort in JavaScript — the JIT compiler could theoretically
45
+ * elide the fill if the array is never read again (though current engines
46
+ * do not). For deterministic zeroization of key material, use
47
+ * `Account.destroy()` or call `.free()` on key objects (PrivateKey, ViewKey,
48
+ * ComputeKey, GraphKey) whose Rust Drop implementations zeroize memory
49
+ * before deallocation.
50
+ *
51
+ * Note: This cannot zeroize JavaScript strings, which are immutable and managed
52
+ * by the garbage collector. Prefer using byte array representations of sensitive
53
+ * data over strings whenever possible.
54
+ *
55
+ * @param {Uint8Array} bytes The byte array to zeroize
56
+ *
57
+ * @example
58
+ * const keyBytes = privateKey.toBytesLe();
59
+ * // ... use keyBytes ...
60
+ * zeroizeBytes(keyBytes); // Overwrite with zeros when done
61
+ */
62
+ export declare function zeroizeBytes(bytes: Uint8Array): void;
@@ -1,6 +1,6 @@
1
1
  import { Address, ComputeKey, Field, Group, PrivateKey, Signature, ViewKey, PrivateKeyCiphertext, RecordCiphertext, RecordPlaintext } from "./wasm.js";
2
2
  interface AccountParam {
3
- privateKey?: string;
3
+ privateKey?: string | PrivateKey;
4
4
  seed?: Uint8Array;
5
5
  }
6
6
  /**
@@ -13,6 +13,9 @@ interface AccountParam {
13
13
  * credits and other records to. This class should only be used in environments where the safety of the underlying key
14
14
  * material can be assured.
15
15
  *
16
+ * When an Account is no longer needed, call {@link destroy} to securely zeroize and free all sensitive key material
17
+ * from WASM memory. Alternatively, use `[Symbol.dispose]()` with the `using` declaration in ES2024+ environments.
18
+ *
16
19
  * @example
17
20
  * import { Account } from "@provablehq/sdk/testnet.js";
18
21
  *
@@ -32,12 +35,16 @@ interface AccountParam {
32
35
  *
33
36
  * // Verify a signature
34
37
  * assert(myRandomAccount.verify(hello_world, signature));
38
+ *
39
+ * // Securely destroy the account when done
40
+ * myRandomAccount.destroy();
35
41
  */
36
42
  export declare class Account {
37
43
  _privateKey: PrivateKey;
38
44
  _viewKey: ViewKey;
39
45
  _computeKey: ComputeKey;
40
46
  _address: Address;
47
+ private _destroyed;
41
48
  constructor(params?: AccountParam);
42
49
  /**
43
50
  * Attempts to create an account from a private key ciphertext
@@ -69,10 +76,14 @@ export declare class Account {
69
76
  static isValidAddress(address: string | Uint8Array): boolean;
70
77
  /**
71
78
  * Creates a PrivateKey from the provided parameters.
72
- * @param {AccountParam} params The parameters containing either a private key string or a seed
79
+ * @param {AccountParam} params The parameters containing either a private key string, PrivateKey object, or a seed
73
80
  * @returns {PrivateKey} A PrivateKey instance derived from the provided parameters
74
81
  */
75
82
  private privateKeyFromParams;
83
+ /**
84
+ * Throws an error if this account has been destroyed.
85
+ */
86
+ private assertNotDestroyed;
76
87
  /**
77
88
  * Returns the PrivateKey associated with the account.
78
89
  * @returns {PrivateKey} The private key of the account
@@ -118,7 +129,8 @@ export declare class Account {
118
129
  */
119
130
  address(): Address;
120
131
  /**
121
- * Deep clones the Account.
132
+ * Deep clones the Account via byte serialization of the private key,
133
+ * avoiding creation of immutable JS string representations of the private key.
122
134
  * @returns {Account} A new Account instance with the same private key
123
135
  *
124
136
  * @example
@@ -303,5 +315,33 @@ export declare class Account {
303
315
  * assert(account.verify(message, signature));
304
316
  */
305
317
  verify(message: Uint8Array, signature: Signature): boolean;
318
+ /**
319
+ * Securely destroys the account by zeroizing and freeing all sensitive key material
320
+ * from WASM memory. After calling this method, the account object should not be used.
321
+ *
322
+ * This triggers the Rust-level zeroizing Drop implementation which overwrites private key,
323
+ * view key, and compute key bytes with zeros in WASM linear memory before deallocation.
324
+ *
325
+ * Note: If destroy() is never called, the FinalizationRegistry (set up by wasm-bindgen)
326
+ * will eventually trigger cleanup via GC, but the timing is non-deterministic. For security-
327
+ * sensitive applications, always call destroy() explicitly when the account is no longer needed.
328
+ *
329
+ * @example
330
+ * const account = new Account();
331
+ * // ... use account ...
332
+ * account.destroy(); // Securely cleans up key material
333
+ */
334
+ destroy(): void;
335
+ /**
336
+ * Implements the Disposable interface for use with `using` declarations (ES2024+).
337
+ * Calls {@link destroy} to securely clean up key material.
338
+ *
339
+ * @example
340
+ * {
341
+ * using account = new Account();
342
+ * // ... use account ...
343
+ * } // account is automatically destroyed here
344
+ */
345
+ [Symbol.dispose](): void;
306
346
  }
307
347
  export {};