@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.
- package/CHANGELOG.md +62 -0
- package/adapters/ethers5.test.ts +174 -0
- package/adapters/ethers5.ts +36 -0
- package/adapters/ethers6.test.ts +169 -0
- package/adapters/ethers6.ts +36 -0
- package/adapters/hardhat-node.ts +167 -0
- package/adapters/hardhat.hh2.test.ts +159 -0
- package/adapters/hardhat.ts +36 -0
- package/adapters/index.test.ts +20 -0
- package/adapters/index.ts +5 -0
- package/adapters/smartWallet.ts +99 -0
- package/adapters/test-utils.ts +53 -0
- package/adapters/types.ts +6 -0
- package/adapters/wagmi.test.ts +156 -0
- package/adapters/wagmi.ts +17 -0
- package/chains/chains/arbSepolia.ts +14 -0
- package/chains/chains/baseSepolia.ts +14 -0
- package/chains/chains/hardhat.ts +15 -0
- package/chains/chains/localcofhe.ts +14 -0
- package/chains/chains/sepolia.ts +14 -0
- package/chains/chains.test.ts +50 -0
- package/chains/defineChain.ts +18 -0
- package/chains/index.ts +35 -0
- package/chains/types.ts +32 -0
- package/core/baseBuilder.ts +119 -0
- package/core/client.test.ts +315 -0
- package/core/client.ts +292 -0
- package/core/clientTypes.ts +108 -0
- package/core/config.test.ts +235 -0
- package/core/config.ts +220 -0
- package/core/decrypt/MockQueryDecrypterAbi.ts +129 -0
- package/core/decrypt/cofheMocksSealOutput.ts +57 -0
- package/core/decrypt/decryptHandleBuilder.ts +287 -0
- package/core/decrypt/decryptUtils.ts +28 -0
- package/core/decrypt/tnSealOutputV1.ts +59 -0
- package/core/decrypt/tnSealOutputV2.ts +298 -0
- package/core/encrypt/MockZkVerifierAbi.ts +106 -0
- package/core/encrypt/cofheMocksZkVerifySign.ts +284 -0
- package/core/encrypt/encryptInputsBuilder.test.ts +751 -0
- package/core/encrypt/encryptInputsBuilder.ts +560 -0
- package/core/encrypt/encryptUtils.ts +67 -0
- package/core/encrypt/zkPackProveVerify.ts +335 -0
- package/core/error.ts +168 -0
- package/core/fetchKeys.test.ts +195 -0
- package/core/fetchKeys.ts +144 -0
- package/core/index.ts +89 -0
- package/core/keyStore.test.ts +226 -0
- package/core/keyStore.ts +154 -0
- package/core/permits.test.ts +494 -0
- package/core/permits.ts +200 -0
- package/core/types.ts +398 -0
- package/core/utils.ts +130 -0
- package/dist/adapters.cjs +88 -0
- package/dist/adapters.d.cts +14576 -0
- package/dist/adapters.d.ts +14576 -0
- package/dist/adapters.js +83 -0
- package/dist/chains.cjs +114 -0
- package/dist/chains.d.cts +121 -0
- package/dist/chains.d.ts +121 -0
- package/dist/chains.js +1 -0
- package/dist/chunk-UGBVZNRT.js +818 -0
- package/dist/chunk-WEAZ25JO.js +105 -0
- package/dist/chunk-WGCRJCBR.js +2523 -0
- package/dist/clientTypes-5_1nwtUe.d.cts +914 -0
- package/dist/clientTypes-Es7fyi65.d.ts +914 -0
- package/dist/core.cjs +3414 -0
- package/dist/core.d.cts +111 -0
- package/dist/core.d.ts +111 -0
- package/dist/core.js +3 -0
- package/dist/node.cjs +3286 -0
- package/dist/node.d.cts +22 -0
- package/dist/node.d.ts +22 -0
- package/dist/node.js +91 -0
- package/dist/permit-fUSe6KKq.d.cts +349 -0
- package/dist/permit-fUSe6KKq.d.ts +349 -0
- package/dist/permits.cjs +871 -0
- package/dist/permits.d.cts +1045 -0
- package/dist/permits.d.ts +1045 -0
- package/dist/permits.js +1 -0
- package/dist/types-KImPrEIe.d.cts +48 -0
- package/dist/types-KImPrEIe.d.ts +48 -0
- package/dist/web.cjs +3478 -0
- package/dist/web.d.cts +38 -0
- package/dist/web.d.ts +38 -0
- package/dist/web.js +240 -0
- package/dist/zkProve.worker.cjs +93 -0
- package/dist/zkProve.worker.d.cts +2 -0
- package/dist/zkProve.worker.d.ts +2 -0
- package/dist/zkProve.worker.js +91 -0
- package/node/client.test.ts +147 -0
- package/node/config.test.ts +68 -0
- package/node/encryptInputs.test.ts +155 -0
- package/node/index.ts +97 -0
- package/node/storage.ts +51 -0
- package/package.json +27 -15
- package/permits/index.ts +68 -0
- package/permits/localstorage.test.ts +117 -0
- package/permits/permit.test.ts +477 -0
- package/permits/permit.ts +405 -0
- package/permits/sealing.test.ts +84 -0
- package/permits/sealing.ts +131 -0
- package/permits/signature.ts +79 -0
- package/permits/store.test.ts +128 -0
- package/permits/store.ts +166 -0
- package/permits/test-utils.ts +20 -0
- package/permits/types.ts +191 -0
- package/permits/utils.ts +62 -0
- package/permits/validation.test.ts +288 -0
- package/permits/validation.ts +369 -0
- package/web/client.web.test.ts +147 -0
- package/web/config.web.test.ts +69 -0
- package/web/encryptInputs.web.test.ts +172 -0
- package/web/index.ts +161 -0
- package/web/storage.ts +34 -0
- package/web/worker.builder.web.test.ts +148 -0
- package/web/worker.config.web.test.ts +329 -0
- package/web/worker.output.web.test.ts +84 -0
- package/web/workerManager.test.ts +80 -0
- package/web/workerManager.ts +214 -0
- package/web/workerManager.web.test.ts +114 -0
- package/web/zkProve.worker.ts +133 -0
package/dist/web.d.cts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { C as CofhesdkInputConfig, a as CofhesdkConfig, b as CofhesdkClient, E as EncryptableItem } from './clientTypes-5_1nwtUe.cjs';
|
|
2
|
+
import 'viem';
|
|
3
|
+
import './types-KImPrEIe.cjs';
|
|
4
|
+
import 'zod';
|
|
5
|
+
import './permit-fUSe6KKq.cjs';
|
|
6
|
+
import 'zustand/vanilla';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Terminate the worker
|
|
10
|
+
*/
|
|
11
|
+
declare function terminateWorker(): void;
|
|
12
|
+
/**
|
|
13
|
+
* Check if workers are available
|
|
14
|
+
*/
|
|
15
|
+
declare function areWorkersAvailable(): boolean;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Creates a CoFHE SDK configuration for web with IndexedDB storage as default
|
|
19
|
+
* @param config - The CoFHE SDK input configuration (fheKeyStorage will default to IndexedDB if not provided)
|
|
20
|
+
* @returns The CoFHE SDK configuration with web defaults applied
|
|
21
|
+
*/
|
|
22
|
+
declare function createCofhesdkConfig(config: CofhesdkInputConfig): CofhesdkConfig;
|
|
23
|
+
/**
|
|
24
|
+
* Creates a CoFHE SDK client instance for web with TFHE automatically configured
|
|
25
|
+
* TFHE will be initialized automatically on first encryption - no manual setup required
|
|
26
|
+
* Workers are automatically enabled if available (can be disabled via config.useWorkers)
|
|
27
|
+
* @param config - The CoFHE SDK configuration (use createCofhesdkConfig to create with web defaults)
|
|
28
|
+
* @returns The CoFHE SDK client instance
|
|
29
|
+
*/
|
|
30
|
+
declare function createCofhesdkClient<TConfig extends CofhesdkConfig>(config: TConfig): CofhesdkClient<TConfig>;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Test helper: Create a client with custom worker function (for testing fallback behavior)
|
|
34
|
+
* @internal - Only for testing purposes
|
|
35
|
+
*/
|
|
36
|
+
declare function createCofhesdkClientWithCustomWorker(config: CofhesdkConfig, customZkProveWorkerFn: (fheKeyHex: string, crsHex: string, items: EncryptableItem[], metadata: Uint8Array) => Promise<Uint8Array>): CofhesdkClient;
|
|
37
|
+
|
|
38
|
+
export { areWorkersAvailable, createCofhesdkClient, createCofhesdkClientWithCustomWorker, createCofhesdkConfig, terminateWorker };
|
package/dist/web.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { C as CofhesdkInputConfig, a as CofhesdkConfig, b as CofhesdkClient, E as EncryptableItem } from './clientTypes-Es7fyi65.js';
|
|
2
|
+
import 'viem';
|
|
3
|
+
import './types-KImPrEIe.js';
|
|
4
|
+
import 'zod';
|
|
5
|
+
import './permit-fUSe6KKq.js';
|
|
6
|
+
import 'zustand/vanilla';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Terminate the worker
|
|
10
|
+
*/
|
|
11
|
+
declare function terminateWorker(): void;
|
|
12
|
+
/**
|
|
13
|
+
* Check if workers are available
|
|
14
|
+
*/
|
|
15
|
+
declare function areWorkersAvailable(): boolean;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Creates a CoFHE SDK configuration for web with IndexedDB storage as default
|
|
19
|
+
* @param config - The CoFHE SDK input configuration (fheKeyStorage will default to IndexedDB if not provided)
|
|
20
|
+
* @returns The CoFHE SDK configuration with web defaults applied
|
|
21
|
+
*/
|
|
22
|
+
declare function createCofhesdkConfig(config: CofhesdkInputConfig): CofhesdkConfig;
|
|
23
|
+
/**
|
|
24
|
+
* Creates a CoFHE SDK client instance for web with TFHE automatically configured
|
|
25
|
+
* TFHE will be initialized automatically on first encryption - no manual setup required
|
|
26
|
+
* Workers are automatically enabled if available (can be disabled via config.useWorkers)
|
|
27
|
+
* @param config - The CoFHE SDK configuration (use createCofhesdkConfig to create with web defaults)
|
|
28
|
+
* @returns The CoFHE SDK client instance
|
|
29
|
+
*/
|
|
30
|
+
declare function createCofhesdkClient<TConfig extends CofhesdkConfig>(config: TConfig): CofhesdkClient<TConfig>;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Test helper: Create a client with custom worker function (for testing fallback behavior)
|
|
34
|
+
* @internal - Only for testing purposes
|
|
35
|
+
*/
|
|
36
|
+
declare function createCofhesdkClientWithCustomWorker(config: CofhesdkConfig, customZkProveWorkerFn: (fheKeyHex: string, crsHex: string, items: EncryptableItem[], metadata: Uint8Array) => Promise<Uint8Array>): CofhesdkClient;
|
|
37
|
+
|
|
38
|
+
export { areWorkersAvailable, createCofhesdkClient, createCofhesdkClientWithCustomWorker, createCofhesdkConfig, terminateWorker };
|
package/dist/web.js
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import { createCofhesdkConfigBase, createCofhesdkClientBase, fheTypeToString } from './chunk-WGCRJCBR.js';
|
|
2
|
+
import './chunk-WEAZ25JO.js';
|
|
3
|
+
import './chunk-UGBVZNRT.js';
|
|
4
|
+
import { constructClient } from 'iframe-shared-storage';
|
|
5
|
+
import init, { init_panic_hook, TfheCompactPublicKey, CompactPkeCrs, ProvenCompactCiphertextList } from 'tfhe';
|
|
6
|
+
|
|
7
|
+
var createWebStorage = () => {
|
|
8
|
+
const client = constructClient({
|
|
9
|
+
iframe: {
|
|
10
|
+
src: "https://iframe-shared-storage.vercel.app/hub.html",
|
|
11
|
+
messagingOptions: {
|
|
12
|
+
enableLog: "both"
|
|
13
|
+
},
|
|
14
|
+
iframeReadyTimeoutMs: 3e4,
|
|
15
|
+
// if the iframe is not initied during this interval AND a reuqest is made, such request will throw an error
|
|
16
|
+
methodCallTimeoutMs: 1e4,
|
|
17
|
+
// if a method call is not answered during this interval, the call will throw an error
|
|
18
|
+
methodCallRetries: 3
|
|
19
|
+
// number of retries for a method call if it times out
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
const indexedDBKeyval = client.indexedDBKeyval;
|
|
23
|
+
return {
|
|
24
|
+
getItem: async (name) => {
|
|
25
|
+
return await indexedDBKeyval.get(name) ?? null;
|
|
26
|
+
},
|
|
27
|
+
setItem: async (name, value) => {
|
|
28
|
+
await indexedDBKeyval.set(name, value);
|
|
29
|
+
},
|
|
30
|
+
removeItem: async (name) => {
|
|
31
|
+
await indexedDBKeyval.del(name);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
// web/workerManager.ts
|
|
37
|
+
var ZkProveWorkerManager = class {
|
|
38
|
+
worker = null;
|
|
39
|
+
pendingRequests = /* @__PURE__ */ new Map();
|
|
40
|
+
requestCounter = 0;
|
|
41
|
+
workerReady = false;
|
|
42
|
+
initializationPromise = null;
|
|
43
|
+
/**
|
|
44
|
+
* Initialize the worker
|
|
45
|
+
*/
|
|
46
|
+
async initializeWorker() {
|
|
47
|
+
if (this.worker && this.workerReady) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (this.initializationPromise) {
|
|
51
|
+
return this.initializationPromise;
|
|
52
|
+
}
|
|
53
|
+
this.initializationPromise = new Promise((resolve, reject) => {
|
|
54
|
+
try {
|
|
55
|
+
if (typeof Worker === "undefined") {
|
|
56
|
+
reject(new Error("Web Workers not supported"));
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
try {
|
|
60
|
+
this.worker = new Worker(new URL("./zkProve.worker.js", import.meta.url), { type: "module" });
|
|
61
|
+
} catch (error) {
|
|
62
|
+
reject(new Error(`Failed to create worker: ${error}`));
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
this.worker.onmessage = (event) => {
|
|
66
|
+
const { id, type, result, error } = event.data;
|
|
67
|
+
if (type === "ready") {
|
|
68
|
+
this.workerReady = true;
|
|
69
|
+
resolve();
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const pending = this.pendingRequests.get(id);
|
|
73
|
+
if (!pending) {
|
|
74
|
+
console.warn("[Worker Manager] Received response for unknown request:", id);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
clearTimeout(pending.timeoutId);
|
|
78
|
+
this.pendingRequests.delete(id);
|
|
79
|
+
if (type === "success" && result) {
|
|
80
|
+
pending.resolve(new Uint8Array(result));
|
|
81
|
+
} else if (type === "error") {
|
|
82
|
+
pending.reject(new Error(error || "Worker error"));
|
|
83
|
+
} else {
|
|
84
|
+
pending.reject(new Error("Invalid response from worker"));
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
this.worker.onerror = (error) => {
|
|
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
|
+
if (!this.workerReady) {
|
|
93
|
+
reject(new Error(`Worker failed to initialize: ${error.message || "Unknown error"}`));
|
|
94
|
+
}
|
|
95
|
+
this.pendingRequests.forEach(({ reject: reject2, timeoutId }) => {
|
|
96
|
+
clearTimeout(timeoutId);
|
|
97
|
+
reject2(new Error("Worker encountered an error"));
|
|
98
|
+
});
|
|
99
|
+
this.pendingRequests.clear();
|
|
100
|
+
};
|
|
101
|
+
setTimeout(() => {
|
|
102
|
+
if (!this.workerReady) {
|
|
103
|
+
reject(new Error("Worker initialization timeout"));
|
|
104
|
+
}
|
|
105
|
+
}, 5e3);
|
|
106
|
+
} catch (error) {
|
|
107
|
+
reject(error);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
return this.initializationPromise;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Submit a proof generation request to the worker
|
|
114
|
+
*/
|
|
115
|
+
async submitProof(fheKeyHex, crsHex, items, metadata) {
|
|
116
|
+
await this.initializeWorker();
|
|
117
|
+
const id = `zkprove-${Date.now()}-${this.requestCounter++}`;
|
|
118
|
+
return new Promise((resolve, reject) => {
|
|
119
|
+
const timeoutId = setTimeout(() => {
|
|
120
|
+
this.pendingRequests.delete(id);
|
|
121
|
+
reject(new Error("Worker request timeout (30s)"));
|
|
122
|
+
}, 3e4);
|
|
123
|
+
this.pendingRequests.set(id, { resolve, reject, timeoutId });
|
|
124
|
+
const message = {
|
|
125
|
+
id,
|
|
126
|
+
type: "zkProve",
|
|
127
|
+
fheKeyHex,
|
|
128
|
+
crsHex,
|
|
129
|
+
items,
|
|
130
|
+
metadata: Array.from(metadata)
|
|
131
|
+
};
|
|
132
|
+
this.worker.postMessage(message);
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Terminate the worker and clean up
|
|
137
|
+
*/
|
|
138
|
+
terminate() {
|
|
139
|
+
if (this.worker) {
|
|
140
|
+
this.worker.terminate();
|
|
141
|
+
this.worker = null;
|
|
142
|
+
this.workerReady = false;
|
|
143
|
+
this.initializationPromise = null;
|
|
144
|
+
}
|
|
145
|
+
this.pendingRequests.forEach(({ reject, timeoutId }) => {
|
|
146
|
+
clearTimeout(timeoutId);
|
|
147
|
+
reject(new Error("Worker terminated"));
|
|
148
|
+
});
|
|
149
|
+
this.pendingRequests.clear();
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Check if worker is available
|
|
153
|
+
*/
|
|
154
|
+
isAvailable() {
|
|
155
|
+
return typeof Worker !== "undefined";
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
var workerManager = null;
|
|
159
|
+
function getWorkerManager() {
|
|
160
|
+
if (!workerManager) {
|
|
161
|
+
workerManager = new ZkProveWorkerManager();
|
|
162
|
+
}
|
|
163
|
+
return workerManager;
|
|
164
|
+
}
|
|
165
|
+
function terminateWorker() {
|
|
166
|
+
if (workerManager) {
|
|
167
|
+
workerManager.terminate();
|
|
168
|
+
workerManager = null;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
function areWorkersAvailable() {
|
|
172
|
+
return typeof Worker !== "undefined";
|
|
173
|
+
}
|
|
174
|
+
var tfheInitialized = false;
|
|
175
|
+
async function initTfhe() {
|
|
176
|
+
if (tfheInitialized)
|
|
177
|
+
return false;
|
|
178
|
+
await init();
|
|
179
|
+
await init_panic_hook();
|
|
180
|
+
tfheInitialized = true;
|
|
181
|
+
return true;
|
|
182
|
+
}
|
|
183
|
+
var fromHexString = (hexString) => {
|
|
184
|
+
const cleanString = hexString.length % 2 === 1 ? `0${hexString}` : hexString;
|
|
185
|
+
const arr = cleanString.replace(/^0x/, "").match(/.{1,2}/g);
|
|
186
|
+
if (!arr)
|
|
187
|
+
return new Uint8Array();
|
|
188
|
+
return new Uint8Array(arr.map((byte) => parseInt(byte, 16)));
|
|
189
|
+
};
|
|
190
|
+
var tfhePublicKeyDeserializer = (buff) => {
|
|
191
|
+
TfheCompactPublicKey.deserialize(fromHexString(buff));
|
|
192
|
+
};
|
|
193
|
+
var compactPkeCrsDeserializer = (buff) => {
|
|
194
|
+
CompactPkeCrs.deserialize(fromHexString(buff));
|
|
195
|
+
};
|
|
196
|
+
var zkBuilderAndCrsGenerator = (fhe, crs) => {
|
|
197
|
+
const fhePublicKey = TfheCompactPublicKey.deserialize(fromHexString(fhe));
|
|
198
|
+
const zkBuilder = ProvenCompactCiphertextList.builder(fhePublicKey);
|
|
199
|
+
const zkCrs = CompactPkeCrs.deserialize(fromHexString(crs));
|
|
200
|
+
return { zkBuilder, zkCrs };
|
|
201
|
+
};
|
|
202
|
+
async function zkProveWithWorker(fheKeyHex, crsHex, items, metadata) {
|
|
203
|
+
const serializedItems = items.map((item) => ({
|
|
204
|
+
utype: fheTypeToString(item.utype),
|
|
205
|
+
data: typeof item.data === "bigint" ? item.data.toString() : item.data
|
|
206
|
+
}));
|
|
207
|
+
const workerManager2 = getWorkerManager();
|
|
208
|
+
return await workerManager2.submitProof(fheKeyHex, crsHex, serializedItems, metadata);
|
|
209
|
+
}
|
|
210
|
+
function createCofhesdkConfig(config) {
|
|
211
|
+
return createCofhesdkConfigBase({
|
|
212
|
+
environment: "web",
|
|
213
|
+
...config,
|
|
214
|
+
fheKeyStorage: config.fheKeyStorage === null ? null : config.fheKeyStorage ?? createWebStorage()
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
function createCofhesdkClient(config) {
|
|
218
|
+
return createCofhesdkClientBase({
|
|
219
|
+
config,
|
|
220
|
+
zkBuilderAndCrsGenerator,
|
|
221
|
+
tfhePublicKeyDeserializer,
|
|
222
|
+
compactPkeCrsDeserializer,
|
|
223
|
+
initTfhe,
|
|
224
|
+
// Always provide the worker function if available - config.useWorkers controls usage
|
|
225
|
+
// areWorkersAvailable will return true if the Worker API is available and false in Node.js
|
|
226
|
+
zkProveWorkerFn: areWorkersAvailable() ? zkProveWithWorker : void 0
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
function createCofhesdkClientWithCustomWorker(config, customZkProveWorkerFn) {
|
|
230
|
+
return createCofhesdkClientBase({
|
|
231
|
+
config,
|
|
232
|
+
zkBuilderAndCrsGenerator,
|
|
233
|
+
tfhePublicKeyDeserializer,
|
|
234
|
+
compactPkeCrsDeserializer,
|
|
235
|
+
initTfhe,
|
|
236
|
+
zkProveWorkerFn: customZkProveWorkerFn
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
export { areWorkersAvailable, createCofhesdkClient, createCofhesdkClientWithCustomWorker, createCofhesdkConfig, terminateWorker };
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// web/zkProve.worker.ts
|
|
4
|
+
var tfheModule = null;
|
|
5
|
+
var initialized = false;
|
|
6
|
+
async function initTfhe() {
|
|
7
|
+
if (initialized)
|
|
8
|
+
return;
|
|
9
|
+
try {
|
|
10
|
+
tfheModule = await import('tfhe');
|
|
11
|
+
await tfheModule.default();
|
|
12
|
+
await tfheModule.init_panic_hook();
|
|
13
|
+
initialized = true;
|
|
14
|
+
console.log("[Worker] TFHE initialized");
|
|
15
|
+
} catch (error) {
|
|
16
|
+
console.error("[Worker] Failed to initialize TFHE:", error);
|
|
17
|
+
throw error;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function fromHexString(hexString) {
|
|
21
|
+
const cleanString = hexString.length % 2 === 1 ? `0${hexString}` : hexString;
|
|
22
|
+
const arr = cleanString.replace(/^0x/, "").match(/.{1,2}/g);
|
|
23
|
+
if (!arr)
|
|
24
|
+
return new Uint8Array();
|
|
25
|
+
return new Uint8Array(arr.map((byte) => parseInt(byte, 16)));
|
|
26
|
+
}
|
|
27
|
+
self.onmessage = async (event) => {
|
|
28
|
+
const { id, type, fheKeyHex, crsHex, items, metadata } = event.data;
|
|
29
|
+
if (type !== "zkProve") {
|
|
30
|
+
self.postMessage({
|
|
31
|
+
id,
|
|
32
|
+
type: "error",
|
|
33
|
+
error: "Invalid message type"
|
|
34
|
+
});
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
await initTfhe();
|
|
39
|
+
if (!tfheModule) {
|
|
40
|
+
throw new Error("TFHE module not initialized");
|
|
41
|
+
}
|
|
42
|
+
const fheKeyBytes = fromHexString(fheKeyHex);
|
|
43
|
+
const crsBytes = fromHexString(crsHex);
|
|
44
|
+
const fheKey = tfheModule.TfheCompactPublicKey.deserialize(fheKeyBytes);
|
|
45
|
+
const crs = tfheModule.CompactPkeCrs.deserialize(crsBytes);
|
|
46
|
+
const builder = tfheModule.ProvenCompactCiphertextList.builder(fheKey);
|
|
47
|
+
for (const item of items) {
|
|
48
|
+
switch (item.utype) {
|
|
49
|
+
case "bool":
|
|
50
|
+
builder.push_boolean(Boolean(item.data));
|
|
51
|
+
break;
|
|
52
|
+
case "uint8":
|
|
53
|
+
builder.push_u8(Number(item.data));
|
|
54
|
+
break;
|
|
55
|
+
case "uint16":
|
|
56
|
+
builder.push_u16(Number(item.data));
|
|
57
|
+
break;
|
|
58
|
+
case "uint32":
|
|
59
|
+
builder.push_u32(Number(item.data));
|
|
60
|
+
break;
|
|
61
|
+
case "uint64":
|
|
62
|
+
builder.push_u64(BigInt(item.data));
|
|
63
|
+
break;
|
|
64
|
+
case "uint128":
|
|
65
|
+
builder.push_u128(BigInt(item.data));
|
|
66
|
+
break;
|
|
67
|
+
case "uint160":
|
|
68
|
+
builder.push_u160(BigInt(item.data));
|
|
69
|
+
break;
|
|
70
|
+
default:
|
|
71
|
+
throw new Error(`Unsupported type: ${item.utype}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
const metadataBytes = new Uint8Array(metadata);
|
|
75
|
+
const compactList = builder.build_with_proof_packed(crs, metadataBytes, 1);
|
|
76
|
+
const result = compactList.serialize();
|
|
77
|
+
self.postMessage({
|
|
78
|
+
id,
|
|
79
|
+
type: "success",
|
|
80
|
+
result: Array.from(result)
|
|
81
|
+
});
|
|
82
|
+
} catch (error) {
|
|
83
|
+
self.postMessage({
|
|
84
|
+
id,
|
|
85
|
+
type: "error",
|
|
86
|
+
error: error instanceof Error ? error.message : String(error)
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
self.postMessage({
|
|
91
|
+
id: "init",
|
|
92
|
+
type: "ready"
|
|
93
|
+
});
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// web/zkProve.worker.ts
|
|
2
|
+
var tfheModule = null;
|
|
3
|
+
var initialized = false;
|
|
4
|
+
async function initTfhe() {
|
|
5
|
+
if (initialized)
|
|
6
|
+
return;
|
|
7
|
+
try {
|
|
8
|
+
tfheModule = await import('tfhe');
|
|
9
|
+
await tfheModule.default();
|
|
10
|
+
await tfheModule.init_panic_hook();
|
|
11
|
+
initialized = true;
|
|
12
|
+
console.log("[Worker] TFHE initialized");
|
|
13
|
+
} catch (error) {
|
|
14
|
+
console.error("[Worker] Failed to initialize TFHE:", error);
|
|
15
|
+
throw error;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function fromHexString(hexString) {
|
|
19
|
+
const cleanString = hexString.length % 2 === 1 ? `0${hexString}` : hexString;
|
|
20
|
+
const arr = cleanString.replace(/^0x/, "").match(/.{1,2}/g);
|
|
21
|
+
if (!arr)
|
|
22
|
+
return new Uint8Array();
|
|
23
|
+
return new Uint8Array(arr.map((byte) => parseInt(byte, 16)));
|
|
24
|
+
}
|
|
25
|
+
self.onmessage = async (event) => {
|
|
26
|
+
const { id, type, fheKeyHex, crsHex, items, metadata } = event.data;
|
|
27
|
+
if (type !== "zkProve") {
|
|
28
|
+
self.postMessage({
|
|
29
|
+
id,
|
|
30
|
+
type: "error",
|
|
31
|
+
error: "Invalid message type"
|
|
32
|
+
});
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
await initTfhe();
|
|
37
|
+
if (!tfheModule) {
|
|
38
|
+
throw new Error("TFHE module not initialized");
|
|
39
|
+
}
|
|
40
|
+
const fheKeyBytes = fromHexString(fheKeyHex);
|
|
41
|
+
const crsBytes = fromHexString(crsHex);
|
|
42
|
+
const fheKey = tfheModule.TfheCompactPublicKey.deserialize(fheKeyBytes);
|
|
43
|
+
const crs = tfheModule.CompactPkeCrs.deserialize(crsBytes);
|
|
44
|
+
const builder = tfheModule.ProvenCompactCiphertextList.builder(fheKey);
|
|
45
|
+
for (const item of items) {
|
|
46
|
+
switch (item.utype) {
|
|
47
|
+
case "bool":
|
|
48
|
+
builder.push_boolean(Boolean(item.data));
|
|
49
|
+
break;
|
|
50
|
+
case "uint8":
|
|
51
|
+
builder.push_u8(Number(item.data));
|
|
52
|
+
break;
|
|
53
|
+
case "uint16":
|
|
54
|
+
builder.push_u16(Number(item.data));
|
|
55
|
+
break;
|
|
56
|
+
case "uint32":
|
|
57
|
+
builder.push_u32(Number(item.data));
|
|
58
|
+
break;
|
|
59
|
+
case "uint64":
|
|
60
|
+
builder.push_u64(BigInt(item.data));
|
|
61
|
+
break;
|
|
62
|
+
case "uint128":
|
|
63
|
+
builder.push_u128(BigInt(item.data));
|
|
64
|
+
break;
|
|
65
|
+
case "uint160":
|
|
66
|
+
builder.push_u160(BigInt(item.data));
|
|
67
|
+
break;
|
|
68
|
+
default:
|
|
69
|
+
throw new Error(`Unsupported type: ${item.utype}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
const metadataBytes = new Uint8Array(metadata);
|
|
73
|
+
const compactList = builder.build_with_proof_packed(crs, metadataBytes, 1);
|
|
74
|
+
const result = compactList.serialize();
|
|
75
|
+
self.postMessage({
|
|
76
|
+
id,
|
|
77
|
+
type: "success",
|
|
78
|
+
result: Array.from(result)
|
|
79
|
+
});
|
|
80
|
+
} catch (error) {
|
|
81
|
+
self.postMessage({
|
|
82
|
+
id,
|
|
83
|
+
type: "error",
|
|
84
|
+
error: error instanceof Error ? error.message : String(error)
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
self.postMessage({
|
|
89
|
+
id: "init",
|
|
90
|
+
type: "ready"
|
|
91
|
+
});
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { type CofhesdkClient, CofhesdkError, CofhesdkErrorCode } from '@/core';
|
|
2
|
+
import { arbSepolia as cofhesdkArbSepolia } from '@/chains';
|
|
3
|
+
|
|
4
|
+
import { describe, it, expect, beforeAll, beforeEach, vi } from 'vitest';
|
|
5
|
+
import type { PublicClient, WalletClient } from 'viem';
|
|
6
|
+
import { createPublicClient, createWalletClient, http } from 'viem';
|
|
7
|
+
import { privateKeyToAccount } from 'viem/accounts';
|
|
8
|
+
import { arbitrumSepolia as viemArbitrumSepolia } from 'viem/chains';
|
|
9
|
+
import { createCofhesdkClient, createCofhesdkConfig } from './index.js';
|
|
10
|
+
|
|
11
|
+
// Real test setup - no mocks
|
|
12
|
+
const TEST_PRIVATE_KEY = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80';
|
|
13
|
+
const TEST_ACCOUNT = privateKeyToAccount(TEST_PRIVATE_KEY).address;
|
|
14
|
+
|
|
15
|
+
describe('@cofhe/node - Client Integration Tests', () => {
|
|
16
|
+
let cofhesdkClient: CofhesdkClient;
|
|
17
|
+
let publicClient: PublicClient;
|
|
18
|
+
let walletClient: WalletClient;
|
|
19
|
+
|
|
20
|
+
beforeAll(() => {
|
|
21
|
+
// Create real viem clients
|
|
22
|
+
publicClient = createPublicClient({
|
|
23
|
+
chain: viemArbitrumSepolia,
|
|
24
|
+
transport: http(),
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const account = privateKeyToAccount(TEST_PRIVATE_KEY);
|
|
28
|
+
walletClient = createWalletClient({
|
|
29
|
+
chain: viemArbitrumSepolia,
|
|
30
|
+
transport: http(),
|
|
31
|
+
account,
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
beforeEach(() => {
|
|
36
|
+
const config = createCofhesdkConfig({
|
|
37
|
+
supportedChains: [cofhesdkArbSepolia],
|
|
38
|
+
});
|
|
39
|
+
cofhesdkClient = createCofhesdkClient(config);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
describe('Real Client Initialization', () => {
|
|
43
|
+
it('should create a client with real node-tfhe', () => {
|
|
44
|
+
expect(cofhesdkClient).toBeDefined();
|
|
45
|
+
expect(cofhesdkClient.config).toBeDefined();
|
|
46
|
+
expect(cofhesdkClient.connected).toBe(false);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('should automatically use filesystem storage as default', () => {
|
|
50
|
+
expect(cofhesdkClient.config.fheKeyStorage).toBeDefined();
|
|
51
|
+
expect(cofhesdkClient.config.fheKeyStorage).not.toBeNull();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('should have all expected methods', () => {
|
|
55
|
+
expect(typeof cofhesdkClient.connect).toBe('function');
|
|
56
|
+
expect(typeof cofhesdkClient.encryptInputs).toBe('function');
|
|
57
|
+
expect(typeof cofhesdkClient.decryptHandle).toBe('function');
|
|
58
|
+
expect(typeof cofhesdkClient.getSnapshot).toBe('function');
|
|
59
|
+
expect(typeof cofhesdkClient.subscribe).toBe('function');
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
describe('Environment', () => {
|
|
64
|
+
it('should have the correct environment', () => {
|
|
65
|
+
expect(cofhesdkClient.config.environment).toBe('node');
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
describe('Real Connection', () => {
|
|
70
|
+
it('should connect to real chain', async () => {
|
|
71
|
+
await cofhesdkClient.connect(publicClient, walletClient);
|
|
72
|
+
|
|
73
|
+
expect(cofhesdkClient.connected).toBe(true);
|
|
74
|
+
|
|
75
|
+
const snapshot = cofhesdkClient.getSnapshot();
|
|
76
|
+
expect(snapshot.connected).toBe(true);
|
|
77
|
+
expect(snapshot.chainId).toBe(cofhesdkArbSepolia.id);
|
|
78
|
+
expect(snapshot.account).toBe(TEST_ACCOUNT);
|
|
79
|
+
}, 30000);
|
|
80
|
+
|
|
81
|
+
it('should handle real network errors', async () => {
|
|
82
|
+
try {
|
|
83
|
+
await cofhesdkClient.connect(
|
|
84
|
+
{
|
|
85
|
+
getChainId: vi.fn().mockRejectedValue(new Error('Network error')),
|
|
86
|
+
} as unknown as PublicClient,
|
|
87
|
+
walletClient
|
|
88
|
+
);
|
|
89
|
+
} catch (error) {
|
|
90
|
+
expect(error).toBeInstanceOf(CofhesdkError);
|
|
91
|
+
expect((error as CofhesdkError).code).toBe(CofhesdkErrorCode.PublicWalletGetChainIdFailed);
|
|
92
|
+
}
|
|
93
|
+
}, 30000);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
describe('State Management', () => {
|
|
97
|
+
it('should track connection state changes', async () => {
|
|
98
|
+
const states: any[] = [];
|
|
99
|
+
const unsubscribe = cofhesdkClient.subscribe((snapshot) => {
|
|
100
|
+
states.push({ ...snapshot });
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
await cofhesdkClient.connect(publicClient, walletClient);
|
|
104
|
+
|
|
105
|
+
unsubscribe();
|
|
106
|
+
|
|
107
|
+
expect(states.length).toBeGreaterThan(0);
|
|
108
|
+
|
|
109
|
+
// First state should be connecting
|
|
110
|
+
const firstState = states.find((s) => s.connecting);
|
|
111
|
+
expect(firstState).toBeDefined();
|
|
112
|
+
expect(firstState?.connecting).toBe(true);
|
|
113
|
+
expect(firstState?.connected).toBe(false);
|
|
114
|
+
|
|
115
|
+
// Last state should be connected
|
|
116
|
+
const lastState = states[states.length - 1];
|
|
117
|
+
expect(lastState.connected).toBe(true);
|
|
118
|
+
expect(lastState.connecting).toBe(false);
|
|
119
|
+
expect(lastState.chainId).toBe(cofhesdkArbSepolia.id);
|
|
120
|
+
}, 30000);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
describe('Builder Creation', () => {
|
|
124
|
+
it('should create encrypt builder after connection', async () => {
|
|
125
|
+
await cofhesdkClient.connect(publicClient, walletClient);
|
|
126
|
+
|
|
127
|
+
const builder = cofhesdkClient.encryptInputs([{ data: 100n, utype: 2, securityZone: 0 }]);
|
|
128
|
+
|
|
129
|
+
expect(builder).toBeDefined();
|
|
130
|
+
expect(typeof builder.setChainId).toBe('function');
|
|
131
|
+
expect(typeof builder.setAccount).toBe('function');
|
|
132
|
+
expect(typeof builder.setSecurityZone).toBe('function');
|
|
133
|
+
expect(typeof builder.encrypt).toBe('function');
|
|
134
|
+
}, 30000);
|
|
135
|
+
|
|
136
|
+
it('should create decrypt builder after connection', async () => {
|
|
137
|
+
await cofhesdkClient.connect(publicClient, walletClient);
|
|
138
|
+
|
|
139
|
+
const builder = cofhesdkClient.decryptHandle(123n, 2);
|
|
140
|
+
|
|
141
|
+
expect(builder).toBeDefined();
|
|
142
|
+
expect(typeof builder.setChainId).toBe('function');
|
|
143
|
+
expect(typeof builder.setAccount).toBe('function');
|
|
144
|
+
expect(typeof builder.decrypt).toBe('function');
|
|
145
|
+
}, 30000);
|
|
146
|
+
});
|
|
147
|
+
});
|