agentvault 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (188) hide show
  1. package/.dfx/local/network-id +4 -0
  2. package/.next/trace +2 -0
  3. package/.vercel/README.txt +11 -0
  4. package/.vercel/project.json +1 -0
  5. package/AGENTS.md +43 -0
  6. package/CHANGELOG.md +196 -0
  7. package/LICENSE +21 -0
  8. package/PLAN_VAULT_INTEGRATION.md +318 -0
  9. package/README.md +253 -0
  10. package/backups/agentvault-backup-test-agent-2026-02-12T17-54-28-967Z.json +28 -0
  11. package/backups/agentvault-backup-test-agent-2026-02-12T17-54-29-032Z.backup +1 -0
  12. package/backups/agentvault-backup-test-agent-2026-02-12T17-57-42-373Z.json +28 -0
  13. package/backups/agentvault-backup-test-agent-2026-02-12T17-57-42-428Z.backup +1 -0
  14. package/backups/agentvault-backup-test-agent-2026-02-12T18-52-25-132Z.json +28 -0
  15. package/backups/agentvault-backup-test-agent-2026-02-12T18-52-25-247Z.backup +1 -0
  16. package/backups/agentvault-backup-test-agent-2026-02-12T18-54-09-216Z.json +28 -0
  17. package/backups/agentvault-backup-test-agent-2026-02-12T18-54-09-283Z.backup +1 -0
  18. package/backups/agentvault-backup-test-agent-2026-02-12T22-18-22-772Z.backup +1 -0
  19. package/backups/agentvault-backup-test-agent-2026-02-12T22-18-22-793Z.json +28 -0
  20. package/backups/test-backup.json +28 -0
  21. package/dist/cli/commands/approve.d.ts +4 -0
  22. package/dist/cli/commands/approve.js +232 -0
  23. package/dist/cli/commands/archive.d.ts +4 -0
  24. package/dist/cli/commands/archive.js +192 -0
  25. package/dist/cli/commands/backup.d.ts +4 -0
  26. package/dist/cli/commands/backup.js +164 -0
  27. package/dist/cli/commands/cloud-backup.d.ts +4 -0
  28. package/dist/cli/commands/cloud-backup.js +221 -0
  29. package/dist/cli/commands/cycles.d.ts +8 -0
  30. package/dist/cli/commands/cycles.js +83 -0
  31. package/dist/cli/commands/decrypt.d.ts +16 -0
  32. package/dist/cli/commands/decrypt.js +101 -0
  33. package/dist/cli/commands/deploy.d.ts +32 -0
  34. package/dist/cli/commands/deploy.js +208 -0
  35. package/dist/cli/commands/exec.d.ts +26 -0
  36. package/dist/cli/commands/exec.js +109 -0
  37. package/dist/cli/commands/fetch.d.ts +23 -0
  38. package/dist/cli/commands/fetch.js +164 -0
  39. package/dist/cli/commands/health.d.ts +8 -0
  40. package/dist/cli/commands/health.js +72 -0
  41. package/dist/cli/commands/identity.d.ts +8 -0
  42. package/dist/cli/commands/identity.js +140 -0
  43. package/dist/cli/commands/inference.d.ts +4 -0
  44. package/dist/cli/commands/inference.js +225 -0
  45. package/dist/cli/commands/info.d.ts +8 -0
  46. package/dist/cli/commands/info.js +59 -0
  47. package/dist/cli/commands/init.d.ts +19 -0
  48. package/dist/cli/commands/init.js +135 -0
  49. package/dist/cli/commands/instrument.d.ts +8 -0
  50. package/dist/cli/commands/instrument.js +35 -0
  51. package/dist/cli/commands/list.d.ts +36 -0
  52. package/dist/cli/commands/list.js +173 -0
  53. package/dist/cli/commands/logs.d.ts +8 -0
  54. package/dist/cli/commands/logs.js +96 -0
  55. package/dist/cli/commands/monitor.d.ts +8 -0
  56. package/dist/cli/commands/monitor.js +84 -0
  57. package/dist/cli/commands/network.d.ts +14 -0
  58. package/dist/cli/commands/network.js +258 -0
  59. package/dist/cli/commands/package.d.ts +36 -0
  60. package/dist/cli/commands/package.js +188 -0
  61. package/dist/cli/commands/profile.d.ts +8 -0
  62. package/dist/cli/commands/profile.js +76 -0
  63. package/dist/cli/commands/promote.d.ts +8 -0
  64. package/dist/cli/commands/promote.js +89 -0
  65. package/dist/cli/commands/rebuild.d.ts +21 -0
  66. package/dist/cli/commands/rebuild.js +140 -0
  67. package/dist/cli/commands/rollback.d.ts +8 -0
  68. package/dist/cli/commands/rollback.js +120 -0
  69. package/dist/cli/commands/show.d.ts +36 -0
  70. package/dist/cli/commands/show.js +200 -0
  71. package/dist/cli/commands/stats.d.ts +8 -0
  72. package/dist/cli/commands/stats.js +34 -0
  73. package/dist/cli/commands/status.d.ts +14 -0
  74. package/dist/cli/commands/status.js +83 -0
  75. package/dist/cli/commands/test.d.ts +8 -0
  76. package/dist/cli/commands/test.js +109 -0
  77. package/dist/cli/commands/tokens.d.ts +8 -0
  78. package/dist/cli/commands/tokens.js +62 -0
  79. package/dist/cli/commands/trace.d.ts +8 -0
  80. package/dist/cli/commands/trace.js +68 -0
  81. package/dist/cli/commands/wallet-export.d.ts +13 -0
  82. package/dist/cli/commands/wallet-export.js +140 -0
  83. package/dist/cli/commands/wallet-history.d.ts +10 -0
  84. package/dist/cli/commands/wallet-history.js +127 -0
  85. package/dist/cli/commands/wallet-import.d.ts +10 -0
  86. package/dist/cli/commands/wallet-import.js +209 -0
  87. package/dist/cli/commands/wallet-multi-send.d.ts +17 -0
  88. package/dist/cli/commands/wallet-multi-send.js +195 -0
  89. package/dist/cli/commands/wallet-process-queue.d.ts +19 -0
  90. package/dist/cli/commands/wallet-process-queue.js +209 -0
  91. package/dist/cli/commands/wallet-sign.d.ts +13 -0
  92. package/dist/cli/commands/wallet-sign.js +207 -0
  93. package/dist/cli/commands/wallet.d.ts +12 -0
  94. package/dist/cli/commands/wallet.js +794 -0
  95. package/dist/cli/index.d.ts +10 -0
  96. package/dist/cli/index.js +96 -0
  97. package/dist/vitest.config.d.ts +3 -0
  98. package/dist/vitest.config.js +14 -0
  99. package/fixup_1_0_OSS_release.md +136 -0
  100. package/fixup_REALEASE_PRD.md +136 -0
  101. package/package.json +79 -0
  102. package/pnpm-workspace.yaml +5 -0
  103. package/scripts/dev-dashboard.mjs +84 -0
  104. package/site/README.md +63 -0
  105. package/site/docusaurus.config.ts +148 -0
  106. package/site/package-lock.json +18383 -0
  107. package/site/package.json +47 -0
  108. package/site/sidebars.ts +86 -0
  109. package/site/static/.gitkeep +0 -0
  110. package/site/static/img/logo.svg +28 -0
  111. package/site/static/img/og-image.svg +35 -0
  112. package/src/archival/archive-manager.ts +372 -0
  113. package/src/archival/arweave-client.ts +289 -0
  114. package/src/archival/index.ts +8 -0
  115. package/src/backup/backup.ts +315 -0
  116. package/src/backup/index.ts +7 -0
  117. package/src/cloud-storage/cloud-sync.ts +461 -0
  118. package/src/cloud-storage/index.ts +11 -0
  119. package/src/cloud-storage/provider-detector.ts +198 -0
  120. package/src/cloud-storage/types.ts +104 -0
  121. package/src/debugging/index.ts +6 -0
  122. package/src/debugging/logs.ts +193 -0
  123. package/src/debugging/types.ts +100 -0
  124. package/src/deployment/deployer.ts +274 -0
  125. package/src/deployment/icpClient.ts +620 -0
  126. package/src/deployment/index.ts +46 -0
  127. package/src/deployment/promotion.ts +161 -0
  128. package/src/deployment/types.ts +111 -0
  129. package/src/icp/batch.ts +374 -0
  130. package/src/icp/cycles.ts +50 -0
  131. package/src/icp/environment.ts +215 -0
  132. package/src/icp/icpcli.ts +438 -0
  133. package/src/icp/icwasm.ts +222 -0
  134. package/src/icp/identity.ts +77 -0
  135. package/src/icp/index.ts +94 -0
  136. package/src/icp/optimization.ts +242 -0
  137. package/src/icp/tokens.ts +36 -0
  138. package/src/icp/tool-detector.ts +110 -0
  139. package/src/icp/types.ts +574 -0
  140. package/src/index.ts +25 -0
  141. package/src/inference/bittensor-client.ts +304 -0
  142. package/src/inference/index.ts +8 -0
  143. package/src/inference/inference-manager.ts +327 -0
  144. package/src/metrics/index.ts +7 -0
  145. package/src/metrics/metrics.ts +186 -0
  146. package/src/monitoring/alerting.ts +190 -0
  147. package/src/monitoring/health.ts +197 -0
  148. package/src/monitoring/index.ts +38 -0
  149. package/src/monitoring/info.ts +114 -0
  150. package/src/monitoring/types.ts +99 -0
  151. package/src/network/index.ts +5 -0
  152. package/src/network/network-config.ts +129 -0
  153. package/src/packaging/compiler.ts +647 -0
  154. package/src/packaging/config-persistence.ts +135 -0
  155. package/src/packaging/config-schemas.ts +156 -0
  156. package/src/packaging/detector.ts +220 -0
  157. package/src/packaging/index.ts +90 -0
  158. package/src/packaging/packager.ts +118 -0
  159. package/src/packaging/parsers/clawdbot.ts +278 -0
  160. package/src/packaging/parsers/cline.ts +223 -0
  161. package/src/packaging/parsers/generic.ts +266 -0
  162. package/src/packaging/parsers/goose.ts +214 -0
  163. package/src/packaging/parsers/index.ts +11 -0
  164. package/src/packaging/serializer.ts +260 -0
  165. package/src/packaging/types.ts +144 -0
  166. package/src/packaging/wasmedge-compiler.ts +406 -0
  167. package/src/security/index.ts +17 -0
  168. package/src/security/multisig.ts +415 -0
  169. package/src/security/types.ts +416 -0
  170. package/src/security/vetkeys.ts +655 -0
  171. package/src/testing/index.ts +6 -0
  172. package/src/testing/local-runner.ts +264 -0
  173. package/src/testing/types.ts +104 -0
  174. package/src/wallet/cbor-serializer.ts +323 -0
  175. package/src/wallet/chain-dispatcher.ts +313 -0
  176. package/src/wallet/cross-chain-aggregator.ts +346 -0
  177. package/src/wallet/index.ts +76 -0
  178. package/src/wallet/key-derivation.ts +425 -0
  179. package/src/wallet/providers/base-provider.ts +154 -0
  180. package/src/wallet/providers/cketh-provider.ts +434 -0
  181. package/src/wallet/providers/polkadot-provider.ts +503 -0
  182. package/src/wallet/providers/solana-provider.ts +490 -0
  183. package/src/wallet/transaction-queue.ts +284 -0
  184. package/src/wallet/types.ts +178 -0
  185. package/src/wallet/vetkeys-adapter.ts +431 -0
  186. package/src/wallet/wallet-manager.ts +597 -0
  187. package/src/wallet/wallet-storage.ts +380 -0
  188. package/vercel.json +8 -0
@@ -0,0 +1,655 @@
1
+ /**
2
+ * VetKeys Integration for Threshold Key Derivation
3
+ *
4
+ * This module provides VetKeys protocol implementation for threshold key derivation.
5
+ * Supports Shamir's Secret Sharing (SSS) for threshold cryptography.
6
+ *
7
+ * Security Properties:
8
+ * - Threshold signatures prevent single points of failure
9
+ * - Distributed trust model
10
+ * - Combiner-based key reconstruction
11
+ *
12
+ * Protocol Features:
13
+ * - Key derivation using secret sharing
14
+ * - Threshold signature verification
15
+ * - Key reconstruction without revealing secrets
16
+ *
17
+ * Note: VetKeysClient interface is defined in types.ts.
18
+ * This implementation class avoids the naming conflict.
19
+ */
20
+
21
+ import * as crypto from 'node:crypto';
22
+ import type {
23
+ EncryptedData,
24
+ VetKeysOptions,
25
+ EncryptionAlgorithm,
26
+ VetKeysDerivedKey as DerivedKey,
27
+ } from './types.js';
28
+
29
+ type CanisterAlgorithm = 'aes_256_gcm' | 'chacha20_poly1305';
30
+
31
+ function toCanisterAlgorithm(algorithm: EncryptionAlgorithm): CanisterAlgorithm {
32
+ return algorithm === 'aes-256-gcm' ? 'aes_256_gcm' : 'chacha20_poly1305';
33
+ }
34
+
35
+ function fromCanisterAlgorithm(canisterAlg: CanisterAlgorithm): EncryptionAlgorithm {
36
+ return canisterAlg === 'aes_256_gcm' ? 'aes-256-gcm' : 'chacha20-poly1305';
37
+ }
38
+
39
+ export class VetKeysImplementation {
40
+ private config: VetKeysOptions;
41
+ private canisterId?: string;
42
+ private useCanister: boolean;
43
+
44
+ constructor(options: VetKeysOptions & { canisterId?: string; useCanister?: boolean } = {}) {
45
+ this.config = {
46
+ threshold: options.threshold ?? 2,
47
+ totalParties: options.totalParties ?? 3,
48
+ encryptionAlgorithm: options.encryptionAlgorithm ?? 'aes-256-gcm',
49
+ vetKeysCanisterId: options.canisterId,
50
+ };
51
+ this.canisterId = options.canisterId;
52
+ this.useCanister = options.useCanister ?? !!options.canisterId;
53
+ }
54
+
55
+ /**
56
+ * Decrypt JSON data using seed phrase
57
+ *
58
+ * @param encrypted - Encrypted data to decrypt
59
+ * @param seedPhrase - Seed phrase for key derivation
60
+ * @returns Decrypted JSON object
61
+ */
62
+ public static async decryptJSON<T = unknown>(
63
+ encrypted: EncryptedData,
64
+ seedPhrase: string
65
+ ): Promise<T> {
66
+ const crypto = await import('node:crypto');
67
+ const bip39 = await import('bip39');
68
+
69
+ // Derive key from seed phrase
70
+ const seed = await bip39.mnemonicToSeed(seedPhrase);
71
+ const key = crypto.pbkdf2Sync(
72
+ seed,
73
+ encrypted.salt,
74
+ 100000,
75
+ 32,
76
+ 'sha256',
77
+ );
78
+
79
+ // Decode IV and ciphertext
80
+ const iv = Buffer.from(encrypted.iv, 'hex');
81
+ const ciphertext = Buffer.from(encrypted.ciphertext, 'hex');
82
+
83
+ // Decrypt based on algorithm
84
+ let algorithm: string;
85
+ if (encrypted.algorithm === 'aes-256-gcm') {
86
+ algorithm = 'aes-256-gcm';
87
+ } else {
88
+ algorithm = encrypted.algorithm.replace('-', '');
89
+ }
90
+
91
+ const decipher = crypto.createDecipheriv(algorithm, key, iv);
92
+
93
+ const decrypted = Buffer.concat([
94
+ decipher.update(ciphertext),
95
+ decipher.final(),
96
+ ]);
97
+
98
+ return JSON.parse(decrypted.toString('utf-8')) as T;
99
+ }
100
+
101
+ /**
102
+ * Derive threshold key from seed phrase
103
+ *
104
+ * Implements Shamir's Secret Sharing for threshold key derivation.
105
+ * Generates n secret shares (where threshold = t out of n)
106
+ * Each share is encrypted and can be used to reconstruct the master key.
107
+ *
108
+ * @param seedPhrase - BIP39 seed phrase
109
+ * @param options - Optional derivation options
110
+ * @returns Derived key with threshold parameters
111
+ */
112
+ public async deriveThresholdKey(
113
+ seedPhrase: string,
114
+ options: VetKeysOptions & {
115
+ threshold?: number;
116
+ totalParties?: number;
117
+ encryptionAlgorithm?: EncryptionAlgorithm;
118
+ } = {}
119
+ ): Promise<DerivedKey> {
120
+ const threshold = options.threshold ?? this.config.threshold;
121
+ const totalParties = options.totalParties ?? this.config.totalParties;
122
+ const algorithm = options.encryptionAlgorithm ?? this.config.encryptionAlgorithm;
123
+
124
+ // Validate threshold
125
+ if (threshold! < 1 || threshold! > totalParties!) {
126
+ throw new Error(
127
+ `Threshold must be between 1 and totalParticipants (${totalParties!}). Got: ${threshold}`
128
+ );
129
+ }
130
+
131
+ try {
132
+ // Derive n secret shares from seed phrase
133
+ const shares = await this.generateSecretShares(seedPhrase, threshold!, totalParties!, algorithm!);
134
+
135
+ // Generate share metadata
136
+ const shareMetadata = shares.map((share, index) => ({
137
+ index: index + 1,
138
+ shareId: this.generateShareId(),
139
+ participantId: (index + 1).toString(),
140
+ encryptedShare: share.encryptedShare,
141
+ commitment: share.commitment,
142
+ }));
143
+
144
+ // Generate commitment
145
+ const commitment = await this.generateCommitment(shares);
146
+
147
+ // Generate verification parameters
148
+ const verification = {
149
+ threshold,
150
+ shares,
151
+ commitment,
152
+ algorithm,
153
+ encryptionAlgorithm: algorithm,
154
+ createdAt: new Date().toISOString(),
155
+ };
156
+
157
+ // Derive master key from seed phrase (for local use)
158
+ const derivedKey = await this.deriveMasterKey(seedPhrase, algorithm!);
159
+
160
+ return {
161
+ type: 'threshold',
162
+ key: derivedKey.key,
163
+ method: derivedKey.method,
164
+ seedPhrase,
165
+ threshold: threshold!,
166
+ totalParties: totalParties!,
167
+ algorithm: algorithm!,
168
+ shares,
169
+ shareMetadata,
170
+ commitment,
171
+ verification,
172
+ } as DerivedKey;
173
+ } catch (error) {
174
+ const message = error instanceof Error ? error.message : 'Unknown error';
175
+ throw new Error(`Failed to derive threshold key: ${message}`);
176
+ }
177
+ }
178
+
179
+ /**
180
+ * Generate secret shares using Shamir's Secret Sharing
181
+ *
182
+ * @param seedPhrase - Master secret
183
+ * @param threshold - Number of shares to create (t)
184
+ * @param totalParties - Total number of participants (n)
185
+ * @param algorithm - Encryption algorithm to use
186
+ * @returns Array of encrypted shares
187
+ */
188
+ private async generateSecretShares(
189
+ seedPhrase: string,
190
+ threshold: number,
191
+ totalParties: number,
192
+ algorithm: EncryptionAlgorithm
193
+ ): Promise<Array<{ shareId: string; participantId: string; encryptedShare: string; commitment: string }>> {
194
+ const shares: Array<{ shareId: string; participantId: string; encryptedShare: string; commitment: string }> = [];
195
+ const masterCommitment = await this.generateCommitment(shares);
196
+
197
+ for (let i = 0; i < threshold; i++) {
198
+ const shareId = this.generateShareId();
199
+ const participantId = i + 1;
200
+
201
+ // Generate unique secret for this participant
202
+ const participantSecret = this.generateParticipantSecret(seedPhrase, i, totalParties);
203
+
204
+ // Encrypt share with participant's secret
205
+ const { encryptedShare, commitment: shareCommitment } = await this.encryptShare(
206
+ participantSecret,
207
+ masterCommitment,
208
+ algorithm,
209
+ );
210
+
211
+ shares.push({
212
+ shareId,
213
+ participantId: participantId.toString(),
214
+ encryptedShare,
215
+ commitment: shareCommitment,
216
+ });
217
+ }
218
+
219
+ return shares;
220
+ }
221
+
222
+ /**
223
+ * Generate share identifier using cryptographically secure random bytes
224
+ */
225
+ private generateShareId(): string {
226
+ const randomBytes = crypto.randomBytes(4);
227
+ const timestamp = Date.now().toString(36);
228
+ const randomHex = randomBytes.toString('hex').substring(0, 8);
229
+ return `share_${timestamp}_${randomHex}`;
230
+ }
231
+
232
+ /**
233
+ * Generate unique secret for a participant
234
+ *
235
+ * @param seedPhrase - Master secret
236
+ * @param participantIndex - Participant index (1-based)
237
+ */
238
+ private generateParticipantSecret(seedPhrase: string, participantIndex: number, _totalParties: number): string {
239
+ const secretBytes = Buffer.from(seedPhrase, 'utf8');
240
+
241
+ // Create unique secret for this participant by adding participant index
242
+ const participantSuffix = Buffer.concat([Buffer.from([participantIndex]), secretBytes]);
243
+
244
+ return participantSuffix.toString('hex');
245
+ }
246
+
247
+ /**
248
+ * Encrypt a secret share
249
+ *
250
+ * @param secret - Secret to encrypt
251
+ * @param algorithm - Encryption algorithm
252
+ */
253
+ private async encryptShare(
254
+ secret: string,
255
+ _commitment: string,
256
+ algorithm: EncryptionAlgorithm
257
+ ): Promise<{ encryptedShare: string; commitment: string }> {
258
+ const crypto = await import('node:crypto');
259
+
260
+ const secretBuffer = Buffer.from(secret, 'utf-8');
261
+ const iv = algorithm === 'aes-256-gcm' ? crypto.randomBytes(12) : crypto.randomBytes(16);
262
+ const algorithmName = algorithm.replace('-', '');
263
+
264
+ const encryptionKey = crypto.pbkdf2Sync(
265
+ secretBuffer,
266
+ iv,
267
+ 100000,
268
+ 32,
269
+ 'sha256'
270
+ );
271
+
272
+ const cipher = crypto.createCipheriv(algorithmName, encryptionKey, iv);
273
+
274
+ const encryptedShare = Buffer.concat([
275
+ cipher.update(secretBuffer),
276
+ cipher.final(),
277
+ ]);
278
+
279
+ const commitmentHash = crypto.createHash('sha256')
280
+ .update(encryptedShare)
281
+ .digest();
282
+
283
+ return {
284
+ encryptedShare: encryptedShare.toString('hex'),
285
+ commitment: commitmentHash.toString('hex'),
286
+ };
287
+ }
288
+
289
+ /**
290
+ * Generate commitment from all shares
291
+ */
292
+ private async generateCommitment(shares: Array<{ encryptedShare: string }>): Promise<string> {
293
+ const crypto = await import('node:crypto');
294
+ const hash = crypto.createHash('sha256');
295
+
296
+ // Combine all encrypted shares
297
+ for (const share of shares) {
298
+ const shareBuffer = Buffer.from(share.encryptedShare, 'hex');
299
+ hash.update(shareBuffer);
300
+ }
301
+
302
+ return hash.digest('hex');
303
+ }
304
+
305
+ /**
306
+ * Derive master key from seed phrase (for local use)
307
+ *
308
+ * Uses PBKDF2 for key derivation with a derived salt from the seed.
309
+ * This is NOT the threshold key, but the master secret that participants share.
310
+ */
311
+ private async deriveMasterKey(seedPhrase: string, _algorithm: EncryptionAlgorithm): Promise<{ key: string; method: string }> {
312
+ const crypto = await import('node:crypto');
313
+ const bip39 = await import('bip39');
314
+
315
+ const seed = await bip39.mnemonicToSeed(seedPhrase);
316
+
317
+ // Derive salt from seed (first 16 bytes) for unique per-wallet salting
318
+ const salt = crypto.createHash('sha256')
319
+ .update(seed.slice(0, 16))
320
+ .update('agentvault-v1')
321
+ .digest();
322
+
323
+ // Derive key using PBKDF2 with unique salt
324
+ const key = crypto.pbkdf2Sync(
325
+ seed,
326
+ salt,
327
+ 100000,
328
+ 32,
329
+ 'sha256',
330
+ );
331
+
332
+ return {
333
+ key: key.toString('hex'),
334
+ method: 'pbkdf2',
335
+ };
336
+ }
337
+
338
+ /**
339
+ * Verify encryption was created by VetKeys
340
+ *
341
+ * Validates that the encrypted data structure is valid and properly formatted.
342
+ *
343
+ * @param encrypted - Encrypted data to verify
344
+ * @returns True if the encryption structure is valid
345
+ */
346
+ public async verifyEncryption(encrypted: EncryptedData): Promise<boolean> {
347
+ if (!encrypted) {
348
+ return false;
349
+ }
350
+
351
+ if (!encrypted.algorithm || !['aes-256-gcm', 'chacha20-poly1305'].includes(encrypted.algorithm)) {
352
+ return false;
353
+ }
354
+
355
+ if (!encrypted.iv || typeof encrypted.iv !== 'string') {
356
+ return false;
357
+ }
358
+
359
+ const ivBytes = Buffer.from(encrypted.iv, 'hex');
360
+ const expectedIvLength = encrypted.algorithm === 'aes-256-gcm' ? 12 : 16;
361
+ if (ivBytes.length !== expectedIvLength) {
362
+ return false;
363
+ }
364
+
365
+ if (!encrypted.salt || typeof encrypted.salt !== 'string') {
366
+ return false;
367
+ }
368
+
369
+ const saltBytes = Buffer.from(encrypted.salt, 'hex');
370
+ if (saltBytes.length < 8) {
371
+ return false;
372
+ }
373
+
374
+ if (!encrypted.ciphertext || typeof encrypted.ciphertext !== 'string') {
375
+ return false;
376
+ }
377
+
378
+ const ciphertextBytes = Buffer.from(encrypted.ciphertext, 'hex');
379
+ if (ciphertextBytes.length === 0) {
380
+ return false;
381
+ }
382
+
383
+ if (encrypted.encryptedAt) {
384
+ const timestamp = new Date(encrypted.encryptedAt);
385
+ if (isNaN(timestamp.getTime())) {
386
+ return false;
387
+ }
388
+ }
389
+
390
+ return true;
391
+ }
392
+
393
+ /**
394
+ * Get encryption status
395
+ */
396
+ public getEncryptionStatus(): {
397
+ thresholdSupported: boolean;
398
+ totalParticipants: number;
399
+ currentThreshold: number;
400
+ encryptionAlgorithm: EncryptionAlgorithm;
401
+ keyDerivation: string;
402
+ } {
403
+ return {
404
+ thresholdSupported: true,
405
+ totalParticipants: this.config.totalParties!,
406
+ currentThreshold: this.config.threshold!,
407
+ encryptionAlgorithm: this.config.encryptionAlgorithm!,
408
+ keyDerivation: 'shamir-ss',
409
+ };
410
+ }
411
+
412
+ /**
413
+ * Store encrypted secret on canister
414
+ *
415
+ * @param secretId - ID of the secret
416
+ * @param encryptedSecret - Encrypted secret data
417
+ * @returns True if stored successfully
418
+ */
419
+ public async storeEncryptedSecretOnCanister(
420
+ secretId: string,
421
+ encryptedSecret: {
422
+ ciphertext: Uint8Array;
423
+ iv: Uint8Array;
424
+ tag: Uint8Array;
425
+ algorithm: EncryptionAlgorithm;
426
+ }
427
+ ): Promise<boolean> {
428
+ if (!this.useCanister) {
429
+ console.warn('Canister integration disabled, skipping canister storage');
430
+ return false;
431
+ }
432
+
433
+ if (!this.canisterId) {
434
+ console.warn('Canister ID not configured, skipping canister storage');
435
+ return false;
436
+ }
437
+
438
+ try {
439
+ const { createActor } = await import('../canister/actor.js');
440
+ const actor = createActor(this.canisterId);
441
+
442
+ const result = await actor.storeEncryptedSecret({
443
+ id: secretId,
444
+ ciphertext: new Uint8Array(encryptedSecret.ciphertext),
445
+ iv: new Uint8Array(encryptedSecret.iv),
446
+ tag: new Uint8Array(encryptedSecret.tag),
447
+ algorithm: toCanisterAlgorithm(encryptedSecret.algorithm),
448
+ createdAt: Date.now(),
449
+ });
450
+
451
+ if ('ok' in result) {
452
+ console.log('Encrypted secret stored on canister:', secretId);
453
+ return true;
454
+ }
455
+
456
+ return false;
457
+ } catch (error) {
458
+ const message = error instanceof Error ? error.message : 'Unknown error';
459
+ console.warn(`Failed to store encrypted secret on canister: ${message}`);
460
+ return false;
461
+ }
462
+ }
463
+
464
+ /**
465
+ * Retrieve encrypted secret from canister
466
+ *
467
+ * @param secretId - ID of the secret
468
+ * @returns Encrypted secret data or null
469
+ */
470
+ public async getEncryptedSecretFromCanister(
471
+ secretId: string
472
+ ): Promise<{ ciphertext: Uint8Array; iv: Uint8Array; tag: Uint8Array; algorithm: EncryptionAlgorithm } | null> {
473
+ if (!this.canisterId) {
474
+ return null;
475
+ }
476
+
477
+ try {
478
+ const { createActor } = await import('../canister/actor.js');
479
+ const actor = createActor(this.canisterId);
480
+
481
+ const result = await actor.getEncryptedSecret(secretId);
482
+
483
+ if (!result || result.length === 0) {
484
+ return null;
485
+ }
486
+
487
+ const [secret] = result;
488
+
489
+ return {
490
+ ciphertext: new Uint8Array(secret.ciphertext),
491
+ iv: new Uint8Array(secret.iv),
492
+ tag: new Uint8Array(secret.tag),
493
+ algorithm: fromCanisterAlgorithm(secret.algorithm),
494
+ };
495
+ } catch (error) {
496
+ const message = error instanceof Error ? error.message : 'Unknown error';
497
+ console.warn(`Failed to retrieve encrypted secret from canister: ${message}`);
498
+ return null;
499
+ }
500
+ }
501
+
502
+ /**
503
+ * List all encrypted secrets from canister
504
+ *
505
+ * @returns Array of secret IDs
506
+ */
507
+ public async listEncryptedSecretsOnCanister(): Promise<string[]> {
508
+ if (!this.canisterId) {
509
+ return [];
510
+ }
511
+
512
+ try {
513
+ const { createActor } = await import('../canister/actor.js');
514
+ const actor = createActor(this.canisterId);
515
+
516
+ const secrets = await actor.listEncryptedSecrets();
517
+
518
+ return secrets.map(s => s.id);
519
+ } catch (error) {
520
+ const message = error instanceof Error ? error.message : 'Unknown error';
521
+ console.warn(`Failed to list encrypted secrets from canister: ${message}`);
522
+ return [];
523
+ }
524
+ }
525
+
526
+ /**
527
+ * Delete encrypted secret from canister
528
+ *
529
+ * @param secretId - ID of the secret
530
+ * @returns True if deleted successfully
531
+ */
532
+ public async deleteEncryptedSecretFromCanister(secretId: string): Promise<boolean> {
533
+ if (!this.canisterId) {
534
+ return false;
535
+ }
536
+
537
+ try {
538
+ const { createActor } = await import('../canister/actor.js');
539
+ const actor = createActor(this.canisterId);
540
+
541
+ const result = await actor.deleteEncryptedSecret(secretId);
542
+
543
+ if ('ok' in result) {
544
+ return true;
545
+ }
546
+
547
+ return false;
548
+ } catch (error) {
549
+ const message = error instanceof Error ? error.message : 'Unknown error';
550
+ console.warn(`Failed to delete encrypted secret from canister: ${message}`);
551
+ return false;
552
+ }
553
+ }
554
+
555
+ /**
556
+ * Verify threshold signature with canister
557
+ *
558
+ * IMPORTANT: Requires VetKeys canister to be deployed and connected.
559
+ * Returns false if canister is not available.
560
+ *
561
+ * @param signature - Signature to verify
562
+ * @param message - Original message
563
+ * @returns True if signature is valid
564
+ */
565
+ public async verifyThresholdSignatureCanister(
566
+ signature: string,
567
+ message: string
568
+ ): Promise<boolean> {
569
+ if (!this.canisterId) {
570
+ console.warn('VetKeys canister not configured: cannot verify threshold signature');
571
+ return false;
572
+ }
573
+
574
+ try {
575
+ const { createActor } = await import('../canister/actor.js');
576
+ const actor = createActor(this.canisterId);
577
+
578
+ const result = await actor.verifyThresholdSignature(signature, message);
579
+
580
+ if ('ok' in result && result.ok === 'verified') {
581
+ return true;
582
+ }
583
+
584
+ return false;
585
+ } catch (error) {
586
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
587
+ console.warn(`Failed to verify threshold signature on canister: ${errorMessage}`);
588
+ return false;
589
+ }
590
+ }
591
+
592
+ /**
593
+ * Get VetKeys status from canister
594
+ *
595
+ * @returns VetKeys status information
596
+ */
597
+ public async getVetKeysStatusFromCanister(): Promise<{
598
+ enabled: boolean;
599
+ thresholdSupported: boolean;
600
+ mode: 'mock' | 'production';
601
+ }> {
602
+ if (!this.canisterId) {
603
+ return {
604
+ enabled: false,
605
+ thresholdSupported: true,
606
+ mode: 'mock',
607
+ };
608
+ }
609
+
610
+ try {
611
+ const { createActor } = await import('../canister/actor.js');
612
+ const actor = createActor(this.canisterId);
613
+
614
+ const status = await actor.getVetKeysStatus();
615
+
616
+ let mode: 'mock' | 'production' = 'mock';
617
+ const hasMockMode = status.mode && typeof status.mode === 'object' && 'mock' in status.mode;
618
+ const hasProductionMode = status.mode && typeof status.mode === 'object' && 'production' in status.mode;
619
+
620
+ if (hasMockMode) {
621
+ mode = 'mock';
622
+ } else if (hasProductionMode) {
623
+ mode = 'production';
624
+ }
625
+
626
+ return {
627
+ enabled: status.enabled,
628
+ thresholdSupported: status.thresholdSupported,
629
+ mode: mode,
630
+ };
631
+ } catch (error) {
632
+ const message = error instanceof Error ? error.message : 'Unknown error';
633
+ console.warn(`Failed to get VetKeys status from canister: ${message}`);
634
+ return {
635
+ enabled: false,
636
+ thresholdSupported: true,
637
+ mode: 'mock',
638
+ };
639
+ }
640
+ }
641
+ }
642
+
643
+ /**
644
+ * Decrypt JSON data using seed phrase
645
+ *
646
+ * @param encrypted - Encrypted data to decrypt
647
+ * @param seedPhrase - Seed phrase for key derivation
648
+ * @returns Decrypted JSON object
649
+ */
650
+ export async function decryptJSON<T = unknown>(
651
+ encrypted: EncryptedData,
652
+ seedPhrase: string
653
+ ): Promise<T> {
654
+ return VetKeysImplementation.decryptJSON(encrypted, seedPhrase);
655
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Testing module
3
+ */
4
+
5
+ export * from './types.js';
6
+ export * from './local-runner.js';