@cmdoss/memwal-sdk 0.6.2 โ 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +547 -547
- package/BENCHMARKS.md +238 -238
- package/README.md +310 -181
- package/dist/ai-sdk/tools.d.ts +2 -2
- package/dist/ai-sdk/tools.js +2 -2
- package/dist/client/ClientMemoryManager.js +2 -2
- package/dist/client/ClientMemoryManager.js.map +1 -1
- package/dist/client/PersonalDataWallet.d.ts.map +1 -1
- package/dist/client/SimplePDWClient.d.ts +29 -1
- package/dist/client/SimplePDWClient.d.ts.map +1 -1
- package/dist/client/SimplePDWClient.js +45 -13
- package/dist/client/SimplePDWClient.js.map +1 -1
- package/dist/client/namespaces/EmbeddingsNamespace.d.ts +1 -1
- package/dist/client/namespaces/EmbeddingsNamespace.js +1 -1
- package/dist/client/namespaces/MemoryNamespace.d.ts +31 -0
- package/dist/client/namespaces/MemoryNamespace.d.ts.map +1 -1
- package/dist/client/namespaces/MemoryNamespace.js +272 -39
- package/dist/client/namespaces/MemoryNamespace.js.map +1 -1
- package/dist/client/namespaces/consolidated/AINamespace.d.ts +2 -2
- package/dist/client/namespaces/consolidated/AINamespace.js +2 -2
- package/dist/client/namespaces/consolidated/BlockchainNamespace.d.ts +12 -2
- package/dist/client/namespaces/consolidated/BlockchainNamespace.d.ts.map +1 -1
- package/dist/client/namespaces/consolidated/BlockchainNamespace.js +62 -4
- package/dist/client/namespaces/consolidated/BlockchainNamespace.js.map +1 -1
- package/dist/client/namespaces/consolidated/StorageNamespace.d.ts +67 -2
- package/dist/client/namespaces/consolidated/StorageNamespace.d.ts.map +1 -1
- package/dist/client/namespaces/consolidated/StorageNamespace.js +549 -16
- package/dist/client/namespaces/consolidated/StorageNamespace.js.map +1 -1
- package/dist/config/ConfigurationHelper.js +61 -61
- package/dist/config/defaults.js +2 -2
- package/dist/config/defaults.js.map +1 -1
- package/dist/graph/GraphService.js +21 -21
- package/dist/graph/GraphService.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/seal/EncryptionService.d.ts +9 -5
- package/dist/infrastructure/seal/EncryptionService.d.ts.map +1 -1
- package/dist/infrastructure/seal/EncryptionService.js +37 -15
- package/dist/infrastructure/seal/EncryptionService.js.map +1 -1
- package/dist/infrastructure/seal/SealService.d.ts +13 -5
- package/dist/infrastructure/seal/SealService.d.ts.map +1 -1
- package/dist/infrastructure/seal/SealService.js +36 -34
- package/dist/infrastructure/seal/SealService.js.map +1 -1
- package/dist/langchain/createPDWRAG.js +30 -30
- package/dist/retrieval/MemoryDecryptionPipeline.d.ts.map +1 -1
- package/dist/retrieval/MemoryDecryptionPipeline.js +2 -1
- package/dist/retrieval/MemoryDecryptionPipeline.js.map +1 -1
- package/dist/retrieval/MemoryRetrievalService.d.ts +31 -0
- package/dist/retrieval/MemoryRetrievalService.d.ts.map +1 -1
- package/dist/retrieval/MemoryRetrievalService.js +44 -4
- package/dist/retrieval/MemoryRetrievalService.js.map +1 -1
- package/dist/services/CapabilityService.d.ts.map +1 -1
- package/dist/services/CapabilityService.js +30 -14
- package/dist/services/CapabilityService.js.map +1 -1
- package/dist/services/CrossContextPermissionService.d.ts.map +1 -1
- package/dist/services/CrossContextPermissionService.js +9 -7
- package/dist/services/CrossContextPermissionService.js.map +1 -1
- package/dist/services/EmbeddingService.d.ts +28 -1
- package/dist/services/EmbeddingService.d.ts.map +1 -1
- package/dist/services/EmbeddingService.js +54 -0
- package/dist/services/EmbeddingService.js.map +1 -1
- package/dist/services/EncryptionService.d.ts.map +1 -1
- package/dist/services/EncryptionService.js +6 -5
- package/dist/services/EncryptionService.js.map +1 -1
- package/dist/services/GeminiAIService.js +309 -309
- package/dist/services/IndexManager.d.ts +5 -1
- package/dist/services/IndexManager.d.ts.map +1 -1
- package/dist/services/IndexManager.js +17 -40
- package/dist/services/IndexManager.js.map +1 -1
- package/dist/services/QueryService.js +1 -1
- package/dist/services/QueryService.js.map +1 -1
- package/dist/services/StorageService.d.ts +11 -0
- package/dist/services/StorageService.d.ts.map +1 -1
- package/dist/services/StorageService.js +73 -10
- package/dist/services/StorageService.js.map +1 -1
- package/dist/services/TransactionService.d.ts +20 -0
- package/dist/services/TransactionService.d.ts.map +1 -1
- package/dist/services/TransactionService.js +43 -0
- package/dist/services/TransactionService.js.map +1 -1
- package/dist/services/ViewService.js +2 -2
- package/dist/services/ViewService.js.map +1 -1
- package/dist/services/storage/QuiltBatchManager.d.ts +101 -1
- package/dist/services/storage/QuiltBatchManager.d.ts.map +1 -1
- package/dist/services/storage/QuiltBatchManager.js +410 -20
- package/dist/services/storage/QuiltBatchManager.js.map +1 -1
- package/dist/services/storage/index.d.ts +1 -1
- package/dist/services/storage/index.d.ts.map +1 -1
- package/dist/services/storage/index.js.map +1 -1
- package/dist/utils/LRUCache.d.ts +106 -0
- package/dist/utils/LRUCache.d.ts.map +1 -0
- package/dist/utils/LRUCache.js +281 -0
- package/dist/utils/LRUCache.js.map +1 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +2 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/memoryIndexOnChain.d.ts +212 -0
- package/dist/utils/memoryIndexOnChain.d.ts.map +1 -0
- package/dist/utils/memoryIndexOnChain.js +312 -0
- package/dist/utils/memoryIndexOnChain.js.map +1 -0
- package/dist/utils/rebuildIndexNode.d.ts +29 -0
- package/dist/utils/rebuildIndexNode.d.ts.map +1 -1
- package/dist/utils/rebuildIndexNode.js +366 -98
- package/dist/utils/rebuildIndexNode.js.map +1 -1
- package/dist/vector/HnswWasmService.d.ts +20 -5
- package/dist/vector/HnswWasmService.d.ts.map +1 -1
- package/dist/vector/HnswWasmService.js +73 -40
- package/dist/vector/HnswWasmService.js.map +1 -1
- package/dist/vector/IHnswService.d.ts +10 -1
- package/dist/vector/IHnswService.d.ts.map +1 -1
- package/dist/vector/IHnswService.js.map +1 -1
- package/dist/vector/NodeHnswService.d.ts +16 -0
- package/dist/vector/NodeHnswService.d.ts.map +1 -1
- package/dist/vector/NodeHnswService.js +84 -5
- package/dist/vector/NodeHnswService.js.map +1 -1
- package/dist/vector/createHnswService.d.ts +1 -1
- package/dist/vector/createHnswService.js +1 -1
- package/dist/vector/index.d.ts +1 -1
- package/dist/vector/index.js +1 -1
- package/package.json +157 -157
- package/src/access/PermissionService.ts +635 -635
- package/src/aggregation/AggregationService.ts +389 -389
- package/src/ai-sdk/PDWVectorStore.ts +715 -715
- package/src/ai-sdk/index.ts +65 -65
- package/src/ai-sdk/tools.ts +460 -460
- package/src/ai-sdk/types.ts +404 -404
- package/src/batch/BatchManager.ts +597 -597
- package/src/batch/BatchingService.ts +429 -429
- package/src/batch/MemoryProcessingCache.ts +492 -492
- package/src/batch/index.ts +30 -30
- package/src/browser.ts +200 -200
- package/src/client/ClientMemoryManager.ts +987 -987
- package/src/client/PersonalDataWallet.ts +345 -345
- package/src/client/SimplePDWClient.ts +1289 -1222
- package/src/client/factory.ts +154 -154
- package/src/client/namespaces/AnalyticsNamespace.ts +377 -377
- package/src/client/namespaces/BatchNamespace.ts +356 -356
- package/src/client/namespaces/CacheNamespace.ts +123 -123
- package/src/client/namespaces/CapabilityNamespace.ts +217 -217
- package/src/client/namespaces/ClassifyNamespace.ts +169 -169
- package/src/client/namespaces/ContextNamespace.ts +297 -297
- package/src/client/namespaces/EmbeddingsNamespace.ts +99 -99
- package/src/client/namespaces/EncryptionNamespace.ts +221 -221
- package/src/client/namespaces/GraphNamespace.ts +468 -468
- package/src/client/namespaces/IndexNamespace.ts +361 -361
- package/src/client/namespaces/MemoryNamespace.ts +1422 -1135
- package/src/client/namespaces/PermissionsNamespace.ts +254 -254
- package/src/client/namespaces/PipelineNamespace.ts +220 -220
- package/src/client/namespaces/SearchNamespace.ts +1049 -1049
- package/src/client/namespaces/StorageNamespace.ts +458 -458
- package/src/client/namespaces/TxNamespace.ts +260 -260
- package/src/client/namespaces/WalletNamespace.ts +243 -243
- package/src/client/namespaces/consolidated/AINamespace.ts +449 -449
- package/src/client/namespaces/consolidated/BlockchainNamespace.ts +607 -546
- package/src/client/namespaces/consolidated/SecurityNamespace.ts +648 -648
- package/src/client/namespaces/consolidated/StorageNamespace.ts +1141 -497
- package/src/client/namespaces/consolidated/index.ts +39 -39
- package/src/client/signers/KeypairSigner.ts +108 -108
- package/src/client/signers/UnifiedSigner.ts +110 -110
- package/src/client/signers/WalletAdapterSigner.ts +159 -159
- package/src/client/signers/index.ts +26 -26
- package/src/config/ConfigurationHelper.ts +412 -412
- package/src/config/defaults.ts +51 -51
- package/src/config/index.ts +8 -8
- package/src/config/validation.ts +70 -70
- package/src/core/index.ts +14 -14
- package/src/core/interfaces/IService.ts +307 -307
- package/src/core/interfaces/index.ts +8 -8
- package/src/core/types/capability.ts +297 -297
- package/src/core/types/index.ts +870 -870
- package/src/core/types/wallet.ts +270 -270
- package/src/core/types.ts +9 -9
- package/src/core/wallet.ts +222 -222
- package/src/embedding/index.ts +19 -19
- package/src/embedding/types.ts +357 -357
- package/src/errors/index.ts +602 -602
- package/src/errors/recovery.ts +461 -461
- package/src/errors/validation.ts +567 -567
- package/src/generated/pdw/capability.ts +319 -319
- package/src/graph/GraphService.ts +887 -887
- package/src/graph/KnowledgeGraphManager.ts +728 -728
- package/src/graph/index.ts +25 -25
- package/src/index.ts +498 -474
- package/src/infrastructure/index.ts +22 -22
- package/src/infrastructure/seal/EncryptionService.ts +628 -603
- package/src/infrastructure/seal/SealService.ts +613 -615
- package/src/infrastructure/seal/index.ts +9 -9
- package/src/infrastructure/sui/BlockchainManager.ts +627 -627
- package/src/infrastructure/sui/SuiService.ts +888 -888
- package/src/infrastructure/sui/index.ts +9 -9
- package/src/infrastructure/walrus/StorageManager.ts +604 -604
- package/src/infrastructure/walrus/WalrusStorageService.ts +612 -612
- package/src/infrastructure/walrus/index.ts +9 -9
- package/src/langchain/PDWEmbeddings.ts +145 -145
- package/src/langchain/PDWVectorStore.ts +456 -456
- package/src/langchain/createPDWRAG.ts +303 -303
- package/src/langchain/index.ts +47 -47
- package/src/permissions/ConsentRepository.browser.ts +249 -249
- package/src/permissions/ConsentRepository.ts +364 -364
- package/src/pipeline/MemoryPipeline.ts +862 -862
- package/src/pipeline/PipelineManager.ts +683 -683
- package/src/pipeline/index.ts +26 -26
- package/src/retrieval/AdvancedSearchService.ts +629 -629
- package/src/retrieval/MemoryAnalyticsService.ts +711 -711
- package/src/retrieval/MemoryDecryptionPipeline.ts +825 -824
- package/src/retrieval/MemoryRetrievalService.ts +904 -830
- package/src/retrieval/index.ts +42 -42
- package/src/services/BatchService.ts +352 -352
- package/src/services/CapabilityService.ts +464 -448
- package/src/services/ClassifierService.ts +465 -465
- package/src/services/CrossContextPermissionService.ts +486 -484
- package/src/services/EmbeddingService.ts +771 -706
- package/src/services/EncryptionService.ts +712 -711
- package/src/services/GeminiAIService.ts +753 -753
- package/src/services/IndexManager.ts +977 -1004
- package/src/services/MemoryIndexService.ts +1003 -1003
- package/src/services/MemoryService.ts +369 -369
- package/src/services/QueryService.ts +890 -890
- package/src/services/StorageService.ts +1182 -1111
- package/src/services/TransactionService.ts +838 -790
- package/src/services/VectorService.ts +462 -462
- package/src/services/ViewService.ts +484 -484
- package/src/services/index.ts +25 -25
- package/src/services/storage/BlobAttributesManager.ts +333 -333
- package/src/services/storage/KnowledgeGraphManager.ts +425 -425
- package/src/services/storage/MemorySearchManager.ts +387 -387
- package/src/services/storage/QuiltBatchManager.ts +1130 -660
- package/src/services/storage/WalrusMetadataManager.ts +268 -268
- package/src/services/storage/WalrusStorageManager.ts +287 -287
- package/src/services/storage/index.ts +57 -52
- package/src/types/index.ts +13 -13
- package/src/utils/LRUCache.ts +378 -0
- package/src/utils/index.ts +76 -68
- package/src/utils/memoryIndexOnChain.ts +507 -0
- package/src/utils/rebuildIndex.ts +290 -290
- package/src/utils/rebuildIndexNode.ts +771 -424
- package/src/vector/BrowserHnswIndexService.ts +758 -758
- package/src/vector/HnswWasmService.ts +731 -679
- package/src/vector/IHnswService.ts +233 -224
- package/src/vector/NodeHnswService.ts +833 -735
- package/src/vector/VectorManager.ts +478 -478
- package/src/vector/createHnswService.ts +135 -135
- package/src/vector/index.ts +56 -56
- package/src/wallet/ContextWalletService.ts +656 -656
- package/src/wallet/MainWalletService.ts +317 -317
|
@@ -1,825 +1,826 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MemoryDecryptionPipeline - Seamless SEAL-based Memory Decryption
|
|
3
|
-
*
|
|
4
|
-
* Provides comprehensive decryption capabilities for encrypted memories using
|
|
5
|
-
* Mysten's SEAL SDK with official testnet key servers and configurable infrastructure.
|
|
6
|
-
*
|
|
7
|
-
* Features:
|
|
8
|
-
* - ๐ Seamless SEAL decryption integration
|
|
9
|
-
* - ๐ Automatic key server configuration (testnet/mainnet)
|
|
10
|
-
* - โก Batch decryption optimization
|
|
11
|
-
* - ๐ก๏ธ Secure session key management
|
|
12
|
-
* - ๐ Automatic retry and fallback mechanisms
|
|
13
|
-
* - ๐ Decryption analytics and monitoring
|
|
14
|
-
* - ๐ Environment-based configuration
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import { SealClient, SessionKey } from '@mysten/seal';
|
|
18
|
-
import { Transaction } from '@mysten/sui/transactions';
|
|
19
|
-
import { fromHex, toHex } from '@mysten/sui/utils';
|
|
20
|
-
import { EncryptionService } from '../services/EncryptionService';
|
|
21
|
-
import { StorageManager } from '../infrastructure/walrus/StorageManager';
|
|
22
|
-
import { UnifiedMemoryResult } from '../retrieval/MemoryRetrievalService';
|
|
23
|
-
|
|
24
|
-
// Key server configurations from SEAL documentation
|
|
25
|
-
export interface KeyServerConfig {
|
|
26
|
-
name: string;
|
|
27
|
-
mode: 'open' | 'permissioned';
|
|
28
|
-
objectId: string;
|
|
29
|
-
url: string;
|
|
30
|
-
provider: string;
|
|
31
|
-
network: 'testnet' | 'mainnet';
|
|
32
|
-
weight?: number;
|
|
33
|
-
isDefault?: boolean;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export interface DecryptionConfig {
|
|
37
|
-
// Key server configuration
|
|
38
|
-
keyServers?: KeyServerConfig[];
|
|
39
|
-
defaultKeyServerMode?: 'open' | 'permissioned';
|
|
40
|
-
customKeyServerUrl?: string;
|
|
41
|
-
customKeyServerObjectId?: string;
|
|
42
|
-
|
|
43
|
-
// Session management
|
|
44
|
-
sessionKeyTTL?: number; // minutes
|
|
45
|
-
maxSessionKeys?: number;
|
|
46
|
-
autoRefreshSession?: boolean;
|
|
47
|
-
|
|
48
|
-
// Performance options
|
|
49
|
-
enableBatchDecryption?: boolean;
|
|
50
|
-
batchSize?: number;
|
|
51
|
-
maxConcurrentDecryptions?: number;
|
|
52
|
-
decryptionTimeout?: number; // ms
|
|
53
|
-
|
|
54
|
-
// Fallback options
|
|
55
|
-
enableFallback?: boolean;
|
|
56
|
-
maxRetryAttempts?: number;
|
|
57
|
-
retryDelayMs?: number;
|
|
58
|
-
|
|
59
|
-
// Security options
|
|
60
|
-
verifyKeyServers?: boolean;
|
|
61
|
-
enableDecryptionAudit?: boolean;
|
|
62
|
-
requireOwnershipVerification?: boolean;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export interface DecryptionRequest {
|
|
66
|
-
memoryId: string;
|
|
67
|
-
encryptedContent: string;
|
|
68
|
-
contentHash?: string;
|
|
69
|
-
userAddress: string;
|
|
70
|
-
ownerAddress?: string;
|
|
71
|
-
sessionKey?: SessionKey;
|
|
72
|
-
metadata?: Record<string, any>;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export interface DecryptionResult {
|
|
76
|
-
memoryId: string;
|
|
77
|
-
decryptedContent: string;
|
|
78
|
-
contentHash: string;
|
|
79
|
-
isVerified: boolean;
|
|
80
|
-
decryptionTime: number;
|
|
81
|
-
keyServerUsed: string;
|
|
82
|
-
sessionKeyId: string;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export interface BatchDecryptionResult {
|
|
86
|
-
successful: DecryptionResult[];
|
|
87
|
-
failed: Array<{
|
|
88
|
-
memoryId: string;
|
|
89
|
-
error: string;
|
|
90
|
-
retryCount: number;
|
|
91
|
-
}>;
|
|
92
|
-
stats: {
|
|
93
|
-
totalRequests: number;
|
|
94
|
-
successCount: number;
|
|
95
|
-
failureCount: number;
|
|
96
|
-
totalProcessingTime: number;
|
|
97
|
-
averageDecryptionTime: number;
|
|
98
|
-
keyServerPerformance: Record<string, {
|
|
99
|
-
requests: number;
|
|
100
|
-
successes: number;
|
|
101
|
-
averageTime: number;
|
|
102
|
-
}>;
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Memory Decryption Pipeline Service
|
|
108
|
-
*/
|
|
109
|
-
export class MemoryDecryptionPipeline {
|
|
110
|
-
private sealClient: SealClient | null = null;
|
|
111
|
-
private encryptionService: EncryptionService;
|
|
112
|
-
private storageManager: StorageManager;
|
|
113
|
-
private config: DecryptionConfig;
|
|
114
|
-
|
|
115
|
-
// Session key management
|
|
116
|
-
private sessionKeys = new Map<string, SessionKey>();
|
|
117
|
-
private sessionKeyTimestamps = new Map<string, number>();
|
|
118
|
-
|
|
119
|
-
// Decryption cache
|
|
120
|
-
private decryptionCache = new Map<string, { content: string; timestamp: number }>();
|
|
121
|
-
private readonly CACHE_TTL = 30 * 60 * 1000; // 30 minutes
|
|
122
|
-
|
|
123
|
-
// Performance monitoring
|
|
124
|
-
private decryptionStats = {
|
|
125
|
-
totalDecryptions: 0,
|
|
126
|
-
successfulDecryptions: 0,
|
|
127
|
-
failedDecryptions: 0,
|
|
128
|
-
totalDecryptionTime: 0,
|
|
129
|
-
keyServerStats: new Map<string, { requests: number; successes: number; totalTime: number }>()
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
// Official Mysten Labs testnet key servers from documentation
|
|
133
|
-
private static readonly DEFAULT_TESTNET_SERVERS: KeyServerConfig[] = [
|
|
134
|
-
{
|
|
135
|
-
name: 'mysten-testnet-1',
|
|
136
|
-
mode: 'open',
|
|
137
|
-
objectId: '0x73d05d62c18d9374e3ea529e8e0ed6161da1a141a94d3f76ae3fe4e99356db75',
|
|
138
|
-
url: 'https://seal-key-server-testnet-1.mystenlabs.com',
|
|
139
|
-
provider: 'Mysten Labs',
|
|
140
|
-
network: 'testnet',
|
|
141
|
-
weight: 1,
|
|
142
|
-
isDefault: true
|
|
143
|
-
},
|
|
144
|
-
{
|
|
145
|
-
name: 'mysten-testnet-2',
|
|
146
|
-
mode: 'open',
|
|
147
|
-
objectId: '0xf5d14a81a982144ae441cd7d64b09027f116a468bd36e7eca494f750591623c8',
|
|
148
|
-
url: 'https://seal-key-server-testnet-2.mystenlabs.com',
|
|
149
|
-
provider: 'Mysten Labs',
|
|
150
|
-
network: 'testnet',
|
|
151
|
-
weight: 1,
|
|
152
|
-
isDefault: true
|
|
153
|
-
}
|
|
154
|
-
];
|
|
155
|
-
|
|
156
|
-
// Additional verified testnet key servers
|
|
157
|
-
private static readonly VERIFIED_TESTNET_SERVERS: KeyServerConfig[] = [
|
|
158
|
-
{
|
|
159
|
-
name: 'ruby-nodes-testnet',
|
|
160
|
-
mode: 'open',
|
|
161
|
-
objectId: '0x6068c0acb197dddbacd4746a9de7f025b2ed5a5b6c1b1ab44dade4426d141da2',
|
|
162
|
-
url: 'https://seal-testnet.api.rubynodes.io',
|
|
163
|
-
provider: 'Ruby Nodes',
|
|
164
|
-
network: 'testnet',
|
|
165
|
-
weight: 1
|
|
166
|
-
},
|
|
167
|
-
{
|
|
168
|
-
name: 'nodeinfra-testnet',
|
|
169
|
-
mode: 'open',
|
|
170
|
-
objectId: '0x5466b7df5c15b508678d51496ada8afab0d6f70a01c10613123382b1b8131007',
|
|
171
|
-
url: 'https://open-seal-testnet.nodeinfra.com',
|
|
172
|
-
provider: 'NodeInfra',
|
|
173
|
-
network: 'testnet',
|
|
174
|
-
weight: 1
|
|
175
|
-
},
|
|
176
|
-
{
|
|
177
|
-
name: 'studio-mirai-testnet',
|
|
178
|
-
mode: 'open',
|
|
179
|
-
objectId: '0x164ac3d2b3b8694b8181c13f671950004765c23f270321a45fdd04d40cccf0f2',
|
|
180
|
-
url: 'https://open.key-server-testnet.seal.mirai.cloud',
|
|
181
|
-
provider: 'Studio Mirai',
|
|
182
|
-
network: 'testnet',
|
|
183
|
-
weight: 1
|
|
184
|
-
},
|
|
185
|
-
{
|
|
186
|
-
name: 'overclock-testnet',
|
|
187
|
-
mode: 'open',
|
|
188
|
-
objectId: '0x9c949e53c36ab7a9c484ed9e8b43267a77d4b8d70e79aa6b39042e3d4c434105',
|
|
189
|
-
url: 'https://seal-testnet-open.overclock.run',
|
|
190
|
-
provider: 'Overclock',
|
|
191
|
-
network: 'testnet',
|
|
192
|
-
weight: 1
|
|
193
|
-
},
|
|
194
|
-
{
|
|
195
|
-
name: 'h2o-nodes-testnet',
|
|
196
|
-
mode: 'open',
|
|
197
|
-
objectId: '0x39cef09b24b667bc6ed54f7159d82352fe2d5dd97ca9a5beaa1d21aa774f25a2',
|
|
198
|
-
url: 'https://seal-open.sui-testnet.h2o-nodes.com',
|
|
199
|
-
provider: 'H2O Nodes',
|
|
200
|
-
network: 'testnet',
|
|
201
|
-
weight: 1
|
|
202
|
-
},
|
|
203
|
-
{
|
|
204
|
-
name: 'triton-one-testnet',
|
|
205
|
-
mode: 'open',
|
|
206
|
-
objectId: '0x4cded1abeb52a22b6becb42a91d3686a4c901cf52eee16234214d0b5b2da4c46',
|
|
207
|
-
url: 'https://seal.testnet.sui.rpcpool.com',
|
|
208
|
-
provider: 'Triton One',
|
|
209
|
-
network: 'testnet',
|
|
210
|
-
weight: 1
|
|
211
|
-
}
|
|
212
|
-
];
|
|
213
|
-
|
|
214
|
-
constructor(
|
|
215
|
-
encryptionService: EncryptionService,
|
|
216
|
-
storageManager: StorageManager,
|
|
217
|
-
config?: Partial<DecryptionConfig>
|
|
218
|
-
) {
|
|
219
|
-
this.encryptionService = encryptionService;
|
|
220
|
-
this.storageManager = storageManager;
|
|
221
|
-
this.config = this.mergeWithDefaults(config || {});
|
|
222
|
-
this.initializeDecryptionPipeline();
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
// ==================== INITIALIZATION ====================
|
|
226
|
-
|
|
227
|
-
/**
|
|
228
|
-
* Merge user config with environment variables and defaults
|
|
229
|
-
*/
|
|
230
|
-
private mergeWithDefaults(userConfig: Partial<DecryptionConfig>): DecryptionConfig {
|
|
231
|
-
// Load from environment variables
|
|
232
|
-
const envConfig: Partial<DecryptionConfig> = {
|
|
233
|
-
customKeyServerUrl: process.env.SEAL_KEY_SERVER_URL,
|
|
234
|
-
customKeyServerObjectId: process.env.SEAL_KEY_SERVER_OBJECT_ID,
|
|
235
|
-
sessionKeyTTL: process.env.SEAL_SESSION_TTL ? parseInt(process.env.SEAL_SESSION_TTL) : undefined,
|
|
236
|
-
enableBatchDecryption: process.env.SEAL_ENABLE_BATCH === 'true',
|
|
237
|
-
batchSize: process.env.SEAL_BATCH_SIZE ? parseInt(process.env.SEAL_BATCH_SIZE) : undefined,
|
|
238
|
-
decryptionTimeout: process.env.SEAL_DECRYPTION_TIMEOUT ? parseInt(process.env.SEAL_DECRYPTION_TIMEOUT) : undefined,
|
|
239
|
-
verifyKeyServers: process.env.SEAL_VERIFY_SERVERS !== 'false', // Default true
|
|
240
|
-
enableDecryptionAudit: process.env.SEAL_ENABLE_AUDIT === 'true'
|
|
241
|
-
};
|
|
242
|
-
|
|
243
|
-
// Default configuration
|
|
244
|
-
const defaults: DecryptionConfig = {
|
|
245
|
-
keyServers: this.getDefaultKeyServers(),
|
|
246
|
-
defaultKeyServerMode: 'open',
|
|
247
|
-
sessionKeyTTL: 60, // 1 hour
|
|
248
|
-
maxSessionKeys: 100,
|
|
249
|
-
autoRefreshSession: true,
|
|
250
|
-
enableBatchDecryption: true,
|
|
251
|
-
batchSize: 10,
|
|
252
|
-
maxConcurrentDecryptions: 5,
|
|
253
|
-
decryptionTimeout: 30000, // 30 seconds
|
|
254
|
-
enableFallback: true,
|
|
255
|
-
maxRetryAttempts: 3,
|
|
256
|
-
retryDelayMs: 1000,
|
|
257
|
-
verifyKeyServers: process.env.NODE_ENV === 'production',
|
|
258
|
-
enableDecryptionAudit: false,
|
|
259
|
-
requireOwnershipVerification: true
|
|
260
|
-
};
|
|
261
|
-
|
|
262
|
-
return { ...defaults, ...envConfig, ...userConfig };
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
/**
|
|
266
|
-
* Get default key servers based on environment
|
|
267
|
-
*/
|
|
268
|
-
private getDefaultKeyServers(): KeyServerConfig[] {
|
|
269
|
-
const network = process.env.SUI_NETWORK || 'testnet';
|
|
270
|
-
|
|
271
|
-
if (network === 'testnet') {
|
|
272
|
-
// Use official Mysten Labs servers as primary, with fallbacks
|
|
273
|
-
return [
|
|
274
|
-
...MemoryDecryptionPipeline.DEFAULT_TESTNET_SERVERS,
|
|
275
|
-
...MemoryDecryptionPipeline.VERIFIED_TESTNET_SERVERS.slice(0, 2) // Add 2 fallback servers
|
|
276
|
-
];
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
// For mainnet, would need to configure based on chosen providers
|
|
280
|
-
return MemoryDecryptionPipeline.DEFAULT_TESTNET_SERVERS;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
/**
|
|
284
|
-
* Initialize the decryption pipeline
|
|
285
|
-
*/
|
|
286
|
-
private async initializeDecryptionPipeline(): Promise<void> {
|
|
287
|
-
try {
|
|
288
|
-
console.log('๐ Initializing SEAL Memory Decryption Pipeline...');
|
|
289
|
-
|
|
290
|
-
// Determine key servers to use
|
|
291
|
-
let keyServers = this.config.keyServers || this.getDefaultKeyServers();
|
|
292
|
-
|
|
293
|
-
// Add custom key server if configured
|
|
294
|
-
if (this.config.customKeyServerUrl && this.config.customKeyServerObjectId) {
|
|
295
|
-
keyServers = [{
|
|
296
|
-
name: 'custom-server',
|
|
297
|
-
mode: this.config.defaultKeyServerMode || 'open',
|
|
298
|
-
objectId: this.config.customKeyServerObjectId,
|
|
299
|
-
url: this.config.customKeyServerUrl,
|
|
300
|
-
provider: 'Custom',
|
|
301
|
-
network: 'custom' as any,
|
|
302
|
-
weight: 2, // Higher weight for custom server
|
|
303
|
-
isDefault: false
|
|
304
|
-
}, ...keyServers];
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
// Initialize SEAL client
|
|
308
|
-
this.sealClient = new SealClient({
|
|
309
|
-
suiClient: (this.encryptionService as any).suiClient,
|
|
310
|
-
serverConfigs: keyServers.map(server => ({
|
|
311
|
-
objectId: server.objectId,
|
|
312
|
-
weight: server.weight || 1
|
|
313
|
-
})),
|
|
314
|
-
verifyKeyServers: this.config.verifyKeyServers || false
|
|
315
|
-
});
|
|
316
|
-
|
|
317
|
-
console.log(`โ
SEAL client initialized with ${keyServers.length} key servers`);
|
|
318
|
-
console.log('๐ก Key servers:', keyServers.map(s => `${s.name} (${s.provider})`).join(', '));
|
|
319
|
-
|
|
320
|
-
// Start session key cleanup interval
|
|
321
|
-
this.startSessionKeyCleanup();
|
|
322
|
-
|
|
323
|
-
} catch (error) {
|
|
324
|
-
console.error('โ Failed to initialize decryption pipeline:', error);
|
|
325
|
-
throw new Error(`Decryption pipeline initialization failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
// ==================== CORE DECRYPTION METHODS ====================
|
|
330
|
-
|
|
331
|
-
/**
|
|
332
|
-
* Decrypt a single memory with full pipeline support
|
|
333
|
-
*/
|
|
334
|
-
async decryptMemory(request: DecryptionRequest): Promise<DecryptionResult> {
|
|
335
|
-
const startTime = Date.now();
|
|
336
|
-
|
|
337
|
-
try {
|
|
338
|
-
// Check cache first
|
|
339
|
-
const cacheKey = `${request.memoryId}:${request.userAddress}`;
|
|
340
|
-
const cached = this.getFromCache(cacheKey);
|
|
341
|
-
if (cached) {
|
|
342
|
-
console.log(`๐ฏ Cache hit for memory ${request.memoryId}`);
|
|
343
|
-
return {
|
|
344
|
-
memoryId: request.memoryId,
|
|
345
|
-
decryptedContent: cached,
|
|
346
|
-
contentHash: request.contentHash || '',
|
|
347
|
-
isVerified: true,
|
|
348
|
-
decryptionTime: Date.now() - startTime,
|
|
349
|
-
keyServerUsed: 'cache',
|
|
350
|
-
sessionKeyId: 'cached'
|
|
351
|
-
};
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
// Verify ownership if required
|
|
355
|
-
if (this.config.requireOwnershipVerification && request.ownerAddress) {
|
|
356
|
-
const hasAccess = await this.verifyAccess(request.userAddress, request.memoryId, request.ownerAddress);
|
|
357
|
-
if (!hasAccess) {
|
|
358
|
-
throw new Error(`Access denied: User ${request.userAddress} cannot decrypt memory ${request.memoryId}`);
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
// Get or create session key
|
|
363
|
-
const sessionKey = request.sessionKey || await this.getOrCreateSessionKey(request.userAddress);
|
|
364
|
-
|
|
365
|
-
// Perform decryption
|
|
366
|
-
const decryptedBytes = await this.performDecryption(request, sessionKey);
|
|
367
|
-
const decryptedContent = new TextDecoder().decode(decryptedBytes);
|
|
368
|
-
|
|
369
|
-
// Verify content integrity if hash provided
|
|
370
|
-
let isVerified = true;
|
|
371
|
-
if (request.contentHash) {
|
|
372
|
-
isVerified = await this.verifyContentIntegrity(decryptedBytes, request.contentHash);
|
|
373
|
-
if (!isVerified) {
|
|
374
|
-
console.warn(`โ ๏ธ Content integrity check failed for memory ${request.memoryId}`);
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
// Cache the result
|
|
379
|
-
this.addToCache(cacheKey, decryptedContent);
|
|
380
|
-
|
|
381
|
-
// Update stats
|
|
382
|
-
this.updateDecryptionStats(true, Date.now() - startTime);
|
|
383
|
-
|
|
384
|
-
const result: DecryptionResult = {
|
|
385
|
-
memoryId: request.memoryId,
|
|
386
|
-
decryptedContent,
|
|
387
|
-
contentHash: request.contentHash || '',
|
|
388
|
-
isVerified,
|
|
389
|
-
decryptionTime: Date.now() - startTime,
|
|
390
|
-
keyServerUsed: 'seal-client', // Would track specific server in production
|
|
391
|
-
sessionKeyId: await this.getSessionKeyId(sessionKey)
|
|
392
|
-
};
|
|
393
|
-
|
|
394
|
-
console.log(`โ
Successfully decrypted memory ${request.memoryId} in ${result.decryptionTime}ms`);
|
|
395
|
-
return result;
|
|
396
|
-
|
|
397
|
-
} catch (error) {
|
|
398
|
-
this.updateDecryptionStats(false, Date.now() - startTime);
|
|
399
|
-
const errorMsg = `Decryption failed for memory ${request.memoryId}: ${error instanceof Error ? error.message : 'Unknown error'}`;
|
|
400
|
-
console.error('โ', errorMsg);
|
|
401
|
-
throw new Error(errorMsg);
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
/**
|
|
406
|
-
* Decrypt multiple memories in batch for performance
|
|
407
|
-
*/
|
|
408
|
-
async decryptMemoryBatch(requests: DecryptionRequest[]): Promise<BatchDecryptionResult> {
|
|
409
|
-
console.log(`๐ Starting batch decryption of ${requests.length} memories`);
|
|
410
|
-
const startTime = Date.now();
|
|
411
|
-
|
|
412
|
-
const successful: DecryptionResult[] = [];
|
|
413
|
-
const failed: Array<{ memoryId: string; error: string; retryCount: number }> = [];
|
|
414
|
-
|
|
415
|
-
// Group requests into batches
|
|
416
|
-
const batchSize = this.config.batchSize || 10;
|
|
417
|
-
const batches = this.chunkArray(requests, batchSize);
|
|
418
|
-
|
|
419
|
-
for (const batch of batches) {
|
|
420
|
-
// Process batch with concurrency limit
|
|
421
|
-
const batchPromises = batch.map(async (request) => {
|
|
422
|
-
try {
|
|
423
|
-
const result = await this.decryptMemory(request);
|
|
424
|
-
successful.push(result);
|
|
425
|
-
} catch (error) {
|
|
426
|
-
failed.push({
|
|
427
|
-
memoryId: request.memoryId,
|
|
428
|
-
error: error instanceof Error ? error.message : 'Unknown error',
|
|
429
|
-
retryCount: 0
|
|
430
|
-
});
|
|
431
|
-
}
|
|
432
|
-
});
|
|
433
|
-
|
|
434
|
-
// Wait for batch to complete
|
|
435
|
-
await Promise.allSettled(batchPromises);
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
// Retry failed decryptions if enabled
|
|
439
|
-
if (this.config.enableFallback && this.config.maxRetryAttempts && this.config.maxRetryAttempts > 0) {
|
|
440
|
-
await this.retryFailedDecryptions(requests, failed, successful);
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
const totalProcessingTime = Date.now() - startTime;
|
|
444
|
-
const stats = this.generateBatchStats(requests.length, successful.length, failed.length, totalProcessingTime);
|
|
445
|
-
|
|
446
|
-
console.log(`โ
Batch decryption completed: ${successful.length}/${requests.length} successful in ${totalProcessingTime}ms`);
|
|
447
|
-
|
|
448
|
-
return {
|
|
449
|
-
successful,
|
|
450
|
-
failed,
|
|
451
|
-
stats
|
|
452
|
-
};
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
// ==================== SESSION KEY MANAGEMENT ====================
|
|
456
|
-
|
|
457
|
-
/**
|
|
458
|
-
* Get or create session key for user
|
|
459
|
-
*/
|
|
460
|
-
async getOrCreateSessionKey(userAddress: string): Promise<SessionKey> {
|
|
461
|
-
// Check if we have a valid cached session key
|
|
462
|
-
const existing = this.sessionKeys.get(userAddress);
|
|
463
|
-
const timestamp = this.sessionKeyTimestamps.get(userAddress);
|
|
464
|
-
|
|
465
|
-
if (existing && timestamp) {
|
|
466
|
-
const age = Date.now() - timestamp;
|
|
467
|
-
const ttl = (this.config.sessionKeyTTL || 60) * 60 * 1000; // Convert to ms
|
|
468
|
-
|
|
469
|
-
if (age < ttl) {
|
|
470
|
-
return existing;
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
// Create new session key
|
|
475
|
-
console.log(`๐ Creating new session key for user ${userAddress}`);
|
|
476
|
-
const sessionKey = await this.encryptionService.createSessionKey(userAddress);
|
|
477
|
-
|
|
478
|
-
// Cache with timestamp
|
|
479
|
-
this.sessionKeys.set(userAddress, sessionKey);
|
|
480
|
-
this.sessionKeyTimestamps.set(userAddress, Date.now());
|
|
481
|
-
|
|
482
|
-
// Cleanup old keys if we exceed limit
|
|
483
|
-
if (this.sessionKeys.size > (this.config.maxSessionKeys || 100)) {
|
|
484
|
-
this.cleanupOldestSessionKeys();
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
return sessionKey;
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
/**
|
|
491
|
-
* Cleanup expired session keys
|
|
492
|
-
*/
|
|
493
|
-
private startSessionKeyCleanup(): void {
|
|
494
|
-
setInterval(() => {
|
|
495
|
-
const now = Date.now();
|
|
496
|
-
const ttl = (this.config.sessionKeyTTL || 60) * 60 * 1000;
|
|
497
|
-
|
|
498
|
-
for (const [userAddress, timestamp] of this.sessionKeyTimestamps.entries()) {
|
|
499
|
-
if (now - timestamp > ttl) {
|
|
500
|
-
this.sessionKeys.delete(userAddress);
|
|
501
|
-
this.sessionKeyTimestamps.delete(userAddress);
|
|
502
|
-
console.log(`๐งน Cleaned up expired session key for ${userAddress}`);
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
}, 5 * 60 * 1000); // Check every 5 minutes
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
/**
|
|
509
|
-
* Cleanup oldest session keys when limit exceeded
|
|
510
|
-
*/
|
|
511
|
-
private cleanupOldestSessionKeys(): void {
|
|
512
|
-
const entries = Array.from(this.sessionKeyTimestamps.entries())
|
|
513
|
-
.sort((a, b) => a[1] - b[1]); // Sort by timestamp
|
|
514
|
-
|
|
515
|
-
// Remove oldest 25%
|
|
516
|
-
const toRemove = Math.floor(entries.length * 0.25);
|
|
517
|
-
for (let i = 0; i < toRemove; i++) {
|
|
518
|
-
const [userAddress] = entries[i];
|
|
519
|
-
this.sessionKeys.delete(userAddress);
|
|
520
|
-
this.sessionKeyTimestamps.delete(userAddress);
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
console.log(`๐งน Cleaned up ${toRemove} oldest session keys`);
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
// ==================== DECRYPTION UTILITIES ====================
|
|
527
|
-
|
|
528
|
-
/**
|
|
529
|
-
* Perform the actual decryption using SEAL
|
|
530
|
-
*/
|
|
531
|
-
private async performDecryption(request: DecryptionRequest, sessionKey: SessionKey): Promise<Uint8Array> {
|
|
532
|
-
if (!this.sealClient) {
|
|
533
|
-
throw new Error('SEAL client not initialized');
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
// Convert base64 encrypted content to bytes
|
|
537
|
-
const encryptedBytes = this.base64ToUint8Array(request.encryptedContent);
|
|
538
|
-
|
|
539
|
-
// Build access transaction
|
|
540
|
-
const accessTx = await this.encryptionService.buildAccessTransaction(request.userAddress, 'read');
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
const
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
successful
|
|
610
|
-
|
|
611
|
-
failed.
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
failure.
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
const
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
this.decryptionStats.
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
1
|
+
/**
|
|
2
|
+
* MemoryDecryptionPipeline - Seamless SEAL-based Memory Decryption
|
|
3
|
+
*
|
|
4
|
+
* Provides comprehensive decryption capabilities for encrypted memories using
|
|
5
|
+
* Mysten's SEAL SDK with official testnet key servers and configurable infrastructure.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - ๐ Seamless SEAL decryption integration
|
|
9
|
+
* - ๐ Automatic key server configuration (testnet/mainnet)
|
|
10
|
+
* - โก Batch decryption optimization
|
|
11
|
+
* - ๐ก๏ธ Secure session key management
|
|
12
|
+
* - ๐ Automatic retry and fallback mechanisms
|
|
13
|
+
* - ๐ Decryption analytics and monitoring
|
|
14
|
+
* - ๐ Environment-based configuration
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { SealClient, SessionKey } from '@mysten/seal';
|
|
18
|
+
import { Transaction } from '@mysten/sui/transactions';
|
|
19
|
+
import { fromHex, toHex } from '@mysten/sui/utils';
|
|
20
|
+
import { EncryptionService } from '../services/EncryptionService';
|
|
21
|
+
import { StorageManager } from '../infrastructure/walrus/StorageManager';
|
|
22
|
+
import { UnifiedMemoryResult } from '../retrieval/MemoryRetrievalService';
|
|
23
|
+
|
|
24
|
+
// Key server configurations from SEAL documentation
|
|
25
|
+
export interface KeyServerConfig {
|
|
26
|
+
name: string;
|
|
27
|
+
mode: 'open' | 'permissioned';
|
|
28
|
+
objectId: string;
|
|
29
|
+
url: string;
|
|
30
|
+
provider: string;
|
|
31
|
+
network: 'testnet' | 'mainnet';
|
|
32
|
+
weight?: number;
|
|
33
|
+
isDefault?: boolean;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface DecryptionConfig {
|
|
37
|
+
// Key server configuration
|
|
38
|
+
keyServers?: KeyServerConfig[];
|
|
39
|
+
defaultKeyServerMode?: 'open' | 'permissioned';
|
|
40
|
+
customKeyServerUrl?: string;
|
|
41
|
+
customKeyServerObjectId?: string;
|
|
42
|
+
|
|
43
|
+
// Session management
|
|
44
|
+
sessionKeyTTL?: number; // minutes
|
|
45
|
+
maxSessionKeys?: number;
|
|
46
|
+
autoRefreshSession?: boolean;
|
|
47
|
+
|
|
48
|
+
// Performance options
|
|
49
|
+
enableBatchDecryption?: boolean;
|
|
50
|
+
batchSize?: number;
|
|
51
|
+
maxConcurrentDecryptions?: number;
|
|
52
|
+
decryptionTimeout?: number; // ms
|
|
53
|
+
|
|
54
|
+
// Fallback options
|
|
55
|
+
enableFallback?: boolean;
|
|
56
|
+
maxRetryAttempts?: number;
|
|
57
|
+
retryDelayMs?: number;
|
|
58
|
+
|
|
59
|
+
// Security options
|
|
60
|
+
verifyKeyServers?: boolean;
|
|
61
|
+
enableDecryptionAudit?: boolean;
|
|
62
|
+
requireOwnershipVerification?: boolean;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface DecryptionRequest {
|
|
66
|
+
memoryId: string;
|
|
67
|
+
encryptedContent: string;
|
|
68
|
+
contentHash?: string;
|
|
69
|
+
userAddress: string;
|
|
70
|
+
ownerAddress?: string;
|
|
71
|
+
sessionKey?: SessionKey;
|
|
72
|
+
metadata?: Record<string, any>;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface DecryptionResult {
|
|
76
|
+
memoryId: string;
|
|
77
|
+
decryptedContent: string;
|
|
78
|
+
contentHash: string;
|
|
79
|
+
isVerified: boolean;
|
|
80
|
+
decryptionTime: number;
|
|
81
|
+
keyServerUsed: string;
|
|
82
|
+
sessionKeyId: string;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export interface BatchDecryptionResult {
|
|
86
|
+
successful: DecryptionResult[];
|
|
87
|
+
failed: Array<{
|
|
88
|
+
memoryId: string;
|
|
89
|
+
error: string;
|
|
90
|
+
retryCount: number;
|
|
91
|
+
}>;
|
|
92
|
+
stats: {
|
|
93
|
+
totalRequests: number;
|
|
94
|
+
successCount: number;
|
|
95
|
+
failureCount: number;
|
|
96
|
+
totalProcessingTime: number;
|
|
97
|
+
averageDecryptionTime: number;
|
|
98
|
+
keyServerPerformance: Record<string, {
|
|
99
|
+
requests: number;
|
|
100
|
+
successes: number;
|
|
101
|
+
averageTime: number;
|
|
102
|
+
}>;
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Memory Decryption Pipeline Service
|
|
108
|
+
*/
|
|
109
|
+
export class MemoryDecryptionPipeline {
|
|
110
|
+
private sealClient: SealClient | null = null;
|
|
111
|
+
private encryptionService: EncryptionService;
|
|
112
|
+
private storageManager: StorageManager;
|
|
113
|
+
private config: DecryptionConfig;
|
|
114
|
+
|
|
115
|
+
// Session key management
|
|
116
|
+
private sessionKeys = new Map<string, SessionKey>();
|
|
117
|
+
private sessionKeyTimestamps = new Map<string, number>();
|
|
118
|
+
|
|
119
|
+
// Decryption cache
|
|
120
|
+
private decryptionCache = new Map<string, { content: string; timestamp: number }>();
|
|
121
|
+
private readonly CACHE_TTL = 30 * 60 * 1000; // 30 minutes
|
|
122
|
+
|
|
123
|
+
// Performance monitoring
|
|
124
|
+
private decryptionStats = {
|
|
125
|
+
totalDecryptions: 0,
|
|
126
|
+
successfulDecryptions: 0,
|
|
127
|
+
failedDecryptions: 0,
|
|
128
|
+
totalDecryptionTime: 0,
|
|
129
|
+
keyServerStats: new Map<string, { requests: number; successes: number; totalTime: number }>()
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
// Official Mysten Labs testnet key servers from documentation
|
|
133
|
+
private static readonly DEFAULT_TESTNET_SERVERS: KeyServerConfig[] = [
|
|
134
|
+
{
|
|
135
|
+
name: 'mysten-testnet-1',
|
|
136
|
+
mode: 'open',
|
|
137
|
+
objectId: '0x73d05d62c18d9374e3ea529e8e0ed6161da1a141a94d3f76ae3fe4e99356db75',
|
|
138
|
+
url: 'https://seal-key-server-testnet-1.mystenlabs.com',
|
|
139
|
+
provider: 'Mysten Labs',
|
|
140
|
+
network: 'testnet',
|
|
141
|
+
weight: 1,
|
|
142
|
+
isDefault: true
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
name: 'mysten-testnet-2',
|
|
146
|
+
mode: 'open',
|
|
147
|
+
objectId: '0xf5d14a81a982144ae441cd7d64b09027f116a468bd36e7eca494f750591623c8',
|
|
148
|
+
url: 'https://seal-key-server-testnet-2.mystenlabs.com',
|
|
149
|
+
provider: 'Mysten Labs',
|
|
150
|
+
network: 'testnet',
|
|
151
|
+
weight: 1,
|
|
152
|
+
isDefault: true
|
|
153
|
+
}
|
|
154
|
+
];
|
|
155
|
+
|
|
156
|
+
// Additional verified testnet key servers
|
|
157
|
+
private static readonly VERIFIED_TESTNET_SERVERS: KeyServerConfig[] = [
|
|
158
|
+
{
|
|
159
|
+
name: 'ruby-nodes-testnet',
|
|
160
|
+
mode: 'open',
|
|
161
|
+
objectId: '0x6068c0acb197dddbacd4746a9de7f025b2ed5a5b6c1b1ab44dade4426d141da2',
|
|
162
|
+
url: 'https://seal-testnet.api.rubynodes.io',
|
|
163
|
+
provider: 'Ruby Nodes',
|
|
164
|
+
network: 'testnet',
|
|
165
|
+
weight: 1
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
name: 'nodeinfra-testnet',
|
|
169
|
+
mode: 'open',
|
|
170
|
+
objectId: '0x5466b7df5c15b508678d51496ada8afab0d6f70a01c10613123382b1b8131007',
|
|
171
|
+
url: 'https://open-seal-testnet.nodeinfra.com',
|
|
172
|
+
provider: 'NodeInfra',
|
|
173
|
+
network: 'testnet',
|
|
174
|
+
weight: 1
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
name: 'studio-mirai-testnet',
|
|
178
|
+
mode: 'open',
|
|
179
|
+
objectId: '0x164ac3d2b3b8694b8181c13f671950004765c23f270321a45fdd04d40cccf0f2',
|
|
180
|
+
url: 'https://open.key-server-testnet.seal.mirai.cloud',
|
|
181
|
+
provider: 'Studio Mirai',
|
|
182
|
+
network: 'testnet',
|
|
183
|
+
weight: 1
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
name: 'overclock-testnet',
|
|
187
|
+
mode: 'open',
|
|
188
|
+
objectId: '0x9c949e53c36ab7a9c484ed9e8b43267a77d4b8d70e79aa6b39042e3d4c434105',
|
|
189
|
+
url: 'https://seal-testnet-open.overclock.run',
|
|
190
|
+
provider: 'Overclock',
|
|
191
|
+
network: 'testnet',
|
|
192
|
+
weight: 1
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
name: 'h2o-nodes-testnet',
|
|
196
|
+
mode: 'open',
|
|
197
|
+
objectId: '0x39cef09b24b667bc6ed54f7159d82352fe2d5dd97ca9a5beaa1d21aa774f25a2',
|
|
198
|
+
url: 'https://seal-open.sui-testnet.h2o-nodes.com',
|
|
199
|
+
provider: 'H2O Nodes',
|
|
200
|
+
network: 'testnet',
|
|
201
|
+
weight: 1
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
name: 'triton-one-testnet',
|
|
205
|
+
mode: 'open',
|
|
206
|
+
objectId: '0x4cded1abeb52a22b6becb42a91d3686a4c901cf52eee16234214d0b5b2da4c46',
|
|
207
|
+
url: 'https://seal.testnet.sui.rpcpool.com',
|
|
208
|
+
provider: 'Triton One',
|
|
209
|
+
network: 'testnet',
|
|
210
|
+
weight: 1
|
|
211
|
+
}
|
|
212
|
+
];
|
|
213
|
+
|
|
214
|
+
constructor(
|
|
215
|
+
encryptionService: EncryptionService,
|
|
216
|
+
storageManager: StorageManager,
|
|
217
|
+
config?: Partial<DecryptionConfig>
|
|
218
|
+
) {
|
|
219
|
+
this.encryptionService = encryptionService;
|
|
220
|
+
this.storageManager = storageManager;
|
|
221
|
+
this.config = this.mergeWithDefaults(config || {});
|
|
222
|
+
this.initializeDecryptionPipeline();
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// ==================== INITIALIZATION ====================
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Merge user config with environment variables and defaults
|
|
229
|
+
*/
|
|
230
|
+
private mergeWithDefaults(userConfig: Partial<DecryptionConfig>): DecryptionConfig {
|
|
231
|
+
// Load from environment variables
|
|
232
|
+
const envConfig: Partial<DecryptionConfig> = {
|
|
233
|
+
customKeyServerUrl: process.env.SEAL_KEY_SERVER_URL,
|
|
234
|
+
customKeyServerObjectId: process.env.SEAL_KEY_SERVER_OBJECT_ID,
|
|
235
|
+
sessionKeyTTL: process.env.SEAL_SESSION_TTL ? parseInt(process.env.SEAL_SESSION_TTL) : undefined,
|
|
236
|
+
enableBatchDecryption: process.env.SEAL_ENABLE_BATCH === 'true',
|
|
237
|
+
batchSize: process.env.SEAL_BATCH_SIZE ? parseInt(process.env.SEAL_BATCH_SIZE) : undefined,
|
|
238
|
+
decryptionTimeout: process.env.SEAL_DECRYPTION_TIMEOUT ? parseInt(process.env.SEAL_DECRYPTION_TIMEOUT) : undefined,
|
|
239
|
+
verifyKeyServers: process.env.SEAL_VERIFY_SERVERS !== 'false', // Default true
|
|
240
|
+
enableDecryptionAudit: process.env.SEAL_ENABLE_AUDIT === 'true'
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
// Default configuration
|
|
244
|
+
const defaults: DecryptionConfig = {
|
|
245
|
+
keyServers: this.getDefaultKeyServers(),
|
|
246
|
+
defaultKeyServerMode: 'open',
|
|
247
|
+
sessionKeyTTL: 60, // 1 hour
|
|
248
|
+
maxSessionKeys: 100,
|
|
249
|
+
autoRefreshSession: true,
|
|
250
|
+
enableBatchDecryption: true,
|
|
251
|
+
batchSize: 10,
|
|
252
|
+
maxConcurrentDecryptions: 5,
|
|
253
|
+
decryptionTimeout: 30000, // 30 seconds
|
|
254
|
+
enableFallback: true,
|
|
255
|
+
maxRetryAttempts: 3,
|
|
256
|
+
retryDelayMs: 1000,
|
|
257
|
+
verifyKeyServers: process.env.NODE_ENV === 'production',
|
|
258
|
+
enableDecryptionAudit: false,
|
|
259
|
+
requireOwnershipVerification: true
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
return { ...defaults, ...envConfig, ...userConfig };
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Get default key servers based on environment
|
|
267
|
+
*/
|
|
268
|
+
private getDefaultKeyServers(): KeyServerConfig[] {
|
|
269
|
+
const network = process.env.SUI_NETWORK || 'testnet';
|
|
270
|
+
|
|
271
|
+
if (network === 'testnet') {
|
|
272
|
+
// Use official Mysten Labs servers as primary, with fallbacks
|
|
273
|
+
return [
|
|
274
|
+
...MemoryDecryptionPipeline.DEFAULT_TESTNET_SERVERS,
|
|
275
|
+
...MemoryDecryptionPipeline.VERIFIED_TESTNET_SERVERS.slice(0, 2) // Add 2 fallback servers
|
|
276
|
+
];
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// For mainnet, would need to configure based on chosen providers
|
|
280
|
+
return MemoryDecryptionPipeline.DEFAULT_TESTNET_SERVERS;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Initialize the decryption pipeline
|
|
285
|
+
*/
|
|
286
|
+
private async initializeDecryptionPipeline(): Promise<void> {
|
|
287
|
+
try {
|
|
288
|
+
console.log('๐ Initializing SEAL Memory Decryption Pipeline...');
|
|
289
|
+
|
|
290
|
+
// Determine key servers to use
|
|
291
|
+
let keyServers = this.config.keyServers || this.getDefaultKeyServers();
|
|
292
|
+
|
|
293
|
+
// Add custom key server if configured
|
|
294
|
+
if (this.config.customKeyServerUrl && this.config.customKeyServerObjectId) {
|
|
295
|
+
keyServers = [{
|
|
296
|
+
name: 'custom-server',
|
|
297
|
+
mode: this.config.defaultKeyServerMode || 'open',
|
|
298
|
+
objectId: this.config.customKeyServerObjectId,
|
|
299
|
+
url: this.config.customKeyServerUrl,
|
|
300
|
+
provider: 'Custom',
|
|
301
|
+
network: 'custom' as any,
|
|
302
|
+
weight: 2, // Higher weight for custom server
|
|
303
|
+
isDefault: false
|
|
304
|
+
}, ...keyServers];
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Initialize SEAL client
|
|
308
|
+
this.sealClient = new SealClient({
|
|
309
|
+
suiClient: (this.encryptionService as any).suiClient,
|
|
310
|
+
serverConfigs: keyServers.map(server => ({
|
|
311
|
+
objectId: server.objectId,
|
|
312
|
+
weight: server.weight || 1
|
|
313
|
+
})),
|
|
314
|
+
verifyKeyServers: this.config.verifyKeyServers || false
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
console.log(`โ
SEAL client initialized with ${keyServers.length} key servers`);
|
|
318
|
+
console.log('๐ก Key servers:', keyServers.map(s => `${s.name} (${s.provider})`).join(', '));
|
|
319
|
+
|
|
320
|
+
// Start session key cleanup interval
|
|
321
|
+
this.startSessionKeyCleanup();
|
|
322
|
+
|
|
323
|
+
} catch (error) {
|
|
324
|
+
console.error('โ Failed to initialize decryption pipeline:', error);
|
|
325
|
+
throw new Error(`Decryption pipeline initialization failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// ==================== CORE DECRYPTION METHODS ====================
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Decrypt a single memory with full pipeline support
|
|
333
|
+
*/
|
|
334
|
+
async decryptMemory(request: DecryptionRequest): Promise<DecryptionResult> {
|
|
335
|
+
const startTime = Date.now();
|
|
336
|
+
|
|
337
|
+
try {
|
|
338
|
+
// Check cache first
|
|
339
|
+
const cacheKey = `${request.memoryId}:${request.userAddress}`;
|
|
340
|
+
const cached = this.getFromCache(cacheKey);
|
|
341
|
+
if (cached) {
|
|
342
|
+
console.log(`๐ฏ Cache hit for memory ${request.memoryId}`);
|
|
343
|
+
return {
|
|
344
|
+
memoryId: request.memoryId,
|
|
345
|
+
decryptedContent: cached,
|
|
346
|
+
contentHash: request.contentHash || '',
|
|
347
|
+
isVerified: true,
|
|
348
|
+
decryptionTime: Date.now() - startTime,
|
|
349
|
+
keyServerUsed: 'cache',
|
|
350
|
+
sessionKeyId: 'cached'
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// Verify ownership if required
|
|
355
|
+
if (this.config.requireOwnershipVerification && request.ownerAddress) {
|
|
356
|
+
const hasAccess = await this.verifyAccess(request.userAddress, request.memoryId, request.ownerAddress);
|
|
357
|
+
if (!hasAccess) {
|
|
358
|
+
throw new Error(`Access denied: User ${request.userAddress} cannot decrypt memory ${request.memoryId}`);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// Get or create session key
|
|
363
|
+
const sessionKey = request.sessionKey || await this.getOrCreateSessionKey(request.userAddress);
|
|
364
|
+
|
|
365
|
+
// Perform decryption
|
|
366
|
+
const decryptedBytes = await this.performDecryption(request, sessionKey);
|
|
367
|
+
const decryptedContent = new TextDecoder().decode(decryptedBytes);
|
|
368
|
+
|
|
369
|
+
// Verify content integrity if hash provided
|
|
370
|
+
let isVerified = true;
|
|
371
|
+
if (request.contentHash) {
|
|
372
|
+
isVerified = await this.verifyContentIntegrity(decryptedBytes, request.contentHash);
|
|
373
|
+
if (!isVerified) {
|
|
374
|
+
console.warn(`โ ๏ธ Content integrity check failed for memory ${request.memoryId}`);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// Cache the result
|
|
379
|
+
this.addToCache(cacheKey, decryptedContent);
|
|
380
|
+
|
|
381
|
+
// Update stats
|
|
382
|
+
this.updateDecryptionStats(true, Date.now() - startTime);
|
|
383
|
+
|
|
384
|
+
const result: DecryptionResult = {
|
|
385
|
+
memoryId: request.memoryId,
|
|
386
|
+
decryptedContent,
|
|
387
|
+
contentHash: request.contentHash || '',
|
|
388
|
+
isVerified,
|
|
389
|
+
decryptionTime: Date.now() - startTime,
|
|
390
|
+
keyServerUsed: 'seal-client', // Would track specific server in production
|
|
391
|
+
sessionKeyId: await this.getSessionKeyId(sessionKey)
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
console.log(`โ
Successfully decrypted memory ${request.memoryId} in ${result.decryptionTime}ms`);
|
|
395
|
+
return result;
|
|
396
|
+
|
|
397
|
+
} catch (error) {
|
|
398
|
+
this.updateDecryptionStats(false, Date.now() - startTime);
|
|
399
|
+
const errorMsg = `Decryption failed for memory ${request.memoryId}: ${error instanceof Error ? error.message : 'Unknown error'}`;
|
|
400
|
+
console.error('โ', errorMsg);
|
|
401
|
+
throw new Error(errorMsg);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* Decrypt multiple memories in batch for performance
|
|
407
|
+
*/
|
|
408
|
+
async decryptMemoryBatch(requests: DecryptionRequest[]): Promise<BatchDecryptionResult> {
|
|
409
|
+
console.log(`๐ Starting batch decryption of ${requests.length} memories`);
|
|
410
|
+
const startTime = Date.now();
|
|
411
|
+
|
|
412
|
+
const successful: DecryptionResult[] = [];
|
|
413
|
+
const failed: Array<{ memoryId: string; error: string; retryCount: number }> = [];
|
|
414
|
+
|
|
415
|
+
// Group requests into batches
|
|
416
|
+
const batchSize = this.config.batchSize || 10;
|
|
417
|
+
const batches = this.chunkArray(requests, batchSize);
|
|
418
|
+
|
|
419
|
+
for (const batch of batches) {
|
|
420
|
+
// Process batch with concurrency limit
|
|
421
|
+
const batchPromises = batch.map(async (request) => {
|
|
422
|
+
try {
|
|
423
|
+
const result = await this.decryptMemory(request);
|
|
424
|
+
successful.push(result);
|
|
425
|
+
} catch (error) {
|
|
426
|
+
failed.push({
|
|
427
|
+
memoryId: request.memoryId,
|
|
428
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
429
|
+
retryCount: 0
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
// Wait for batch to complete
|
|
435
|
+
await Promise.allSettled(batchPromises);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// Retry failed decryptions if enabled
|
|
439
|
+
if (this.config.enableFallback && this.config.maxRetryAttempts && this.config.maxRetryAttempts > 0) {
|
|
440
|
+
await this.retryFailedDecryptions(requests, failed, successful);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
const totalProcessingTime = Date.now() - startTime;
|
|
444
|
+
const stats = this.generateBatchStats(requests.length, successful.length, failed.length, totalProcessingTime);
|
|
445
|
+
|
|
446
|
+
console.log(`โ
Batch decryption completed: ${successful.length}/${requests.length} successful in ${totalProcessingTime}ms`);
|
|
447
|
+
|
|
448
|
+
return {
|
|
449
|
+
successful,
|
|
450
|
+
failed,
|
|
451
|
+
stats
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// ==================== SESSION KEY MANAGEMENT ====================
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* Get or create session key for user
|
|
459
|
+
*/
|
|
460
|
+
async getOrCreateSessionKey(userAddress: string): Promise<SessionKey> {
|
|
461
|
+
// Check if we have a valid cached session key
|
|
462
|
+
const existing = this.sessionKeys.get(userAddress);
|
|
463
|
+
const timestamp = this.sessionKeyTimestamps.get(userAddress);
|
|
464
|
+
|
|
465
|
+
if (existing && timestamp) {
|
|
466
|
+
const age = Date.now() - timestamp;
|
|
467
|
+
const ttl = (this.config.sessionKeyTTL || 60) * 60 * 1000; // Convert to ms
|
|
468
|
+
|
|
469
|
+
if (age < ttl) {
|
|
470
|
+
return existing;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// Create new session key
|
|
475
|
+
console.log(`๐ Creating new session key for user ${userAddress}`);
|
|
476
|
+
const sessionKey = await this.encryptionService.createSessionKey(userAddress);
|
|
477
|
+
|
|
478
|
+
// Cache with timestamp
|
|
479
|
+
this.sessionKeys.set(userAddress, sessionKey);
|
|
480
|
+
this.sessionKeyTimestamps.set(userAddress, Date.now());
|
|
481
|
+
|
|
482
|
+
// Cleanup old keys if we exceed limit
|
|
483
|
+
if (this.sessionKeys.size > (this.config.maxSessionKeys || 100)) {
|
|
484
|
+
this.cleanupOldestSessionKeys();
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
return sessionKey;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* Cleanup expired session keys
|
|
492
|
+
*/
|
|
493
|
+
private startSessionKeyCleanup(): void {
|
|
494
|
+
setInterval(() => {
|
|
495
|
+
const now = Date.now();
|
|
496
|
+
const ttl = (this.config.sessionKeyTTL || 60) * 60 * 1000;
|
|
497
|
+
|
|
498
|
+
for (const [userAddress, timestamp] of this.sessionKeyTimestamps.entries()) {
|
|
499
|
+
if (now - timestamp > ttl) {
|
|
500
|
+
this.sessionKeys.delete(userAddress);
|
|
501
|
+
this.sessionKeyTimestamps.delete(userAddress);
|
|
502
|
+
console.log(`๐งน Cleaned up expired session key for ${userAddress}`);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
}, 5 * 60 * 1000); // Check every 5 minutes
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* Cleanup oldest session keys when limit exceeded
|
|
510
|
+
*/
|
|
511
|
+
private cleanupOldestSessionKeys(): void {
|
|
512
|
+
const entries = Array.from(this.sessionKeyTimestamps.entries())
|
|
513
|
+
.sort((a, b) => a[1] - b[1]); // Sort by timestamp
|
|
514
|
+
|
|
515
|
+
// Remove oldest 25%
|
|
516
|
+
const toRemove = Math.floor(entries.length * 0.25);
|
|
517
|
+
for (let i = 0; i < toRemove; i++) {
|
|
518
|
+
const [userAddress] = entries[i];
|
|
519
|
+
this.sessionKeys.delete(userAddress);
|
|
520
|
+
this.sessionKeyTimestamps.delete(userAddress);
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
console.log(`๐งน Cleaned up ${toRemove} oldest session keys`);
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
// ==================== DECRYPTION UTILITIES ====================
|
|
527
|
+
|
|
528
|
+
/**
|
|
529
|
+
* Perform the actual decryption using SEAL
|
|
530
|
+
*/
|
|
531
|
+
private async performDecryption(request: DecryptionRequest, sessionKey: SessionKey): Promise<Uint8Array> {
|
|
532
|
+
if (!this.sealClient) {
|
|
533
|
+
throw new Error('SEAL client not initialized');
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
// Convert base64 encrypted content to bytes
|
|
537
|
+
const encryptedBytes = this.base64ToUint8Array(request.encryptedContent);
|
|
538
|
+
|
|
539
|
+
// Build access transaction
|
|
540
|
+
const accessTx = await this.encryptionService.buildAccessTransaction(request.userAddress, 'read');
|
|
541
|
+
// SEAL REQUIREMENT: Must use onlyTransactionKind: true for PTB validation
|
|
542
|
+
const txBytes = await accessTx.build({ client: (this.encryptionService as any).suiClient, onlyTransactionKind: true });
|
|
543
|
+
|
|
544
|
+
// Perform decryption with timeout
|
|
545
|
+
const decryptPromise = this.sealClient.decrypt({
|
|
546
|
+
data: encryptedBytes,
|
|
547
|
+
sessionKey: sessionKey,
|
|
548
|
+
txBytes: txBytes,
|
|
549
|
+
checkShareConsistency: true
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
// Add timeout
|
|
553
|
+
const timeoutPromise = new Promise<never>((_, reject) => {
|
|
554
|
+
setTimeout(() => reject(new Error('Decryption timeout')), this.config.decryptionTimeout || 30000);
|
|
555
|
+
});
|
|
556
|
+
|
|
557
|
+
return Promise.race([decryptPromise, timeoutPromise]);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
/**
|
|
561
|
+
* Verify user access to encrypted content
|
|
562
|
+
*/
|
|
563
|
+
private async verifyAccess(userAddress: string, memoryId: string, ownerAddress: string): Promise<boolean> {
|
|
564
|
+
try {
|
|
565
|
+
return await this.encryptionService.hasAccess(userAddress, memoryId, ownerAddress);
|
|
566
|
+
} catch (error) {
|
|
567
|
+
console.error(`Access verification failed: ${error}`);
|
|
568
|
+
return false;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
/**
|
|
573
|
+
* Verify content integrity using hash
|
|
574
|
+
*/
|
|
575
|
+
private async verifyContentIntegrity(content: Uint8Array, expectedHash: string): Promise<boolean> {
|
|
576
|
+
try {
|
|
577
|
+
return await (this.encryptionService as any).verifyContentHash(content, expectedHash);
|
|
578
|
+
} catch (error) {
|
|
579
|
+
console.error(`Content integrity verification failed: ${error}`);
|
|
580
|
+
return false;
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
/**
|
|
585
|
+
* Retry failed decryptions with exponential backoff
|
|
586
|
+
*/
|
|
587
|
+
private async retryFailedDecryptions(
|
|
588
|
+
originalRequests: DecryptionRequest[],
|
|
589
|
+
failed: Array<{ memoryId: string; error: string; retryCount: number }>,
|
|
590
|
+
successful: DecryptionResult[]
|
|
591
|
+
): Promise<void> {
|
|
592
|
+
const maxRetries = this.config.maxRetryAttempts || 3;
|
|
593
|
+
const baseDelay = this.config.retryDelayMs || 1000;
|
|
594
|
+
|
|
595
|
+
for (const failure of failed) {
|
|
596
|
+
if (failure.retryCount >= maxRetries) continue;
|
|
597
|
+
|
|
598
|
+
const originalRequest = originalRequests.find(r => r.memoryId === failure.memoryId);
|
|
599
|
+
if (!originalRequest) continue;
|
|
600
|
+
|
|
601
|
+
try {
|
|
602
|
+
// Exponential backoff
|
|
603
|
+
const delay = baseDelay * Math.pow(2, failure.retryCount);
|
|
604
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
605
|
+
|
|
606
|
+
console.log(`๐ Retrying decryption for memory ${failure.memoryId} (attempt ${failure.retryCount + 1})`);
|
|
607
|
+
const result = await this.decryptMemory(originalRequest);
|
|
608
|
+
|
|
609
|
+
// Move from failed to successful
|
|
610
|
+
successful.push(result);
|
|
611
|
+
const failIndex = failed.indexOf(failure);
|
|
612
|
+
failed.splice(failIndex, 1);
|
|
613
|
+
|
|
614
|
+
console.log(`โ
Retry successful for memory ${failure.memoryId}`);
|
|
615
|
+
} catch (error) {
|
|
616
|
+
failure.retryCount++;
|
|
617
|
+
failure.error = error instanceof Error ? error.message : 'Unknown error';
|
|
618
|
+
console.warn(`โ ๏ธ Retry ${failure.retryCount} failed for memory ${failure.memoryId}`);
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
// ==================== CACHE MANAGEMENT ====================
|
|
624
|
+
|
|
625
|
+
private getFromCache(key: string): string | null {
|
|
626
|
+
const cached = this.decryptionCache.get(key);
|
|
627
|
+
if (cached && Date.now() - cached.timestamp < this.CACHE_TTL) {
|
|
628
|
+
return cached.content;
|
|
629
|
+
}
|
|
630
|
+
this.decryptionCache.delete(key);
|
|
631
|
+
return null;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
private addToCache(key: string, content: string): void {
|
|
635
|
+
this.decryptionCache.set(key, { content, timestamp: Date.now() });
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
// ==================== UTILITY METHODS ====================
|
|
639
|
+
|
|
640
|
+
private base64ToUint8Array(base64: string): Uint8Array {
|
|
641
|
+
const binaryString = atob(base64);
|
|
642
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
643
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
644
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
645
|
+
}
|
|
646
|
+
return bytes;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
private chunkArray<T>(array: T[], size: number): T[][] {
|
|
650
|
+
const chunks: T[][] = [];
|
|
651
|
+
for (let i = 0; i < array.length; i += size) {
|
|
652
|
+
chunks.push(array.slice(i, i + size));
|
|
653
|
+
}
|
|
654
|
+
return chunks;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
private async getSessionKeyId(sessionKey: SessionKey): Promise<string> {
|
|
658
|
+
try {
|
|
659
|
+
const exported = sessionKey.export();
|
|
660
|
+
return `session_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
661
|
+
} catch {
|
|
662
|
+
return `session_${Date.now()}`;
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
private updateDecryptionStats(success: boolean, processingTime: number): void {
|
|
667
|
+
this.decryptionStats.totalDecryptions++;
|
|
668
|
+
this.decryptionStats.totalDecryptionTime += processingTime;
|
|
669
|
+
|
|
670
|
+
if (success) {
|
|
671
|
+
this.decryptionStats.successfulDecryptions++;
|
|
672
|
+
} else {
|
|
673
|
+
this.decryptionStats.failedDecryptions++;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
private generateBatchStats(
|
|
678
|
+
totalRequests: number,
|
|
679
|
+
successCount: number,
|
|
680
|
+
failureCount: number,
|
|
681
|
+
totalProcessingTime: number
|
|
682
|
+
): BatchDecryptionResult['stats'] {
|
|
683
|
+
return {
|
|
684
|
+
totalRequests,
|
|
685
|
+
successCount,
|
|
686
|
+
failureCount,
|
|
687
|
+
totalProcessingTime,
|
|
688
|
+
averageDecryptionTime: totalProcessingTime / totalRequests,
|
|
689
|
+
keyServerPerformance: {} // Would be populated with actual server stats
|
|
690
|
+
};
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
// ==================== PUBLIC API ====================
|
|
694
|
+
|
|
695
|
+
/**
|
|
696
|
+
* Decrypt encrypted content from unified memory results
|
|
697
|
+
*/
|
|
698
|
+
async decryptMemoryResults(
|
|
699
|
+
memories: UnifiedMemoryResult[],
|
|
700
|
+
userAddress: string
|
|
701
|
+
): Promise<UnifiedMemoryResult[]> {
|
|
702
|
+
console.log(`๐ Decrypting ${memories.length} encrypted memories for user ${userAddress}`);
|
|
703
|
+
|
|
704
|
+
const encryptedMemories = memories.filter(m => m.metadata.isEncrypted);
|
|
705
|
+
if (encryptedMemories.length === 0) {
|
|
706
|
+
console.log('๐ No encrypted memories found, returning original results');
|
|
707
|
+
return memories;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
// Prepare decryption requests
|
|
711
|
+
const decryptionRequests: DecryptionRequest[] = encryptedMemories.map(memory => ({
|
|
712
|
+
memoryId: memory.id,
|
|
713
|
+
encryptedContent: memory.content || '',
|
|
714
|
+
userAddress,
|
|
715
|
+
ownerAddress: memory.metadata.owner,
|
|
716
|
+
metadata: memory.metadata
|
|
717
|
+
}));
|
|
718
|
+
|
|
719
|
+
// Batch decrypt if enabled
|
|
720
|
+
let decryptedResults: DecryptionResult[] = [];
|
|
721
|
+
if (this.config.enableBatchDecryption && decryptionRequests.length > 1) {
|
|
722
|
+
const batchResult = await this.decryptMemoryBatch(decryptionRequests);
|
|
723
|
+
decryptedResults = batchResult.successful;
|
|
724
|
+
|
|
725
|
+
if (batchResult.failed.length > 0) {
|
|
726
|
+
console.warn(`โ ๏ธ Failed to decrypt ${batchResult.failed.length} memories:`,
|
|
727
|
+
batchResult.failed.map(f => f.memoryId));
|
|
728
|
+
}
|
|
729
|
+
} else {
|
|
730
|
+
// Decrypt individually
|
|
731
|
+
for (const request of decryptionRequests) {
|
|
732
|
+
try {
|
|
733
|
+
const result = await this.decryptMemory(request);
|
|
734
|
+
decryptedResults.push(result);
|
|
735
|
+
} catch (error) {
|
|
736
|
+
console.error(`Failed to decrypt memory ${request.memoryId}:`, error);
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
// Update memory results with decrypted content
|
|
742
|
+
const decryptionMap = new Map(decryptedResults.map(r => [r.memoryId, r]));
|
|
743
|
+
|
|
744
|
+
return memories.map(memory => {
|
|
745
|
+
if (memory.metadata.isEncrypted && decryptionMap.has(memory.id)) {
|
|
746
|
+
const decrypted = decryptionMap.get(memory.id)!;
|
|
747
|
+
return {
|
|
748
|
+
...memory,
|
|
749
|
+
content: decrypted.decryptedContent,
|
|
750
|
+
analytics: {
|
|
751
|
+
...memory.analytics,
|
|
752
|
+
viewCount: memory.analytics?.viewCount || 0,
|
|
753
|
+
shareCount: memory.analytics?.shareCount || 0,
|
|
754
|
+
editCount: memory.analytics?.editCount || 0,
|
|
755
|
+
sentimentScore: memory.analytics?.sentimentScore || 0,
|
|
756
|
+
topicDistribution: memory.analytics?.topicDistribution || {},
|
|
757
|
+
decryptionTime: decrypted.decryptionTime,
|
|
758
|
+
isDecryptionVerified: decrypted.isVerified
|
|
759
|
+
}
|
|
760
|
+
};
|
|
761
|
+
}
|
|
762
|
+
return memory;
|
|
763
|
+
});
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
/**
|
|
767
|
+
* Get decryption pipeline statistics
|
|
768
|
+
*/
|
|
769
|
+
getDecryptionStats(): {
|
|
770
|
+
totalDecryptions: number;
|
|
771
|
+
successRate: number;
|
|
772
|
+
averageDecryptionTime: number;
|
|
773
|
+
cacheHitRate: number;
|
|
774
|
+
activeSessionKeys: number;
|
|
775
|
+
keyServerStatus: string[];
|
|
776
|
+
} {
|
|
777
|
+
const successRate = this.decryptionStats.totalDecryptions > 0
|
|
778
|
+
? this.decryptionStats.successfulDecryptions / this.decryptionStats.totalDecryptions
|
|
779
|
+
: 0;
|
|
780
|
+
|
|
781
|
+
const avgTime = this.decryptionStats.totalDecryptions > 0
|
|
782
|
+
? this.decryptionStats.totalDecryptionTime / this.decryptionStats.totalDecryptions
|
|
783
|
+
: 0;
|
|
784
|
+
|
|
785
|
+
return {
|
|
786
|
+
totalDecryptions: this.decryptionStats.totalDecryptions,
|
|
787
|
+
successRate,
|
|
788
|
+
averageDecryptionTime: avgTime,
|
|
789
|
+
cacheHitRate: 0.85, // Would calculate from actual cache stats
|
|
790
|
+
activeSessionKeys: this.sessionKeys.size,
|
|
791
|
+
keyServerStatus: this.config.keyServers?.map(s => s.name) || []
|
|
792
|
+
};
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
/**
|
|
796
|
+
* Clear decryption cache
|
|
797
|
+
*/
|
|
798
|
+
clearCache(): void {
|
|
799
|
+
this.decryptionCache.clear();
|
|
800
|
+
console.log('๐งน Decryption cache cleared');
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
/**
|
|
804
|
+
* Check if decryption pipeline is ready
|
|
805
|
+
*/
|
|
806
|
+
isReady(): boolean {
|
|
807
|
+
return this.sealClient !== null;
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
/**
|
|
811
|
+
* Get pipeline configuration info
|
|
812
|
+
*/
|
|
813
|
+
getConfigInfo(): {
|
|
814
|
+
keyServers: number;
|
|
815
|
+
defaultNetwork: string;
|
|
816
|
+
batchingEnabled: boolean;
|
|
817
|
+
cacheEnabled: boolean;
|
|
818
|
+
} {
|
|
819
|
+
return {
|
|
820
|
+
keyServers: this.config.keyServers?.length || 0,
|
|
821
|
+
defaultNetwork: process.env.SUI_NETWORK || 'testnet',
|
|
822
|
+
batchingEnabled: this.config.enableBatchDecryption || false,
|
|
823
|
+
cacheEnabled: true
|
|
824
|
+
};
|
|
825
|
+
}
|
|
825
826
|
}
|