@cofhe/sdk 0.1.0 → 0.2.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 (121) hide show
  1. package/CHANGELOG.md +62 -0
  2. package/adapters/ethers5.test.ts +174 -0
  3. package/adapters/ethers5.ts +36 -0
  4. package/adapters/ethers6.test.ts +169 -0
  5. package/adapters/ethers6.ts +36 -0
  6. package/adapters/hardhat-node.ts +167 -0
  7. package/adapters/hardhat.hh2.test.ts +159 -0
  8. package/adapters/hardhat.ts +36 -0
  9. package/adapters/index.test.ts +20 -0
  10. package/adapters/index.ts +5 -0
  11. package/adapters/smartWallet.ts +99 -0
  12. package/adapters/test-utils.ts +53 -0
  13. package/adapters/types.ts +6 -0
  14. package/adapters/wagmi.test.ts +156 -0
  15. package/adapters/wagmi.ts +17 -0
  16. package/chains/chains/arbSepolia.ts +14 -0
  17. package/chains/chains/baseSepolia.ts +14 -0
  18. package/chains/chains/hardhat.ts +15 -0
  19. package/chains/chains/localcofhe.ts +14 -0
  20. package/chains/chains/sepolia.ts +14 -0
  21. package/chains/chains.test.ts +50 -0
  22. package/chains/defineChain.ts +18 -0
  23. package/chains/index.ts +35 -0
  24. package/chains/types.ts +32 -0
  25. package/core/baseBuilder.ts +119 -0
  26. package/core/client.test.ts +315 -0
  27. package/core/client.ts +292 -0
  28. package/core/clientTypes.ts +108 -0
  29. package/core/config.test.ts +235 -0
  30. package/core/config.ts +220 -0
  31. package/core/decrypt/MockQueryDecrypterAbi.ts +129 -0
  32. package/core/decrypt/cofheMocksSealOutput.ts +57 -0
  33. package/core/decrypt/decryptHandleBuilder.ts +287 -0
  34. package/core/decrypt/decryptUtils.ts +28 -0
  35. package/core/decrypt/tnSealOutputV1.ts +59 -0
  36. package/core/decrypt/tnSealOutputV2.ts +298 -0
  37. package/core/encrypt/MockZkVerifierAbi.ts +106 -0
  38. package/core/encrypt/cofheMocksZkVerifySign.ts +284 -0
  39. package/core/encrypt/encryptInputsBuilder.test.ts +751 -0
  40. package/core/encrypt/encryptInputsBuilder.ts +560 -0
  41. package/core/encrypt/encryptUtils.ts +67 -0
  42. package/core/encrypt/zkPackProveVerify.ts +335 -0
  43. package/core/error.ts +168 -0
  44. package/core/fetchKeys.test.ts +195 -0
  45. package/core/fetchKeys.ts +144 -0
  46. package/core/index.ts +89 -0
  47. package/core/keyStore.test.ts +226 -0
  48. package/core/keyStore.ts +154 -0
  49. package/core/permits.test.ts +494 -0
  50. package/core/permits.ts +200 -0
  51. package/core/types.ts +398 -0
  52. package/core/utils.ts +130 -0
  53. package/dist/adapters.cjs +88 -0
  54. package/dist/adapters.d.cts +14576 -0
  55. package/dist/adapters.d.ts +14576 -0
  56. package/dist/adapters.js +83 -0
  57. package/dist/chains.cjs +114 -0
  58. package/dist/chains.d.cts +121 -0
  59. package/dist/chains.d.ts +121 -0
  60. package/dist/chains.js +1 -0
  61. package/dist/chunk-UGBVZNRT.js +818 -0
  62. package/dist/chunk-WEAZ25JO.js +105 -0
  63. package/dist/chunk-WGCRJCBR.js +2523 -0
  64. package/dist/clientTypes-5_1nwtUe.d.cts +914 -0
  65. package/dist/clientTypes-Es7fyi65.d.ts +914 -0
  66. package/dist/core.cjs +3414 -0
  67. package/dist/core.d.cts +111 -0
  68. package/dist/core.d.ts +111 -0
  69. package/dist/core.js +3 -0
  70. package/dist/node.cjs +3286 -0
  71. package/dist/node.d.cts +22 -0
  72. package/dist/node.d.ts +22 -0
  73. package/dist/node.js +91 -0
  74. package/dist/permit-fUSe6KKq.d.cts +349 -0
  75. package/dist/permit-fUSe6KKq.d.ts +349 -0
  76. package/dist/permits.cjs +871 -0
  77. package/dist/permits.d.cts +1045 -0
  78. package/dist/permits.d.ts +1045 -0
  79. package/dist/permits.js +1 -0
  80. package/dist/types-KImPrEIe.d.cts +48 -0
  81. package/dist/types-KImPrEIe.d.ts +48 -0
  82. package/dist/web.cjs +3478 -0
  83. package/dist/web.d.cts +38 -0
  84. package/dist/web.d.ts +38 -0
  85. package/dist/web.js +240 -0
  86. package/dist/zkProve.worker.cjs +93 -0
  87. package/dist/zkProve.worker.d.cts +2 -0
  88. package/dist/zkProve.worker.d.ts +2 -0
  89. package/dist/zkProve.worker.js +91 -0
  90. package/node/client.test.ts +147 -0
  91. package/node/config.test.ts +68 -0
  92. package/node/encryptInputs.test.ts +155 -0
  93. package/node/index.ts +97 -0
  94. package/node/storage.ts +51 -0
  95. package/package.json +27 -15
  96. package/permits/index.ts +68 -0
  97. package/permits/localstorage.test.ts +117 -0
  98. package/permits/permit.test.ts +477 -0
  99. package/permits/permit.ts +405 -0
  100. package/permits/sealing.test.ts +84 -0
  101. package/permits/sealing.ts +131 -0
  102. package/permits/signature.ts +79 -0
  103. package/permits/store.test.ts +128 -0
  104. package/permits/store.ts +166 -0
  105. package/permits/test-utils.ts +20 -0
  106. package/permits/types.ts +191 -0
  107. package/permits/utils.ts +62 -0
  108. package/permits/validation.test.ts +288 -0
  109. package/permits/validation.ts +369 -0
  110. package/web/client.web.test.ts +147 -0
  111. package/web/config.web.test.ts +69 -0
  112. package/web/encryptInputs.web.test.ts +172 -0
  113. package/web/index.ts +161 -0
  114. package/web/storage.ts +34 -0
  115. package/web/worker.builder.web.test.ts +148 -0
  116. package/web/worker.config.web.test.ts +329 -0
  117. package/web/worker.output.web.test.ts +84 -0
  118. package/web/workerManager.test.ts +80 -0
  119. package/web/workerManager.ts +214 -0
  120. package/web/workerManager.web.test.ts +114 -0
  121. package/web/zkProve.worker.ts +133 -0
@@ -0,0 +1,214 @@
1
+ /**
2
+ * Worker Manager for ZK Proof Generation
3
+ * Manages worker lifecycle and request/response handling
4
+ */
5
+
6
+ import type { ZkProveWorkerRequest, ZkProveWorkerResponse } from '@/core';
7
+
8
+ // Declare Worker type for environments where it's not available
9
+ declare const Worker: any;
10
+
11
+ interface PendingRequest {
12
+ resolve: (value: Uint8Array) => void;
13
+ reject: (error: Error) => void;
14
+ timeoutId: ReturnType<typeof setTimeout>;
15
+ }
16
+
17
+ class ZkProveWorkerManager {
18
+ private worker: (typeof Worker extends new (...args: any[]) => infer W ? W : any) | null = null;
19
+ private pendingRequests = new Map<string, PendingRequest>();
20
+ private requestCounter = 0;
21
+ private workerReady = false;
22
+ private initializationPromise: Promise<void> | null = null;
23
+
24
+ /**
25
+ * Initialize the worker
26
+ */
27
+ private async initializeWorker(): Promise<void> {
28
+ if (this.worker && this.workerReady) {
29
+ return;
30
+ }
31
+
32
+ if (this.initializationPromise) {
33
+ return this.initializationPromise;
34
+ }
35
+
36
+ this.initializationPromise = new Promise((resolve, reject) => {
37
+ try {
38
+ // Check if Worker is supported
39
+ if (typeof Worker === 'undefined') {
40
+ reject(new Error('Web Workers not supported'));
41
+ return;
42
+ }
43
+
44
+ // Create worker
45
+ // Note: In production, this will try to load the worker from the same directory
46
+ // The bundler should handle this Worker instantiation
47
+ try {
48
+ this.worker = new Worker(new URL('./zkProve.worker.js', import.meta.url), { type: 'module' }) as any;
49
+ } catch (error) {
50
+ // If Worker creation fails, reject immediately
51
+ reject(new Error(`Failed to create worker: ${error}`));
52
+ return;
53
+ }
54
+
55
+ // Set up message handler
56
+ (this.worker as any).onmessage = (event: any) => {
57
+ const { id, type, result, error } = event.data as ZkProveWorkerResponse;
58
+
59
+ // Handle ready signal
60
+ if (type === 'ready') {
61
+ this.workerReady = true;
62
+ resolve();
63
+ return;
64
+ }
65
+
66
+ // Handle proof responses
67
+ const pending = this.pendingRequests.get(id);
68
+ if (!pending) {
69
+ console.warn('[Worker Manager] Received response for unknown request:', id);
70
+ return;
71
+ }
72
+
73
+ // Clear timeout
74
+ clearTimeout(pending.timeoutId);
75
+ this.pendingRequests.delete(id);
76
+
77
+ if (type === 'success' && result) {
78
+ pending.resolve(new Uint8Array(result));
79
+ } else if (type === 'error') {
80
+ pending.reject(new Error(error || 'Worker error'));
81
+ } else {
82
+ pending.reject(new Error('Invalid response from worker'));
83
+ }
84
+ };
85
+
86
+ // Set up error handler
87
+ (this.worker as any).onerror = (error: any) => {
88
+ console.error('[Worker Manager] Worker error event:', error);
89
+ console.error('[Worker Manager] Error message:', error.message);
90
+ console.error('[Worker Manager] Error filename:', error.filename);
91
+ console.error('[Worker Manager] Error lineno:', error.lineno);
92
+
93
+ // Reject initialization if not ready yet
94
+ if (!this.workerReady) {
95
+ reject(new Error(`Worker failed to initialize: ${error.message || 'Unknown error'}`));
96
+ }
97
+
98
+ // Reject all pending requests
99
+ this.pendingRequests.forEach(({ reject, timeoutId }) => {
100
+ clearTimeout(timeoutId);
101
+ reject(new Error('Worker encountered an error'));
102
+ });
103
+ this.pendingRequests.clear();
104
+ };
105
+
106
+ // Timeout if worker doesn't signal ready within 5 seconds
107
+ setTimeout(() => {
108
+ if (!this.workerReady) {
109
+ reject(new Error('Worker initialization timeout'));
110
+ }
111
+ }, 5000);
112
+ } catch (error) {
113
+ reject(error);
114
+ }
115
+ });
116
+
117
+ return this.initializationPromise;
118
+ }
119
+
120
+ /**
121
+ * Submit a proof generation request to the worker
122
+ */
123
+ async submitProof(
124
+ fheKeyHex: string,
125
+ crsHex: string,
126
+ items: Array<{ utype: string; data: any }>,
127
+ metadata: Uint8Array
128
+ ): Promise<Uint8Array> {
129
+ // Initialize worker if needed
130
+ await this.initializeWorker();
131
+
132
+ // Generate unique request ID
133
+ const id = `zkprove-${Date.now()}-${this.requestCounter++}`;
134
+
135
+ return new Promise((resolve, reject) => {
136
+ // Set up timeout (30 seconds)
137
+ const timeoutId = setTimeout(() => {
138
+ this.pendingRequests.delete(id);
139
+ reject(new Error('Worker request timeout (30s)'));
140
+ }, 30000);
141
+
142
+ // Store pending request
143
+ this.pendingRequests.set(id, { resolve, reject, timeoutId });
144
+
145
+ // Send message to worker
146
+ const message: ZkProveWorkerRequest = {
147
+ id,
148
+ type: 'zkProve',
149
+ fheKeyHex,
150
+ crsHex,
151
+ items,
152
+ metadata: Array.from(metadata),
153
+ };
154
+
155
+ (this.worker as any).postMessage(message);
156
+ });
157
+ }
158
+
159
+ /**
160
+ * Terminate the worker and clean up
161
+ */
162
+ terminate(): void {
163
+ if (this.worker) {
164
+ (this.worker as any).terminate();
165
+ this.worker = null;
166
+ this.workerReady = false;
167
+ this.initializationPromise = null;
168
+ }
169
+
170
+ // Reject all pending requests
171
+ this.pendingRequests.forEach(({ reject, timeoutId }) => {
172
+ clearTimeout(timeoutId);
173
+ reject(new Error('Worker terminated'));
174
+ });
175
+ this.pendingRequests.clear();
176
+ }
177
+
178
+ /**
179
+ * Check if worker is available
180
+ */
181
+ isAvailable(): boolean {
182
+ return typeof Worker !== 'undefined';
183
+ }
184
+ }
185
+
186
+ // Singleton instance
187
+ let workerManager: ZkProveWorkerManager | null = null;
188
+
189
+ /**
190
+ * Get the worker manager instance
191
+ */
192
+ export function getWorkerManager(): ZkProveWorkerManager {
193
+ if (!workerManager) {
194
+ workerManager = new ZkProveWorkerManager();
195
+ }
196
+ return workerManager;
197
+ }
198
+
199
+ /**
200
+ * Terminate the worker
201
+ */
202
+ export function terminateWorker(): void {
203
+ if (workerManager) {
204
+ workerManager.terminate();
205
+ workerManager = null;
206
+ }
207
+ }
208
+
209
+ /**
210
+ * Check if workers are available
211
+ */
212
+ export function areWorkersAvailable(): boolean {
213
+ return typeof Worker !== 'undefined';
214
+ }
@@ -0,0 +1,114 @@
1
+ import { describe, it, expect, afterEach } from 'vitest';
2
+ import { getWorkerManager, terminateWorker, areWorkersAvailable } from './workerManager.js';
3
+
4
+ describe('WorkerManager (Browser)', () => {
5
+ afterEach(() => {
6
+ // Clean up worker after each test
7
+ terminateWorker();
8
+ });
9
+
10
+ describe('areWorkersAvailable', () => {
11
+ it('should return true in browser environment', () => {
12
+ // In real browser with Playwright, workers should be available
13
+ expect(areWorkersAvailable()).toBe(true);
14
+ });
15
+ });
16
+
17
+ describe('Worker lifecycle', () => {
18
+ it('should initialize worker successfully', async () => {
19
+ const manager = getWorkerManager();
20
+ expect(manager).toBeDefined();
21
+
22
+ // Worker should be available
23
+ expect(areWorkersAvailable()).toBe(true);
24
+ });
25
+
26
+ it('should handle worker termination', () => {
27
+ const manager = getWorkerManager();
28
+ expect(manager).toBeDefined();
29
+
30
+ terminateWorker();
31
+
32
+ // Should be able to get a new instance
33
+ const newManager = getWorkerManager();
34
+ expect(newManager).toBeDefined();
35
+ });
36
+ });
37
+
38
+ describe('submitProof', () => {
39
+ it('should reject invalid data with error message', async () => {
40
+ const manager = getWorkerManager();
41
+
42
+ // Submit with invalid data - should fail quickly
43
+ await expect(manager.submitProof('invalid', 'invalid', [], new Uint8Array())).rejects.toThrow();
44
+ }, 35000);
45
+
46
+ it('should reject invalid message type', async () => {
47
+ const manager = getWorkerManager();
48
+
49
+ // Submit with invalid data that will cause worker error
50
+ await expect(
51
+ manager.submitProof(
52
+ '', // empty key
53
+ '', // empty crs
54
+ [{ utype: 'invalid', data: 'test' }],
55
+ new Uint8Array([1, 2, 3])
56
+ )
57
+ ).rejects.toThrow();
58
+ }, 35000);
59
+ });
60
+
61
+ describe('Concurrent requests', () => {
62
+ it('should handle multiple concurrent proof requests', async () => {
63
+ const manager = getWorkerManager();
64
+
65
+ // Submit multiple requests concurrently
66
+ const requests = [
67
+ manager.submitProof('key1', 'crs1', [], new Uint8Array([1])),
68
+ manager.submitProof('key2', 'crs2', [], new Uint8Array([2])),
69
+ manager.submitProof('key3', 'crs3', [], new Uint8Array([3])),
70
+ ];
71
+
72
+ // All should reject (invalid data), but shouldn't crash
73
+ const results = await Promise.allSettled(requests);
74
+
75
+ expect(results).toHaveLength(3);
76
+ results.forEach((result) => {
77
+ expect(result.status).toBe('rejected');
78
+ });
79
+ }, 35000);
80
+ });
81
+
82
+ describe('Worker error handling', () => {
83
+ it('should handle worker errors gracefully', async () => {
84
+ const manager = getWorkerManager();
85
+
86
+ // This should cause an error in the worker
87
+ await expect(
88
+ manager.submitProof(
89
+ 'malformed-hex',
90
+ 'malformed-crs',
91
+ [{ utype: 'uint128', data: 'not-a-number' }],
92
+ new Uint8Array([])
93
+ )
94
+ ).rejects.toThrow();
95
+ }, 35000);
96
+ });
97
+
98
+ describe('Termination during processing', () => {
99
+ it('should reject pending requests on termination', async () => {
100
+ const manager = getWorkerManager();
101
+
102
+ // Start a request (will timeout)
103
+ const proofPromise = manager.submitProof('test', 'test', [], new Uint8Array());
104
+
105
+ // Terminate immediately
106
+ setTimeout(() => {
107
+ terminateWorker();
108
+ }, 100);
109
+
110
+ // Request should be rejected
111
+ await expect(proofPromise).rejects.toThrow();
112
+ }, 5000);
113
+ });
114
+ });
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Web Worker for ZK Proof Generation
3
+ * Performs heavy WASM computation off the main thread
4
+ */
5
+
6
+ /// <reference lib="webworker" />
7
+ /* eslint-disable no-undef */
8
+
9
+ import type { ZkProveWorkerRequest, ZkProveWorkerResponse } from '../core/encrypt/zkPackProveVerify.js';
10
+
11
+ // TFHE module (will be initialized on first use)
12
+ let tfheModule: any = null;
13
+ let initialized = false;
14
+
15
+ /**
16
+ * Initialize TFHE in worker context
17
+ */
18
+ async function initTfhe() {
19
+ if (initialized) return;
20
+
21
+ try {
22
+ // Dynamic import of tfhe module
23
+ tfheModule = await import('tfhe');
24
+ await tfheModule.default();
25
+ await tfheModule.init_panic_hook();
26
+ initialized = true;
27
+ console.log('[Worker] TFHE initialized');
28
+ } catch (error) {
29
+ console.error('[Worker] Failed to initialize TFHE:', error);
30
+ throw error;
31
+ }
32
+ }
33
+
34
+ /**
35
+ * Convert hex string to Uint8Array
36
+ */
37
+ function fromHexString(hexString: string): Uint8Array {
38
+ const cleanString = hexString.length % 2 === 1 ? `0${hexString}` : hexString;
39
+ const arr = cleanString.replace(/^0x/, '').match(/.{1,2}/g);
40
+ if (!arr) return new Uint8Array();
41
+ return new Uint8Array(arr.map((byte) => parseInt(byte, 16)));
42
+ }
43
+
44
+ /**
45
+ * Main message handler
46
+ */
47
+ self.onmessage = async (event: MessageEvent) => {
48
+ const { id, type, fheKeyHex, crsHex, items, metadata } = event.data as ZkProveWorkerRequest;
49
+
50
+ if (type !== 'zkProve') {
51
+ self.postMessage({
52
+ id,
53
+ type: 'error',
54
+ error: 'Invalid message type',
55
+ } as ZkProveWorkerResponse);
56
+ return;
57
+ }
58
+
59
+ try {
60
+ // Initialize TFHE if needed
61
+ await initTfhe();
62
+
63
+ if (!tfheModule) {
64
+ throw new Error('TFHE module not initialized');
65
+ }
66
+
67
+ // Deserialize FHE public key and CRS from hex strings
68
+ const fheKeyBytes = fromHexString(fheKeyHex);
69
+ const crsBytes = fromHexString(crsHex);
70
+
71
+ const fheKey = tfheModule.TfheCompactPublicKey.deserialize(fheKeyBytes);
72
+ const crs = tfheModule.CompactPkeCrs.deserialize(crsBytes);
73
+
74
+ // Create builder
75
+ const builder = tfheModule.ProvenCompactCiphertextList.builder(fheKey);
76
+
77
+ // Pack all items (duplicate of zkPack logic)
78
+ for (const item of items) {
79
+ switch (item.utype) {
80
+ case 'bool':
81
+ builder.push_boolean(Boolean(item.data));
82
+ break;
83
+ case 'uint8':
84
+ builder.push_u8(Number(item.data));
85
+ break;
86
+ case 'uint16':
87
+ builder.push_u16(Number(item.data));
88
+ break;
89
+ case 'uint32':
90
+ builder.push_u32(Number(item.data));
91
+ break;
92
+ case 'uint64':
93
+ builder.push_u64(BigInt(item.data));
94
+ break;
95
+ case 'uint128':
96
+ builder.push_u128(BigInt(item.data));
97
+ break;
98
+ case 'uint160':
99
+ builder.push_u160(BigInt(item.data));
100
+ break;
101
+ default:
102
+ throw new Error(`Unsupported type: ${item.utype}`);
103
+ }
104
+ }
105
+
106
+ // THE HEAVY OPERATION - but in worker thread!
107
+ const metadataBytes = new Uint8Array(metadata);
108
+ const compactList = builder.build_with_proof_packed(crs, metadataBytes, 1);
109
+
110
+ // Serialize result
111
+ const result = compactList.serialize();
112
+
113
+ // Send success response
114
+ self.postMessage({
115
+ id,
116
+ type: 'success',
117
+ result: Array.from(result),
118
+ } as ZkProveWorkerResponse);
119
+ } catch (error) {
120
+ // Send error response
121
+ self.postMessage({
122
+ id,
123
+ type: 'error',
124
+ error: error instanceof Error ? error.message : String(error),
125
+ } as ZkProveWorkerResponse);
126
+ }
127
+ };
128
+
129
+ // Signal ready - send proper message format
130
+ self.postMessage({
131
+ id: 'init',
132
+ type: 'ready',
133
+ } as ZkProveWorkerResponse);