@cofhe/sdk 0.1.1 → 0.2.1
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 +22 -0
- package/adapters/ethers6.ts +28 -28
- package/adapters/hardhat.ts +0 -1
- package/adapters/index.test.ts +14 -19
- package/adapters/smartWallet.ts +81 -73
- package/adapters/test-utils.ts +45 -45
- package/adapters/types.ts +3 -3
- package/chains/chains/localcofhe.ts +14 -0
- package/chains/chains.test.ts +2 -1
- package/chains/defineChain.ts +2 -2
- package/chains/index.ts +3 -1
- package/chains/types.ts +3 -3
- package/core/baseBuilder.ts +30 -49
- package/core/client.test.ts +200 -72
- package/core/client.ts +152 -148
- package/core/clientTypes.ts +114 -0
- package/core/config.test.ts +30 -11
- package/core/config.ts +26 -13
- package/core/consts.ts +18 -0
- package/core/decrypt/cofheMocksSealOutput.ts +2 -4
- package/core/decrypt/decryptHandleBuilder.ts +51 -45
- package/core/decrypt/{tnSealOutput.ts → tnSealOutputV1.ts} +1 -1
- package/core/decrypt/tnSealOutputV2.ts +298 -0
- package/core/encrypt/cofheMocksZkVerifySign.ts +15 -16
- package/core/encrypt/encryptInputsBuilder.test.ts +132 -116
- package/core/encrypt/encryptInputsBuilder.ts +159 -111
- package/core/encrypt/encryptUtils.ts +6 -3
- package/core/encrypt/zkPackProveVerify.ts +70 -8
- package/core/error.ts +0 -2
- package/core/fetchKeys.test.ts +1 -18
- package/core/fetchKeys.ts +0 -26
- package/core/index.ts +37 -17
- package/core/keyStore.ts +65 -38
- package/core/permits.test.ts +255 -4
- package/core/permits.ts +83 -18
- package/core/types.ts +198 -152
- package/core/utils.ts +43 -1
- package/dist/adapters.d.cts +38 -20
- package/dist/adapters.d.ts +38 -20
- package/dist/chains.cjs +18 -8
- package/dist/chains.d.cts +31 -9
- package/dist/chains.d.ts +31 -9
- package/dist/chains.js +1 -1
- package/dist/{chunk-KFGPTJ6X.js → chunk-I5WFEYXX.js} +1768 -1526
- package/dist/{chunk-LU7BMUUT.js → chunk-R3B5TMVX.js} +330 -197
- package/dist/{chunk-GZCQQYVI.js → chunk-TBLR7NNE.js} +18 -9
- package/dist/{types-PhwGgQvs.d.ts → clientTypes-RqkgkV2i.d.ts} +331 -429
- package/dist/{types-bB7wLj0q.d.cts → clientTypes-e4filDzK.d.cts} +331 -429
- package/dist/core.cjs +3000 -2625
- package/dist/core.d.cts +113 -7
- package/dist/core.d.ts +113 -7
- package/dist/core.js +3 -3
- package/dist/node.cjs +2851 -2526
- package/dist/node.d.cts +4 -4
- package/dist/node.d.ts +4 -4
- package/dist/node.js +4 -3
- package/dist/{permit-S9CnI6MF.d.cts → permit-MZ502UBl.d.cts} +54 -41
- package/dist/{permit-S9CnI6MF.d.ts → permit-MZ502UBl.d.ts} +54 -41
- package/dist/permits.cjs +328 -195
- package/dist/permits.d.cts +113 -825
- package/dist/permits.d.ts +113 -825
- package/dist/permits.js +1 -1
- package/dist/types-YiAC4gig.d.cts +33 -0
- package/dist/types-YiAC4gig.d.ts +33 -0
- package/dist/web.cjs +3067 -2527
- package/dist/web.d.cts +22 -6
- package/dist/web.d.ts +22 -6
- package/dist/web.js +185 -9
- 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 +20 -25
- package/node/encryptInputs.test.ts +18 -38
- package/node/index.ts +1 -0
- package/package.json +15 -15
- package/permits/index.ts +1 -0
- package/permits/localstorage.test.ts +9 -14
- package/permits/onchain-utils.ts +221 -0
- package/permits/permit.test.ts +76 -27
- package/permits/permit.ts +58 -95
- package/permits/sealing.test.ts +3 -3
- package/permits/sealing.ts +2 -2
- package/permits/store.test.ts +10 -50
- package/permits/store.ts +9 -21
- package/permits/test-utils.ts +11 -3
- package/permits/types.ts +39 -9
- package/permits/utils.ts +0 -5
- package/permits/validation.test.ts +29 -32
- package/permits/validation.ts +114 -176
- package/web/client.web.test.ts +20 -25
- package/web/config.web.test.ts +0 -2
- package/web/encryptInputs.web.test.ts +31 -54
- package/web/index.ts +65 -1
- package/web/storage.ts +19 -5
- 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/core/result.test.ts +0 -180
- package/core/result.ts +0 -67
- package/core/test-utils.ts +0 -45
- package/dist/types-KImPrEIe.d.cts +0 -48
- package/dist/types-KImPrEIe.d.ts +0 -48
package/web/index.ts
CHANGED
|
@@ -8,11 +8,16 @@ import {
|
|
|
8
8
|
type CofhesdkInputConfig,
|
|
9
9
|
type ZkBuilderAndCrsGenerator,
|
|
10
10
|
type FheKeyDeserializer,
|
|
11
|
+
type EncryptableItem,
|
|
12
|
+
fheTypeToString,
|
|
11
13
|
} from '@/core';
|
|
12
14
|
|
|
13
15
|
// Import web-specific storage (internal use only)
|
|
14
16
|
import { createWebStorage } from './storage.js';
|
|
15
17
|
|
|
18
|
+
// Import worker manager
|
|
19
|
+
import { getWorkerManager, terminateWorker, areWorkersAvailable } from './workerManager.js';
|
|
20
|
+
|
|
16
21
|
// Import tfhe for web
|
|
17
22
|
import init, { init_panic_hook, TfheCompactPublicKey, ProvenCompactCiphertextList, CompactPkeCrs } from 'tfhe';
|
|
18
23
|
|
|
@@ -68,6 +73,27 @@ const zkBuilderAndCrsGenerator: ZkBuilderAndCrsGenerator = (fhe: string, crs: st
|
|
|
68
73
|
return { zkBuilder, zkCrs };
|
|
69
74
|
};
|
|
70
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Worker-enabled zkProve function
|
|
78
|
+
* This submits proof generation to a Web Worker
|
|
79
|
+
*/
|
|
80
|
+
async function zkProveWithWorker(
|
|
81
|
+
fheKeyHex: string,
|
|
82
|
+
crsHex: string,
|
|
83
|
+
items: EncryptableItem[],
|
|
84
|
+
metadata: Uint8Array
|
|
85
|
+
): Promise<Uint8Array> {
|
|
86
|
+
// Serialize items for worker (convert enum to string name)
|
|
87
|
+
const serializedItems = items.map((item) => ({
|
|
88
|
+
utype: fheTypeToString(item.utype),
|
|
89
|
+
data: typeof item.data === 'bigint' ? item.data.toString() : item.data,
|
|
90
|
+
}));
|
|
91
|
+
|
|
92
|
+
// Submit to worker
|
|
93
|
+
const workerManager = getWorkerManager();
|
|
94
|
+
return await workerManager.submitProof(fheKeyHex, crsHex, serializedItems, metadata);
|
|
95
|
+
}
|
|
96
|
+
|
|
71
97
|
/**
|
|
72
98
|
* Creates a CoFHE SDK configuration for web with IndexedDB storage as default
|
|
73
99
|
* @param config - The CoFHE SDK input configuration (fheKeyStorage will default to IndexedDB if not provided)
|
|
@@ -75,6 +101,7 @@ const zkBuilderAndCrsGenerator: ZkBuilderAndCrsGenerator = (fhe: string, crs: st
|
|
|
75
101
|
*/
|
|
76
102
|
export function createCofhesdkConfig(config: CofhesdkInputConfig): CofhesdkConfig {
|
|
77
103
|
return createCofhesdkConfigBase({
|
|
104
|
+
environment: 'web',
|
|
78
105
|
...config,
|
|
79
106
|
fheKeyStorage: config.fheKeyStorage === null ? null : config.fheKeyStorage ?? createWebStorage(),
|
|
80
107
|
});
|
|
@@ -83,15 +110,52 @@ export function createCofhesdkConfig(config: CofhesdkInputConfig): CofhesdkConfi
|
|
|
83
110
|
/**
|
|
84
111
|
* Creates a CoFHE SDK client instance for web with TFHE automatically configured
|
|
85
112
|
* TFHE will be initialized automatically on first encryption - no manual setup required
|
|
113
|
+
* Workers are automatically enabled if available (can be disabled via config.useWorkers)
|
|
86
114
|
* @param config - The CoFHE SDK configuration (use createCofhesdkConfig to create with web defaults)
|
|
87
115
|
* @returns The CoFHE SDK client instance
|
|
88
116
|
*/
|
|
89
|
-
export function createCofhesdkClient(config:
|
|
117
|
+
export function createCofhesdkClient<TConfig extends CofhesdkConfig>(config: TConfig): CofhesdkClient<TConfig> {
|
|
118
|
+
return createCofhesdkClientBase({
|
|
119
|
+
config,
|
|
120
|
+
zkBuilderAndCrsGenerator,
|
|
121
|
+
tfhePublicKeyDeserializer,
|
|
122
|
+
compactPkeCrsDeserializer,
|
|
123
|
+
initTfhe,
|
|
124
|
+
// Always provide the worker function if available - config.useWorkers controls usage
|
|
125
|
+
// areWorkersAvailable will return true if the Worker API is available and false in Node.js
|
|
126
|
+
zkProveWorkerFn: areWorkersAvailable() ? zkProveWithWorker : undefined,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Terminate the worker (call on app cleanup)
|
|
132
|
+
*/
|
|
133
|
+
export { terminateWorker };
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Check if workers are available
|
|
137
|
+
*/
|
|
138
|
+
export { areWorkersAvailable };
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Test helper: Create a client with custom worker function (for testing fallback behavior)
|
|
142
|
+
* @internal - Only for testing purposes
|
|
143
|
+
*/
|
|
144
|
+
export function createCofhesdkClientWithCustomWorker(
|
|
145
|
+
config: CofhesdkConfig,
|
|
146
|
+
customZkProveWorkerFn: (
|
|
147
|
+
fheKeyHex: string,
|
|
148
|
+
crsHex: string,
|
|
149
|
+
items: EncryptableItem[],
|
|
150
|
+
metadata: Uint8Array
|
|
151
|
+
) => Promise<Uint8Array>
|
|
152
|
+
): CofhesdkClient {
|
|
90
153
|
return createCofhesdkClientBase({
|
|
91
154
|
config,
|
|
92
155
|
zkBuilderAndCrsGenerator,
|
|
93
156
|
tfhePublicKeyDeserializer,
|
|
94
157
|
compactPkeCrsDeserializer,
|
|
95
158
|
initTfhe,
|
|
159
|
+
zkProveWorkerFn: customZkProveWorkerFn,
|
|
96
160
|
});
|
|
97
161
|
}
|
package/web/storage.ts
CHANGED
|
@@ -1,20 +1,34 @@
|
|
|
1
1
|
import type { IStorage } from '@/core';
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import { constructClient } from 'iframe-shared-storage';
|
|
4
3
|
/**
|
|
5
4
|
* Creates a web storage implementation using IndexedDB
|
|
6
5
|
* @returns IStorage implementation for browser environments
|
|
7
6
|
*/
|
|
8
7
|
export const createWebStorage = (): IStorage => {
|
|
8
|
+
const client = constructClient({
|
|
9
|
+
iframe: {
|
|
10
|
+
src: 'https://iframe-shared-storage.vercel.app/hub.html',
|
|
11
|
+
messagingOptions: {
|
|
12
|
+
enableLog: 'both',
|
|
13
|
+
},
|
|
14
|
+
|
|
15
|
+
iframeReadyTimeoutMs: 30_000, // if the iframe is not initied during this interval AND a reuqest is made, such request will throw an error
|
|
16
|
+
methodCallTimeoutMs: 10_000, // if a method call is not answered during this interval, the call will throw an error
|
|
17
|
+
methodCallRetries: 3, // number of retries for a method call if it times out
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
const indexedDBKeyval = client.indexedDBKeyval;
|
|
9
22
|
return {
|
|
10
23
|
getItem: async (name: string) => {
|
|
11
|
-
|
|
24
|
+
// IndexedDBKeyval returns undefined if not found, but we want null (a json-deserialized value is expected)
|
|
25
|
+
return (await indexedDBKeyval.get(name)) ?? null;
|
|
12
26
|
},
|
|
13
27
|
setItem: async (name: string, value: any) => {
|
|
14
|
-
await set(name, value);
|
|
28
|
+
await indexedDBKeyval.set(name, value);
|
|
15
29
|
},
|
|
16
30
|
removeItem: async (name: string) => {
|
|
17
|
-
await del(name);
|
|
31
|
+
await indexedDBKeyval.del(name);
|
|
18
32
|
},
|
|
19
33
|
};
|
|
20
34
|
};
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { describe, it, expect, beforeAll, beforeEach } from 'vitest';
|
|
2
|
+
import { createCofhesdkClient, createCofhesdkConfig } from './index.js';
|
|
3
|
+
import { Encryptable, type CofhesdkClient } from '@/core';
|
|
4
|
+
import { arbSepolia as cofhesdkArbSepolia } from '@/chains';
|
|
5
|
+
import { arbitrumSepolia as viemArbitrumSepolia } from 'viem/chains';
|
|
6
|
+
import { createPublicClient, createWalletClient, http, type PublicClient, type WalletClient } from 'viem';
|
|
7
|
+
import { privateKeyToAccount } from 'viem/accounts';
|
|
8
|
+
|
|
9
|
+
const TEST_PRIVATE_KEY = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80';
|
|
10
|
+
|
|
11
|
+
describe('@cofhe/sdk/web - EncryptInputsBuilder Worker Methods', () => {
|
|
12
|
+
let cofhesdkClient: CofhesdkClient;
|
|
13
|
+
let publicClient: PublicClient;
|
|
14
|
+
let walletClient: WalletClient;
|
|
15
|
+
|
|
16
|
+
beforeAll(() => {
|
|
17
|
+
publicClient = createPublicClient({
|
|
18
|
+
chain: viemArbitrumSepolia,
|
|
19
|
+
transport: http(),
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const account = privateKeyToAccount(TEST_PRIVATE_KEY);
|
|
23
|
+
walletClient = createWalletClient({
|
|
24
|
+
chain: viemArbitrumSepolia,
|
|
25
|
+
transport: http(),
|
|
26
|
+
account,
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
beforeEach(async () => {
|
|
31
|
+
const config = createCofhesdkConfig({
|
|
32
|
+
supportedChains: [cofhesdkArbSepolia],
|
|
33
|
+
});
|
|
34
|
+
cofhesdkClient = createCofhesdkClient(config);
|
|
35
|
+
await cofhesdkClient.connect(publicClient, walletClient);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
describe('setUseWorker method', () => {
|
|
39
|
+
it('should have setUseWorker method on EncryptInputsBuilder', () => {
|
|
40
|
+
const builder = cofhesdkClient.encryptInputs([Encryptable.uint128(100n)]);
|
|
41
|
+
|
|
42
|
+
expect(builder).toHaveProperty('setUseWorker');
|
|
43
|
+
expect(typeof builder.setUseWorker).toBe('function');
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('should return builder for method chaining', () => {
|
|
47
|
+
const builder = cofhesdkClient.encryptInputs([Encryptable.uint128(100n)]);
|
|
48
|
+
const returnedBuilder = builder.setUseWorker(false);
|
|
49
|
+
|
|
50
|
+
// Should return the same builder instance (or at least same type)
|
|
51
|
+
expect(returnedBuilder).toBe(builder);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('should allow chaining with other builder methods', () => {
|
|
55
|
+
// Should be able to chain setUseWorker with setStepCallback
|
|
56
|
+
const builder = cofhesdkClient
|
|
57
|
+
.encryptInputs([Encryptable.uint128(100n)])
|
|
58
|
+
.setUseWorker(false)
|
|
59
|
+
.setStepCallback(() => {});
|
|
60
|
+
|
|
61
|
+
expect(builder).toBeDefined();
|
|
62
|
+
expect(builder).toHaveProperty('encrypt');
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('should accept true parameter', () => {
|
|
66
|
+
expect(() => {
|
|
67
|
+
cofhesdkClient.encryptInputs([Encryptable.uint128(100n)]).setUseWorker(true);
|
|
68
|
+
}).not.toThrow();
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('should accept false parameter', () => {
|
|
72
|
+
expect(() => {
|
|
73
|
+
cofhesdkClient.encryptInputs([Encryptable.uint128(100n)]).setUseWorker(false);
|
|
74
|
+
}).not.toThrow();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('should have getUseWorker method', () => {
|
|
78
|
+
const builder = cofhesdkClient.encryptInputs([Encryptable.uint128(100n)]);
|
|
79
|
+
|
|
80
|
+
expect(builder).toHaveProperty('getUseWorker');
|
|
81
|
+
expect(typeof builder.getUseWorker).toBe('function');
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('should return current useWorker value', () => {
|
|
85
|
+
const builderWithWorkers = cofhesdkClient.encryptInputs([Encryptable.uint128(100n)]).setUseWorker(true);
|
|
86
|
+
const builderWithoutWorkers = cofhesdkClient.encryptInputs([Encryptable.uint128(100n)]).setUseWorker(false);
|
|
87
|
+
|
|
88
|
+
// Should reflect config values
|
|
89
|
+
expect(builderWithWorkers.getUseWorker()).toBe(true);
|
|
90
|
+
expect(builderWithoutWorkers.getUseWorker()).toBe(false);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('should reflect changes from setUseWorker', () => {
|
|
94
|
+
const builder = cofhesdkClient.encryptInputs([Encryptable.uint128(100n)]).setUseWorker(true);
|
|
95
|
+
expect(builder.getUseWorker()).toBe(true);
|
|
96
|
+
|
|
97
|
+
builder.setUseWorker(false);
|
|
98
|
+
expect(builder.getUseWorker()).toBe(false);
|
|
99
|
+
|
|
100
|
+
builder.setUseWorker(true);
|
|
101
|
+
expect(builder.getUseWorker()).toBe(true);
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
describe('Worker function availability', () => {
|
|
106
|
+
it('should initialize client without errors', () => {
|
|
107
|
+
const config = createCofhesdkConfig({
|
|
108
|
+
supportedChains: [cofhesdkArbSepolia],
|
|
109
|
+
useWorkers: true,
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
expect(() => {
|
|
113
|
+
createCofhesdkClient(config);
|
|
114
|
+
}).not.toThrow();
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('should handle worker function when workers enabled', async () => {
|
|
118
|
+
const config = createCofhesdkConfig({
|
|
119
|
+
supportedChains: [cofhesdkArbSepolia],
|
|
120
|
+
useWorkers: true,
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
const client = createCofhesdkClient(config);
|
|
124
|
+
await client.connect(publicClient, walletClient);
|
|
125
|
+
const builder = client.encryptInputs([Encryptable.uint128(100n)]);
|
|
126
|
+
|
|
127
|
+
// Should not throw even though workers aren't available in Node
|
|
128
|
+
expect(() => {
|
|
129
|
+
builder.setUseWorker(true);
|
|
130
|
+
}).not.toThrow();
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('should handle when workers disabled', async () => {
|
|
134
|
+
const config = createCofhesdkConfig({
|
|
135
|
+
supportedChains: [cofhesdkArbSepolia],
|
|
136
|
+
useWorkers: false,
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
const client = createCofhesdkClient(config);
|
|
140
|
+
await client.connect(publicClient, walletClient);
|
|
141
|
+
const builder = client.encryptInputs([Encryptable.uint128(100n)]);
|
|
142
|
+
|
|
143
|
+
expect(() => {
|
|
144
|
+
builder.setUseWorker(false);
|
|
145
|
+
}).not.toThrow();
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
});
|
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
import { arbSepolia as cofhesdkArbSepolia } from '@/chains';
|
|
2
|
+
import { Encryptable } from '@/core';
|
|
3
|
+
|
|
4
|
+
import { describe, it, expect, beforeAll } 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, createCofhesdkClientWithCustomWorker } from './index.js';
|
|
10
|
+
|
|
11
|
+
const TEST_PRIVATE_KEY = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80';
|
|
12
|
+
|
|
13
|
+
describe('@cofhe/sdk/web - Worker Configuration Tests', () => {
|
|
14
|
+
let publicClient: PublicClient;
|
|
15
|
+
let walletClient: WalletClient;
|
|
16
|
+
|
|
17
|
+
beforeAll(() => {
|
|
18
|
+
publicClient = createPublicClient({
|
|
19
|
+
chain: viemArbitrumSepolia,
|
|
20
|
+
transport: http(),
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const account = privateKeyToAccount(TEST_PRIVATE_KEY);
|
|
24
|
+
walletClient = createWalletClient({
|
|
25
|
+
chain: viemArbitrumSepolia,
|
|
26
|
+
transport: http(),
|
|
27
|
+
account,
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe('useWorkers config flag', () => {
|
|
32
|
+
it('should use workers by default (useWorkers: true)', async () => {
|
|
33
|
+
const config = createCofhesdkConfig({
|
|
34
|
+
supportedChains: [cofhesdkArbSepolia],
|
|
35
|
+
// useWorkers defaults to true
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
expect(config.useWorkers).toBe(true);
|
|
39
|
+
|
|
40
|
+
const client = createCofhesdkClient(config);
|
|
41
|
+
await client.connect(publicClient, walletClient);
|
|
42
|
+
|
|
43
|
+
// Track step callbacks to see worker usage
|
|
44
|
+
let proveContext: any;
|
|
45
|
+
const result = await client
|
|
46
|
+
.encryptInputs([Encryptable.uint128(100n)])
|
|
47
|
+
.setStepCallback((step, context) => {
|
|
48
|
+
if (step === 'prove' && context?.isEnd) {
|
|
49
|
+
proveContext = context;
|
|
50
|
+
}
|
|
51
|
+
})
|
|
52
|
+
.encrypt();
|
|
53
|
+
|
|
54
|
+
expect(result).toBeDefined();
|
|
55
|
+
|
|
56
|
+
// Check that worker was attempted
|
|
57
|
+
expect(proveContext).toBeDefined();
|
|
58
|
+
expect(proveContext.useWorker).toBe(true);
|
|
59
|
+
// Note: Workers may fail to initialize in Playwright test environment
|
|
60
|
+
// due to WASM module loading issues. Verify fallback works correctly.
|
|
61
|
+
expect(proveContext.usedWorker).toBeDefined();
|
|
62
|
+
// The test cannot load tfhe module, so the worker fallback occurs.
|
|
63
|
+
// The real test is to check that usedWorker is true
|
|
64
|
+
// TBD: Find a way to test this in the test environment.
|
|
65
|
+
|
|
66
|
+
// Log if fallback occurred for debugging
|
|
67
|
+
if (!proveContext.usedWorker) {
|
|
68
|
+
console.log('Worker fallback occurred (expected in test env):', proveContext.workerFailedError);
|
|
69
|
+
expect(proveContext.workerFailedError).toBeDefined();
|
|
70
|
+
}
|
|
71
|
+
}, 60000);
|
|
72
|
+
|
|
73
|
+
it('should disable workers when useWorkers: false', async () => {
|
|
74
|
+
const config = createCofhesdkConfig({
|
|
75
|
+
supportedChains: [cofhesdkArbSepolia],
|
|
76
|
+
useWorkers: false,
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
expect(config.useWorkers).toBe(false);
|
|
80
|
+
|
|
81
|
+
const client = createCofhesdkClient(config);
|
|
82
|
+
await client.connect(publicClient, walletClient);
|
|
83
|
+
|
|
84
|
+
// Track step callbacks
|
|
85
|
+
let proveContext: any;
|
|
86
|
+
const result = await client
|
|
87
|
+
.encryptInputs([Encryptable.uint128(100n)])
|
|
88
|
+
.setStepCallback((step, context) => {
|
|
89
|
+
if (step === 'prove' && context?.isEnd) {
|
|
90
|
+
proveContext = context;
|
|
91
|
+
}
|
|
92
|
+
})
|
|
93
|
+
.encrypt();
|
|
94
|
+
|
|
95
|
+
expect(result).toBeDefined();
|
|
96
|
+
|
|
97
|
+
// Should explicitly NOT use workers
|
|
98
|
+
expect(proveContext).toBeDefined();
|
|
99
|
+
expect(proveContext.useWorker).toBe(false);
|
|
100
|
+
expect(proveContext.usedWorker).toBe(false);
|
|
101
|
+
}, 60000);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
describe('setUseWorker() method', () => {
|
|
105
|
+
it('should override config with setUseWorker(false)', async () => {
|
|
106
|
+
const config = createCofhesdkConfig({
|
|
107
|
+
supportedChains: [cofhesdkArbSepolia],
|
|
108
|
+
useWorkers: true, // Config says true
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
const client = createCofhesdkClient(config);
|
|
112
|
+
await client.connect(publicClient, walletClient);
|
|
113
|
+
|
|
114
|
+
// Track step callbacks
|
|
115
|
+
let proveContext: any;
|
|
116
|
+
const result = await client
|
|
117
|
+
.encryptInputs([Encryptable.uint128(100n)])
|
|
118
|
+
.setUseWorker(false) // Override to false
|
|
119
|
+
.setStepCallback((step, context) => {
|
|
120
|
+
if (step === 'prove' && context?.isEnd) {
|
|
121
|
+
proveContext = context;
|
|
122
|
+
}
|
|
123
|
+
})
|
|
124
|
+
.encrypt();
|
|
125
|
+
|
|
126
|
+
expect(result).toBeDefined();
|
|
127
|
+
|
|
128
|
+
// Should respect the override
|
|
129
|
+
expect(proveContext.useWorker).toBe(false);
|
|
130
|
+
expect(proveContext.usedWorker).toBe(false);
|
|
131
|
+
}, 60000);
|
|
132
|
+
|
|
133
|
+
it('should override config with setUseWorker(true)', async () => {
|
|
134
|
+
const config = createCofhesdkConfig({
|
|
135
|
+
supportedChains: [cofhesdkArbSepolia],
|
|
136
|
+
useWorkers: false, // Config says false
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
const client = createCofhesdkClient(config);
|
|
140
|
+
await client.connect(publicClient, walletClient);
|
|
141
|
+
|
|
142
|
+
// Track step callbacks
|
|
143
|
+
let proveContext: any;
|
|
144
|
+
const result = await client
|
|
145
|
+
.encryptInputs([Encryptable.uint128(100n)])
|
|
146
|
+
.setUseWorker(true) // Override to true
|
|
147
|
+
.setStepCallback((step, context) => {
|
|
148
|
+
if (step === 'prove' && context?.isEnd) {
|
|
149
|
+
proveContext = context;
|
|
150
|
+
}
|
|
151
|
+
})
|
|
152
|
+
.encrypt();
|
|
153
|
+
|
|
154
|
+
expect(result).toBeDefined();
|
|
155
|
+
|
|
156
|
+
// Should use worker since we overrode to true
|
|
157
|
+
expect(proveContext.useWorker).toBe(true);
|
|
158
|
+
}, 60000);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
describe('Step callback worker context', () => {
|
|
162
|
+
it('should include worker debug info in prove step', async () => {
|
|
163
|
+
const config = createCofhesdkConfig({
|
|
164
|
+
supportedChains: [cofhesdkArbSepolia],
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
const client = createCofhesdkClient(config);
|
|
168
|
+
await client.connect(publicClient, walletClient);
|
|
169
|
+
|
|
170
|
+
let proveContext: any;
|
|
171
|
+
const result = await client
|
|
172
|
+
.encryptInputs([Encryptable.uint128(100n)])
|
|
173
|
+
.setStepCallback((step, context) => {
|
|
174
|
+
if (step === 'prove' && context?.isEnd) {
|
|
175
|
+
proveContext = context;
|
|
176
|
+
}
|
|
177
|
+
})
|
|
178
|
+
.encrypt();
|
|
179
|
+
|
|
180
|
+
expect(result).toBeDefined();
|
|
181
|
+
|
|
182
|
+
// Verify all worker-related fields are present
|
|
183
|
+
expect(proveContext).toBeDefined();
|
|
184
|
+
expect(proveContext).toHaveProperty('useWorker');
|
|
185
|
+
expect(proveContext).toHaveProperty('usedWorker');
|
|
186
|
+
expect(proveContext).toHaveProperty('isEnd');
|
|
187
|
+
expect(proveContext).toHaveProperty('duration');
|
|
188
|
+
|
|
189
|
+
// If worker failed, should have error message
|
|
190
|
+
if (proveContext.useWorker && !proveContext.usedWorker) {
|
|
191
|
+
expect(proveContext).toHaveProperty('workerFailedError');
|
|
192
|
+
expect(typeof proveContext.workerFailedError).toBe('string');
|
|
193
|
+
}
|
|
194
|
+
}, 60000);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
describe('Worker fallback behavior', () => {
|
|
198
|
+
it('should fallback to main thread when worker fails', async () => {
|
|
199
|
+
const config = createCofhesdkConfig({
|
|
200
|
+
supportedChains: [cofhesdkArbSepolia],
|
|
201
|
+
useWorkers: true,
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
// Create a worker function that ALWAYS fails
|
|
205
|
+
const failingWorkerFn = async () => {
|
|
206
|
+
throw new Error('Worker failed intentionally');
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
// Inject the failing worker into the client
|
|
210
|
+
const client = createCofhesdkClientWithCustomWorker(config, failingWorkerFn);
|
|
211
|
+
await client.connect(publicClient, walletClient);
|
|
212
|
+
|
|
213
|
+
// Track step callbacks to verify fallback
|
|
214
|
+
let proveContext: any;
|
|
215
|
+
const result = await client
|
|
216
|
+
.encryptInputs([Encryptable.uint128(100n)])
|
|
217
|
+
.setStepCallback((step, context) => {
|
|
218
|
+
if (step === 'prove' && context?.isEnd) {
|
|
219
|
+
proveContext = context;
|
|
220
|
+
}
|
|
221
|
+
})
|
|
222
|
+
.encrypt();
|
|
223
|
+
|
|
224
|
+
// Verify encryption succeeded via fallback to main thread
|
|
225
|
+
expect(result).toBeDefined();
|
|
226
|
+
expect(result.length).toBe(1);
|
|
227
|
+
|
|
228
|
+
// Verify worker was attempted but failed, triggering fallback
|
|
229
|
+
expect(proveContext).toBeDefined();
|
|
230
|
+
expect(proveContext.useWorker).toBe(true); // Worker was requested
|
|
231
|
+
expect(proveContext.usedWorker).toBe(false); // But it failed
|
|
232
|
+
expect(proveContext.workerFailedError).toBe('Worker failed intentionally');
|
|
233
|
+
}, 60000);
|
|
234
|
+
|
|
235
|
+
it('should fallback when encrypting multiple values', async () => {
|
|
236
|
+
const config = createCofhesdkConfig({
|
|
237
|
+
supportedChains: [cofhesdkArbSepolia],
|
|
238
|
+
useWorkers: true,
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
// Failing worker with different error message
|
|
242
|
+
const failingWorkerFn = async () => {
|
|
243
|
+
throw new Error('Worker unavailable');
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
const client = createCofhesdkClientWithCustomWorker(config, failingWorkerFn);
|
|
247
|
+
await client.connect(publicClient, walletClient);
|
|
248
|
+
|
|
249
|
+
let proveContext: any;
|
|
250
|
+
const result = await client
|
|
251
|
+
.encryptInputs([Encryptable.uint128(100n), Encryptable.uint64(50n), Encryptable.bool(true)])
|
|
252
|
+
.setStepCallback((step, context) => {
|
|
253
|
+
if (step === 'prove' && context?.isEnd) {
|
|
254
|
+
proveContext = context;
|
|
255
|
+
}
|
|
256
|
+
})
|
|
257
|
+
.encrypt();
|
|
258
|
+
|
|
259
|
+
// All values should encrypt successfully via fallback
|
|
260
|
+
expect(result).toBeDefined();
|
|
261
|
+
expect(result.length).toBe(3);
|
|
262
|
+
|
|
263
|
+
// Verify fallback occurred
|
|
264
|
+
expect(proveContext.useWorker).toBe(true);
|
|
265
|
+
expect(proveContext.usedWorker).toBe(false);
|
|
266
|
+
expect(proveContext.workerFailedError).toBe('Worker unavailable');
|
|
267
|
+
}, 60000);
|
|
268
|
+
|
|
269
|
+
it('should handle async worker errors gracefully', async () => {
|
|
270
|
+
const config = createCofhesdkConfig({
|
|
271
|
+
supportedChains: [cofhesdkArbSepolia],
|
|
272
|
+
useWorkers: true,
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
// Worker that fails after a delay
|
|
276
|
+
const asyncFailingWorkerFn = async () => {
|
|
277
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
278
|
+
throw new Error('Async worker failure');
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
const client = createCofhesdkClientWithCustomWorker(config, asyncFailingWorkerFn);
|
|
282
|
+
await client.connect(publicClient, walletClient);
|
|
283
|
+
|
|
284
|
+
let proveContext: any;
|
|
285
|
+
const result = await client
|
|
286
|
+
.encryptInputs([Encryptable.uint8(42n)])
|
|
287
|
+
.setStepCallback((step, context) => {
|
|
288
|
+
if (step === 'prove' && context?.isEnd) {
|
|
289
|
+
proveContext = context;
|
|
290
|
+
}
|
|
291
|
+
})
|
|
292
|
+
.encrypt();
|
|
293
|
+
|
|
294
|
+
expect(result).toBeDefined();
|
|
295
|
+
|
|
296
|
+
expect(proveContext.useWorker).toBe(true);
|
|
297
|
+
expect(proveContext.usedWorker).toBe(false);
|
|
298
|
+
expect(proveContext.workerFailedError).toBe('Async worker failure');
|
|
299
|
+
}, 60000);
|
|
300
|
+
|
|
301
|
+
it('should work without worker when explicitly disabled', async () => {
|
|
302
|
+
const config = createCofhesdkConfig({
|
|
303
|
+
supportedChains: [cofhesdkArbSepolia],
|
|
304
|
+
useWorkers: true, // Config says use workers
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
const client = createCofhesdkClient(config);
|
|
308
|
+
await client.connect(publicClient, walletClient);
|
|
309
|
+
|
|
310
|
+
let proveContext: any;
|
|
311
|
+
const result = await client
|
|
312
|
+
.encryptInputs([Encryptable.uint8(42n)])
|
|
313
|
+
.setUseWorker(false) // But override to disable worker
|
|
314
|
+
.setStepCallback((step, context) => {
|
|
315
|
+
if (step === 'prove' && context?.isEnd) {
|
|
316
|
+
proveContext = context;
|
|
317
|
+
}
|
|
318
|
+
})
|
|
319
|
+
.encrypt();
|
|
320
|
+
|
|
321
|
+
expect(result).toBeDefined();
|
|
322
|
+
|
|
323
|
+
// Should NOT attempt worker at all
|
|
324
|
+
expect(proveContext.useWorker).toBe(false);
|
|
325
|
+
expect(proveContext.usedWorker).toBe(false);
|
|
326
|
+
expect(proveContext.workerFailedError).toBeUndefined();
|
|
327
|
+
}, 60000);
|
|
328
|
+
});
|
|
329
|
+
});
|