@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.
- package/CHANGELOG.md +47 -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 +37 -0
- package/adapters/index.test.ts +25 -0
- package/adapters/index.ts +5 -0
- package/adapters/smartWallet.ts +91 -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/sepolia.ts +14 -0
- package/chains/chains.test.ts +49 -0
- package/chains/defineChain.ts +18 -0
- package/chains/index.ts +33 -0
- package/chains/types.ts +32 -0
- package/core/baseBuilder.ts +138 -0
- package/core/client.test.ts +298 -0
- package/core/client.ts +308 -0
- package/core/config.test.ts +224 -0
- package/core/config.ts +213 -0
- package/core/decrypt/MockQueryDecrypterAbi.ts +129 -0
- package/core/decrypt/cofheMocksSealOutput.ts +57 -0
- package/core/decrypt/decryptHandleBuilder.ts +281 -0
- package/core/decrypt/decryptUtils.ts +28 -0
- package/core/decrypt/tnSealOutput.ts +59 -0
- package/core/encrypt/MockZkVerifierAbi.ts +106 -0
- package/core/encrypt/cofheMocksZkVerifySign.ts +278 -0
- package/core/encrypt/encryptInputsBuilder.test.ts +735 -0
- package/core/encrypt/encryptInputsBuilder.ts +512 -0
- package/core/encrypt/encryptUtils.ts +64 -0
- package/core/encrypt/zkPackProveVerify.ts +273 -0
- package/core/error.ts +170 -0
- package/core/fetchKeys.test.ts +212 -0
- package/core/fetchKeys.ts +170 -0
- package/core/index.ts +77 -0
- package/core/keyStore.test.ts +226 -0
- package/core/keyStore.ts +127 -0
- package/core/permits.test.ts +242 -0
- package/core/permits.ts +136 -0
- package/core/result.test.ts +180 -0
- package/core/result.ts +67 -0
- package/core/test-utils.ts +45 -0
- package/core/types.ts +352 -0
- package/core/utils.ts +88 -0
- package/dist/adapters.cjs +88 -0
- package/dist/adapters.d.cts +14558 -0
- package/dist/adapters.d.ts +14558 -0
- package/dist/adapters.js +83 -0
- package/dist/chains.cjs +101 -0
- package/dist/chains.d.cts +99 -0
- package/dist/chains.d.ts +99 -0
- package/dist/chains.js +1 -0
- package/dist/chunk-GZCQQYVI.js +93 -0
- package/dist/chunk-KFGPTJ6X.js +2295 -0
- package/dist/chunk-LU7BMUUT.js +804 -0
- package/dist/core.cjs +3174 -0
- package/dist/core.d.cts +16 -0
- package/dist/core.d.ts +16 -0
- package/dist/core.js +3 -0
- package/dist/node.cjs +3090 -0
- package/dist/node.d.cts +22 -0
- package/dist/node.d.ts +22 -0
- package/dist/node.js +90 -0
- package/dist/permit-S9CnI6MF.d.cts +333 -0
- package/dist/permit-S9CnI6MF.d.ts +333 -0
- package/dist/permits.cjs +856 -0
- package/dist/permits.d.cts +1056 -0
- package/dist/permits.d.ts +1056 -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/types-PhwGgQvs.d.ts +953 -0
- package/dist/types-bB7wLj0q.d.cts +953 -0
- package/dist/web.cjs +3067 -0
- package/dist/web.d.cts +22 -0
- package/dist/web.d.ts +22 -0
- package/dist/web.js +64 -0
- package/node/client.test.ts +152 -0
- package/node/config.test.ts +68 -0
- package/node/encryptInputs.test.ts +175 -0
- package/node/index.ts +96 -0
- package/node/storage.ts +51 -0
- package/package.json +120 -0
- package/permits/index.ts +67 -0
- package/permits/localstorage.test.ts +118 -0
- package/permits/permit.test.ts +474 -0
- package/permits/permit.ts +396 -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 +168 -0
- package/permits/test-utils.ts +20 -0
- package/permits/types.ts +174 -0
- package/permits/utils.ts +63 -0
- package/permits/validation.test.ts +288 -0
- package/permits/validation.ts +349 -0
- package/web/client.web.test.ts +152 -0
- package/web/config.web.test.ts +71 -0
- package/web/encryptInputs.web.test.ts +195 -0
- package/web/index.ts +97 -0
- 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
|
+
}
|