@cofhe/sdk 0.0.0-beta-20251027110729

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 (110) hide show
  1. package/CHANGELOG.md +47 -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 +37 -0
  9. package/adapters/index.test.ts +25 -0
  10. package/adapters/index.ts +5 -0
  11. package/adapters/smartWallet.ts +91 -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/sepolia.ts +14 -0
  20. package/chains/chains.test.ts +49 -0
  21. package/chains/defineChain.ts +18 -0
  22. package/chains/index.ts +33 -0
  23. package/chains/types.ts +32 -0
  24. package/core/baseBuilder.ts +138 -0
  25. package/core/client.test.ts +298 -0
  26. package/core/client.ts +308 -0
  27. package/core/config.test.ts +224 -0
  28. package/core/config.ts +213 -0
  29. package/core/decrypt/MockQueryDecrypterAbi.ts +129 -0
  30. package/core/decrypt/cofheMocksSealOutput.ts +57 -0
  31. package/core/decrypt/decryptHandleBuilder.ts +281 -0
  32. package/core/decrypt/decryptUtils.ts +28 -0
  33. package/core/decrypt/tnSealOutput.ts +59 -0
  34. package/core/encrypt/MockZkVerifierAbi.ts +106 -0
  35. package/core/encrypt/cofheMocksZkVerifySign.ts +278 -0
  36. package/core/encrypt/encryptInputsBuilder.test.ts +735 -0
  37. package/core/encrypt/encryptInputsBuilder.ts +512 -0
  38. package/core/encrypt/encryptUtils.ts +64 -0
  39. package/core/encrypt/zkPackProveVerify.ts +273 -0
  40. package/core/error.ts +170 -0
  41. package/core/fetchKeys.test.ts +212 -0
  42. package/core/fetchKeys.ts +170 -0
  43. package/core/index.ts +77 -0
  44. package/core/keyStore.test.ts +226 -0
  45. package/core/keyStore.ts +127 -0
  46. package/core/permits.test.ts +242 -0
  47. package/core/permits.ts +136 -0
  48. package/core/result.test.ts +180 -0
  49. package/core/result.ts +67 -0
  50. package/core/test-utils.ts +45 -0
  51. package/core/types.ts +352 -0
  52. package/core/utils.ts +88 -0
  53. package/dist/adapters.cjs +88 -0
  54. package/dist/adapters.d.cts +14558 -0
  55. package/dist/adapters.d.ts +14558 -0
  56. package/dist/adapters.js +83 -0
  57. package/dist/chains.cjs +101 -0
  58. package/dist/chains.d.cts +99 -0
  59. package/dist/chains.d.ts +99 -0
  60. package/dist/chains.js +1 -0
  61. package/dist/chunk-GZCQQYVI.js +93 -0
  62. package/dist/chunk-KFGPTJ6X.js +2295 -0
  63. package/dist/chunk-LU7BMUUT.js +804 -0
  64. package/dist/core.cjs +3174 -0
  65. package/dist/core.d.cts +16 -0
  66. package/dist/core.d.ts +16 -0
  67. package/dist/core.js +3 -0
  68. package/dist/node.cjs +3090 -0
  69. package/dist/node.d.cts +22 -0
  70. package/dist/node.d.ts +22 -0
  71. package/dist/node.js +90 -0
  72. package/dist/permit-S9CnI6MF.d.cts +333 -0
  73. package/dist/permit-S9CnI6MF.d.ts +333 -0
  74. package/dist/permits.cjs +856 -0
  75. package/dist/permits.d.cts +1056 -0
  76. package/dist/permits.d.ts +1056 -0
  77. package/dist/permits.js +1 -0
  78. package/dist/types-KImPrEIe.d.cts +48 -0
  79. package/dist/types-KImPrEIe.d.ts +48 -0
  80. package/dist/types-PhwGgQvs.d.ts +953 -0
  81. package/dist/types-bB7wLj0q.d.cts +953 -0
  82. package/dist/web.cjs +3067 -0
  83. package/dist/web.d.cts +22 -0
  84. package/dist/web.d.ts +22 -0
  85. package/dist/web.js +64 -0
  86. package/node/client.test.ts +152 -0
  87. package/node/config.test.ts +68 -0
  88. package/node/encryptInputs.test.ts +175 -0
  89. package/node/index.ts +96 -0
  90. package/node/storage.ts +51 -0
  91. package/package.json +120 -0
  92. package/permits/index.ts +67 -0
  93. package/permits/localstorage.test.ts +118 -0
  94. package/permits/permit.test.ts +474 -0
  95. package/permits/permit.ts +396 -0
  96. package/permits/sealing.test.ts +84 -0
  97. package/permits/sealing.ts +131 -0
  98. package/permits/signature.ts +79 -0
  99. package/permits/store.test.ts +128 -0
  100. package/permits/store.ts +168 -0
  101. package/permits/test-utils.ts +20 -0
  102. package/permits/types.ts +174 -0
  103. package/permits/utils.ts +63 -0
  104. package/permits/validation.test.ts +288 -0
  105. package/permits/validation.ts +349 -0
  106. package/web/client.web.test.ts +152 -0
  107. package/web/config.web.test.ts +71 -0
  108. package/web/encryptInputs.web.test.ts +195 -0
  109. package/web/index.ts +97 -0
  110. package/web/storage.ts +20 -0
@@ -0,0 +1,512 @@
1
+ /* eslint-disable no-unused-vars */
2
+
3
+ import { type ZkBuilderAndCrsGenerator, zkPack, zkProve, zkVerify } from './zkPackProveVerify.js';
4
+ import { CofhesdkError, CofhesdkErrorCode } from '../error.js';
5
+ import { type Result, resultWrapper } from '../result.js';
6
+ import {
7
+ type EncryptStepCallbackFunction,
8
+ EncryptStep,
9
+ type EncryptableItem,
10
+ type EncryptedItemInput,
11
+ type EncryptedItemInputs,
12
+ type TfheInitializer,
13
+ type EncryptStepCallbackContext,
14
+ } from '../types.js';
15
+ import { cofheMocksCheckEncryptableBits, cofheMocksZkVerifySign } from './cofheMocksZkVerifySign.js';
16
+ import { hardhat } from 'viem/chains';
17
+ import { fetchKeys, type FheKeyDeserializer } from '../fetchKeys.js';
18
+ import { getZkVerifierUrlOrThrow } from '../config.js';
19
+ import { type WalletClient } from 'viem';
20
+ import { sleep } from '../utils.js';
21
+ import { BaseBuilder, type BaseBuilderParams } from '../baseBuilder.js';
22
+ import { type KeysStorage } from '../keyStore.js';
23
+
24
+ type EncryptInputsBuilderParams<T extends EncryptableItem[]> = BaseBuilderParams & {
25
+ inputs: [...T];
26
+ securityZone?: number;
27
+
28
+ zkvWalletClient?: WalletClient | undefined;
29
+
30
+ tfhePublicKeyDeserializer: FheKeyDeserializer | undefined;
31
+ compactPkeCrsDeserializer: FheKeyDeserializer | undefined;
32
+ zkBuilderAndCrsGenerator: ZkBuilderAndCrsGenerator | undefined;
33
+ initTfhe: TfheInitializer | undefined;
34
+
35
+ keysStorage: KeysStorage | undefined;
36
+ };
37
+
38
+ /**
39
+ * EncryptInputsBuilder exposes a builder pattern for encrypting inputs.
40
+ * account, securityZone, and chainId can be overridden in the builder.
41
+ * config, tfhePublicKeyDeserializer, compactPkeCrsDeserializer, and zkBuilderAndCrsGenerator are required to be set in the builder.
42
+ *
43
+ * @dev All errors must be throw in `encrypt`, which wraps them in a Result.
44
+ * Do not throw errors in the constructor or in the builder methods.
45
+ */
46
+
47
+ export class EncryptInputsBuilder<T extends EncryptableItem[]> extends BaseBuilder {
48
+ private securityZone: number;
49
+ private stepCallback?: EncryptStepCallbackFunction;
50
+ private inputItems: [...T];
51
+
52
+ private zkvWalletClient: WalletClient | undefined;
53
+
54
+ private tfhePublicKeyDeserializer: FheKeyDeserializer | undefined;
55
+ private compactPkeCrsDeserializer: FheKeyDeserializer | undefined;
56
+ private zkBuilderAndCrsGenerator: ZkBuilderAndCrsGenerator | undefined;
57
+ private initTfhe: TfheInitializer | undefined;
58
+
59
+ private keysStorage: KeysStorage | undefined;
60
+
61
+ private stepTimestamps: Record<EncryptStep, number> = {
62
+ [EncryptStep.InitTfhe]: 0,
63
+ [EncryptStep.FetchKeys]: 0,
64
+ [EncryptStep.Pack]: 0,
65
+ [EncryptStep.Prove]: 0,
66
+ [EncryptStep.Verify]: 0,
67
+ };
68
+
69
+ constructor(params: EncryptInputsBuilderParams<T>) {
70
+ super({
71
+ config: params.config,
72
+ publicClient: params.publicClient,
73
+ walletClient: params.walletClient,
74
+ chainId: params.chainId,
75
+ account: params.account,
76
+ requireConnected: params.requireConnected,
77
+ });
78
+
79
+ this.inputItems = params.inputs;
80
+ this.securityZone = params.securityZone ?? 0;
81
+
82
+ this.zkvWalletClient = params.zkvWalletClient;
83
+
84
+ this.tfhePublicKeyDeserializer = params.tfhePublicKeyDeserializer;
85
+ this.compactPkeCrsDeserializer = params.compactPkeCrsDeserializer;
86
+ this.zkBuilderAndCrsGenerator = params.zkBuilderAndCrsGenerator;
87
+ this.initTfhe = params.initTfhe;
88
+
89
+ this.keysStorage = params.keysStorage;
90
+ }
91
+
92
+ /**
93
+ * @param account - Account that will create the tx using the encrypted inputs.
94
+ *
95
+ * If not provided, the account will be fetched from the connected walletClient.
96
+ *
97
+ * Example:
98
+ * ```typescript
99
+ * const encrypted = await encryptInputs([Encryptable.uint128(10n)])
100
+ * .setAccount("0x123")
101
+ * .encrypt();
102
+ * ```
103
+ *
104
+ * @returns The chainable EncryptInputsBuilder instance.
105
+ */
106
+ setAccount(account: string): EncryptInputsBuilder<T> {
107
+ this.account = account;
108
+ return this;
109
+ }
110
+
111
+ getAccount(): string | undefined {
112
+ return this.account;
113
+ }
114
+
115
+ /**
116
+ * @param chainId - Chain that will consume the encrypted inputs.
117
+ *
118
+ * If not provided, the chainId will be fetched from the connected publicClient.
119
+ *
120
+ * Example:
121
+ * ```typescript
122
+ * const encrypted = await encryptInputs([Encryptable.uint128(10n)])
123
+ * .setChainId(11155111)
124
+ * .encrypt();
125
+ * ```
126
+ *
127
+ * @returns The chainable EncryptInputsBuilder instance.
128
+ */
129
+ setChainId(chainId: number): EncryptInputsBuilder<T> {
130
+ this.chainId = chainId;
131
+ return this;
132
+ }
133
+
134
+ getChainId(): number | undefined {
135
+ return this.chainId;
136
+ }
137
+
138
+ /**
139
+ * @param securityZone - Security zone to encrypt the inputs for.
140
+ *
141
+ * If not provided, the default securityZone 0 will be used.
142
+ *
143
+ * Example:
144
+ * ```typescript
145
+ * const encrypted = await encryptInputs([Encryptable.uint128(10n)])
146
+ * .setSecurityZone(1)
147
+ * .encrypt();
148
+ * ```
149
+ *
150
+ * @returns The chainable EncryptInputsBuilder instance.
151
+ */
152
+ setSecurityZone(securityZone: number): EncryptInputsBuilder<T> {
153
+ this.securityZone = securityZone;
154
+ return this;
155
+ }
156
+
157
+ getSecurityZone(): number {
158
+ return this.securityZone;
159
+ }
160
+
161
+ /**
162
+ * @param callback - Function to be called with the encryption step.
163
+ *
164
+ * Useful for debugging and tracking the progress of the encryption process.
165
+ * Useful for a UI element that shows the progress of the encryption process.
166
+ *
167
+ * Example:
168
+ * ```typescript
169
+ * const encrypted = await encryptInputs([Encryptable.uint128(10n)])
170
+ * .setStepCallback((step: EncryptStep) => console.log(step))
171
+ * .encrypt();
172
+ * ```
173
+ *
174
+ * @returns The EncryptInputsBuilder instance.
175
+ */
176
+ setStepCallback(callback: EncryptStepCallbackFunction): EncryptInputsBuilder<T> {
177
+ this.stepCallback = callback;
178
+ return this;
179
+ }
180
+
181
+ getStepCallback(): EncryptStepCallbackFunction | undefined {
182
+ return this.stepCallback;
183
+ }
184
+
185
+ /**
186
+ * Fires the step callback if set
187
+ */
188
+ private fireStepStart(
189
+ step: EncryptStep,
190
+ context: Omit<EncryptStepCallbackContext, 'isStart' | 'isEnd' | 'duration'> = {}
191
+ ) {
192
+ if (!this.stepCallback) return;
193
+ this.stepTimestamps[step] = Date.now();
194
+ this.stepCallback(step, { ...context, isStart: true, isEnd: false, duration: 0 });
195
+ }
196
+ private fireStepEnd(
197
+ step: EncryptStep,
198
+ context: Omit<EncryptStepCallbackContext, 'isStart' | 'isEnd' | 'duration'> = {}
199
+ ) {
200
+ if (!this.stepCallback) return;
201
+ const duration = Date.now() - this.stepTimestamps[step];
202
+ this.stepCallback(step, { ...context, isStart: false, isEnd: true, duration });
203
+ }
204
+
205
+ /**
206
+ * tfhePublicKeyDeserializer is a platform-specific dependency injected into core/createCofhesdkClientBase by web/createCofhesdkClient and node/createCofhesdkClient
207
+ * web/ uses zama "tfhe"
208
+ * node/ uses zama "node-tfhe"
209
+ * Users should not set this manually.
210
+ */
211
+ private getTfhePublicKeyDeserializerOrThrow(): FheKeyDeserializer {
212
+ if (this.tfhePublicKeyDeserializer) return this.tfhePublicKeyDeserializer;
213
+ throw new CofhesdkError({
214
+ code: CofhesdkErrorCode.MissingTfhePublicKeyDeserializer,
215
+ message: 'EncryptInputsBuilder tfhePublicKeyDeserializer is undefined',
216
+ hint: 'Ensure client has been created with a tfhePublicKeyDeserializer.',
217
+ context: {
218
+ tfhePublicKeyDeserializer: this.tfhePublicKeyDeserializer,
219
+ },
220
+ });
221
+ }
222
+
223
+ /**
224
+ * compactPkeCrsDeserializer is a platform-specific dependency injected into core/createCofhesdkClientBase by web/createCofhesdkClient and node/createCofhesdkClient
225
+ * web/ uses zama "tfhe"
226
+ * node/ uses zama "node-tfhe"
227
+ * Users should not set this manually.
228
+ */
229
+ private getCompactPkeCrsDeserializerOrThrow(): FheKeyDeserializer {
230
+ if (this.compactPkeCrsDeserializer) return this.compactPkeCrsDeserializer;
231
+ throw new CofhesdkError({
232
+ code: CofhesdkErrorCode.MissingCompactPkeCrsDeserializer,
233
+ message: 'EncryptInputsBuilder compactPkeCrsDeserializer is undefined',
234
+ hint: 'Ensure client has been created with a compactPkeCrsDeserializer.',
235
+ context: {
236
+ compactPkeCrsDeserializer: this.compactPkeCrsDeserializer,
237
+ },
238
+ });
239
+ }
240
+
241
+ /**
242
+ * zkVerifierUrl is included in the chains exported from cofhesdk/chains for use in CofhesdkConfig.supportedChains
243
+ * Users should generally not set this manually.
244
+ */
245
+ private async getZkVerifierUrl(): Promise<string> {
246
+ const config = this.getConfigOrThrow();
247
+ const chainId = await this.getChainIdOrThrow();
248
+ return getZkVerifierUrlOrThrow(config, chainId);
249
+ }
250
+
251
+ /**
252
+ * initTfhe is a platform-specific dependency injected into core/createCofhesdkClientBase by web/createCofhesdkClient and node/createCofhesdkClient
253
+ * web/ uses zama "tfhe"
254
+ * node/ uses zama "node-tfhe"
255
+ * Users should not set this manually.
256
+ */
257
+ private async initTfheOrThrow(): Promise<boolean> {
258
+ if (!this.initTfhe) return false;
259
+
260
+ try {
261
+ return await this.initTfhe();
262
+ } catch (error) {
263
+ throw CofhesdkError.fromError(error, {
264
+ code: CofhesdkErrorCode.InitTfheFailed,
265
+ message: `Failed to initialize TFHE`,
266
+ context: {
267
+ initTfhe: this.initTfhe,
268
+ },
269
+ });
270
+ }
271
+ }
272
+
273
+ /**
274
+ * Fetches the FHE key and CRS from the CoFHE API
275
+ * If the key/crs already exists in the store it is returned, else it is fetched, stored, and returned
276
+ */
277
+ private async fetchFheKeyAndCrs(): Promise<{
278
+ fheKey: string;
279
+ fheKeyFetchedFromCoFHE: boolean;
280
+ crs: string;
281
+ crsFetchedFromCoFHE: boolean;
282
+ }> {
283
+ const config = this.getConfigOrThrow();
284
+ const chainId = await this.getChainIdOrThrow();
285
+ const compactPkeCrsDeserializer = this.getCompactPkeCrsDeserializerOrThrow();
286
+ const tfhePublicKeyDeserializer = this.getTfhePublicKeyDeserializerOrThrow();
287
+ const securityZone = this.getSecurityZone();
288
+
289
+ try {
290
+ await this.keysStorage?.rehydrateKeysStore();
291
+ } catch (error) {
292
+ throw CofhesdkError.fromError(error, {
293
+ code: CofhesdkErrorCode.RehydrateKeysStoreFailed,
294
+ message: `Failed to rehydrate keys store`,
295
+ context: {
296
+ keysStorage: this.keysStorage,
297
+ },
298
+ });
299
+ }
300
+
301
+ let fheKey: string | undefined;
302
+ let fheKeyFetchedFromCoFHE: boolean = false;
303
+ let crs: string | undefined;
304
+ let crsFetchedFromCoFHE: boolean = false;
305
+
306
+ try {
307
+ [[fheKey, fheKeyFetchedFromCoFHE], [crs, crsFetchedFromCoFHE]] = await fetchKeys(
308
+ config,
309
+ chainId,
310
+ securityZone,
311
+ tfhePublicKeyDeserializer,
312
+ compactPkeCrsDeserializer,
313
+ this.keysStorage
314
+ );
315
+ } catch (error) {
316
+ throw CofhesdkError.fromError(error, {
317
+ code: CofhesdkErrorCode.FetchKeysFailed,
318
+ message: `Failed to fetch FHE key and CRS`,
319
+ context: {
320
+ config,
321
+ chainId,
322
+ securityZone,
323
+ compactPkeCrsDeserializer,
324
+ tfhePublicKeyDeserializer,
325
+ },
326
+ });
327
+ }
328
+
329
+ if (!fheKey) {
330
+ throw new CofhesdkError({
331
+ code: CofhesdkErrorCode.MissingFheKey,
332
+ message: `FHE key not found`,
333
+ context: {
334
+ chainId,
335
+ securityZone,
336
+ },
337
+ });
338
+ }
339
+
340
+ if (!crs) {
341
+ throw new CofhesdkError({
342
+ code: CofhesdkErrorCode.MissingCrs,
343
+ message: `CRS not found for chainId <${this.chainId}>`,
344
+ context: {
345
+ chainId,
346
+ },
347
+ });
348
+ }
349
+
350
+ return { fheKey, fheKeyFetchedFromCoFHE, crs, crsFetchedFromCoFHE };
351
+ }
352
+
353
+ /**
354
+ * zkBuilderAndCrsGenerator is a platform-specific dependency injected into core/createCofhesdkClientBase by web/createCofhesdkClient and node/createCofhesdkClient
355
+ * web/ uses zama "tfhe"
356
+ * node/ uses zama "node-tfhe"
357
+ * Users should not set this manually.
358
+ *
359
+ * Generates the zkBuilder and zkCrs from the fheKey and crs
360
+ */
361
+ private generateZkBuilderAndCrs(fheKey: string, crs: string) {
362
+ const zkBuilderAndCrsGenerator = this.zkBuilderAndCrsGenerator;
363
+
364
+ if (!zkBuilderAndCrsGenerator) {
365
+ throw new CofhesdkError({
366
+ code: CofhesdkErrorCode.MissingZkBuilderAndCrsGenerator,
367
+ message: `zkBuilderAndCrsGenerator is undefined`,
368
+ hint: 'Ensure client has been created with a zkBuilderAndCrsGenerator.',
369
+ context: {
370
+ zkBuilderAndCrsGenerator: this.zkBuilderAndCrsGenerator,
371
+ },
372
+ });
373
+ }
374
+
375
+ return zkBuilderAndCrsGenerator(fheKey, crs);
376
+ }
377
+
378
+ /**
379
+ * @dev Encrypt against the cofheMocks instead of CoFHE
380
+ *
381
+ * In the cofheMocks, the MockZkVerifier contract is deployed on hardhat to a fixed address, this contract handles mocking the zk verifying.
382
+ * cofheMocksInsertPackedHashes - stores the ctHashes and their plaintext values for on-chain mocking of FHE operations.
383
+ * cofheMocksZkCreateProofSignatures - creates signatures to be included in the encrypted inputs. The signers address is known and verified in the mock contracts.
384
+ */
385
+ private async mocksEncrypt(account: string): Promise<[...EncryptedItemInputs<T>]> {
386
+ this.fireStepStart(EncryptStep.InitTfhe);
387
+ await sleep(100);
388
+ this.fireStepEnd(EncryptStep.InitTfhe, { tfheInitializationExecuted: false });
389
+
390
+ this.fireStepStart(EncryptStep.FetchKeys);
391
+ await sleep(100);
392
+ this.fireStepEnd(EncryptStep.FetchKeys, { fheKeyFetchedFromCoFHE: false, crsFetchedFromCoFHE: false });
393
+
394
+ this.fireStepStart(EncryptStep.Pack);
395
+ await cofheMocksCheckEncryptableBits(this.inputItems);
396
+ await sleep(100);
397
+ this.fireStepEnd(EncryptStep.Pack);
398
+
399
+ this.fireStepStart(EncryptStep.Prove);
400
+ await sleep(500);
401
+ this.fireStepEnd(EncryptStep.Prove);
402
+
403
+ this.fireStepStart(EncryptStep.Verify);
404
+ await sleep(500);
405
+ const signedResults = await cofheMocksZkVerifySign(
406
+ this.inputItems,
407
+ account,
408
+ this.securityZone,
409
+ this.getPublicClientOrThrow(),
410
+ this.getWalletClientOrThrow(),
411
+ this.zkvWalletClient
412
+ );
413
+ const encryptedInputs: EncryptedItemInput[] = signedResults.map(({ ct_hash, signature }, index) => ({
414
+ ctHash: BigInt(ct_hash),
415
+ securityZone: this.securityZone,
416
+ utype: this.inputItems[index].utype,
417
+ signature,
418
+ }));
419
+ this.fireStepEnd(EncryptStep.Verify);
420
+
421
+ return encryptedInputs as [...EncryptedItemInputs<T>];
422
+ }
423
+
424
+ /**
425
+ * In the production context, perform a true encryption with the CoFHE coprocessor.
426
+ */
427
+ private async productionEncrypt(account: string, chainId: number): Promise<[...EncryptedItemInputs<T>]> {
428
+ this.fireStepStart(EncryptStep.InitTfhe);
429
+
430
+ // Deferred initialization of tfhe wasm until encrypt is called
431
+ // Returns true if tfhe was initialized, false if already initialized
432
+ const tfheInitializationExecuted = await this.initTfheOrThrow();
433
+
434
+ this.fireStepEnd(EncryptStep.InitTfhe, { tfheInitializationExecuted });
435
+
436
+ this.fireStepStart(EncryptStep.FetchKeys);
437
+
438
+ // Deferred fetching of fheKey and crs until encrypt is called
439
+ // if the key/crs is already in the store, it is not fetched from the CoFHE API
440
+ const { fheKey, fheKeyFetchedFromCoFHE, crs, crsFetchedFromCoFHE } = await this.fetchFheKeyAndCrs();
441
+ let { zkBuilder, zkCrs } = this.generateZkBuilderAndCrs(fheKey, crs);
442
+
443
+ this.fireStepEnd(EncryptStep.FetchKeys, { fheKeyFetchedFromCoFHE, crsFetchedFromCoFHE });
444
+
445
+ this.fireStepStart(EncryptStep.Pack);
446
+
447
+ zkBuilder = zkPack(this.inputItems, zkBuilder);
448
+
449
+ this.fireStepEnd(EncryptStep.Pack);
450
+
451
+ this.fireStepStart(EncryptStep.Prove);
452
+
453
+ const proof = await zkProve(zkBuilder, zkCrs, account, this.securityZone, chainId);
454
+
455
+ this.fireStepEnd(EncryptStep.Prove);
456
+
457
+ this.fireStepStart(EncryptStep.Verify);
458
+
459
+ const zkVerifierUrl = await this.getZkVerifierUrl();
460
+
461
+ const verifyResults = await zkVerify(zkVerifierUrl, proof, account, this.securityZone, chainId);
462
+ // Add securityZone and utype to the verify results
463
+ const encryptedInputs: EncryptedItemInput[] = verifyResults.map(
464
+ ({ ct_hash, signature }: { ct_hash: string; signature: string }, index: number) => ({
465
+ ctHash: BigInt(ct_hash),
466
+ securityZone: this.securityZone,
467
+ utype: this.inputItems[index].utype,
468
+ signature,
469
+ })
470
+ );
471
+
472
+ this.fireStepEnd(EncryptStep.Verify);
473
+
474
+ return encryptedInputs as [...EncryptedItemInputs<T>];
475
+ }
476
+
477
+ /**
478
+ * Final step of the encryption process. MUST BE CALLED LAST IN THE CHAIN.
479
+ *
480
+ * This will:
481
+ * - Pack the encryptable items into a zk proof
482
+ * - Prove the zk proof
483
+ * - Verify the zk proof with CoFHE
484
+ * - Package and return the encrypted inputs
485
+ *
486
+ * Example:
487
+ * ```typescript
488
+ * const encrypted = await encryptInputs([Encryptable.uint128(10n)])
489
+ * .setAccount('0x123...890') // optional
490
+ * .setChainId(11155111) // optional
491
+ * .encrypt(); // execute
492
+ * ```
493
+ *
494
+ * @returns The encrypted inputs.
495
+ */
496
+ async encrypt(): Promise<Result<[...EncryptedItemInputs<T>]>> {
497
+ return resultWrapper(async () => {
498
+ // Ensure cofhe client is connected
499
+ await this.requireConnectedOrThrow();
500
+
501
+ const account = await this.getAccountOrThrow();
502
+ const chainId = await this.getChainIdOrThrow();
503
+
504
+ // On hardhat, interact with MockZkVerifier contract instead of CoFHE
505
+ if (chainId === hardhat.id) {
506
+ return await this.mocksEncrypt(account);
507
+ }
508
+
509
+ return await this.productionEncrypt(account, chainId);
510
+ });
511
+ }
512
+ }
@@ -0,0 +1,64 @@
1
+ /* eslint-disable no-redeclare */
2
+ /* eslint-disable no-unused-vars */
3
+
4
+ import { type EncryptableItem, isEncryptableItem, type EncryptedItemInput, type EncryptedItemInputs } from '../types.js';
5
+
6
+ export function encryptExtract<T>(item: T): EncryptableItem[];
7
+ export function encryptExtract<T extends any[]>(item: [...T]): EncryptableItem[];
8
+ export function encryptExtract<T>(item: T) {
9
+ if (isEncryptableItem(item)) {
10
+ return item;
11
+ }
12
+
13
+ // Object | Array
14
+ if (typeof item === 'object' && item !== null) {
15
+ if (Array.isArray(item)) {
16
+ // Array - recurse
17
+ return item.flatMap((nestedItem) => encryptExtract(nestedItem));
18
+ } else {
19
+ // Object - recurse
20
+ return Object.values(item).flatMap((value) => encryptExtract(value));
21
+ }
22
+ }
23
+
24
+ return [];
25
+ }
26
+
27
+ export function encryptReplace<T>(
28
+ item: T,
29
+ encryptedItems: EncryptedItemInput[]
30
+ ): [EncryptedItemInputs<T>, EncryptedItemInput[]];
31
+ export function encryptReplace<T extends any[]>(
32
+ item: [...T],
33
+ encryptedItems: EncryptedItemInput[]
34
+ ): [...EncryptedItemInputs<T>, EncryptedItemInput[]];
35
+ export function encryptReplace<T>(item: T, encryptedItems: EncryptedItemInput[]) {
36
+ if (isEncryptableItem(item)) {
37
+ return [encryptedItems[0], encryptedItems.slice(1)];
38
+ }
39
+
40
+ // Object | Array
41
+ if (typeof item === 'object' && item !== null) {
42
+ if (Array.isArray(item)) {
43
+ // Array - recurse
44
+ return item.reduce<[any[], EncryptedItemInput[]]>(
45
+ ([acc, remaining], item) => {
46
+ const [newItem, newRemaining] = encryptReplace(item, remaining);
47
+ return [[...acc, newItem], newRemaining];
48
+ },
49
+ [[], encryptedItems]
50
+ );
51
+ } else {
52
+ // Object - recurse
53
+ return Object.entries(item).reduce<[Record<string, any>, EncryptedItemInput[]]>(
54
+ ([acc, remaining], [key, value]) => {
55
+ const [newValue, newRemaining] = encryptReplace(value, remaining);
56
+ return [{ ...acc, [key]: newValue }, newRemaining];
57
+ },
58
+ [{}, encryptedItems]
59
+ );
60
+ }
61
+ }
62
+
63
+ return [item, encryptedItems];
64
+ }