@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,2295 @@
|
|
|
1
|
+
import { hardhat } from './chunk-GZCQQYVI.js';
|
|
2
|
+
import { permitStore, PermitUtils } from './chunk-LU7BMUUT.js';
|
|
3
|
+
import { createStore } from 'zustand/vanilla';
|
|
4
|
+
import { getAddress, http, createWalletClient, encodePacked, keccak256, toBytes, hashMessage } from 'viem';
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { hardhat as hardhat$1 } from 'viem/chains';
|
|
7
|
+
import { privateKeyToAccount } from 'viem/accounts';
|
|
8
|
+
import { persist, createJSONStorage } from 'zustand/middleware';
|
|
9
|
+
import { produce } from 'immer';
|
|
10
|
+
|
|
11
|
+
// core/error.ts
|
|
12
|
+
var CofhesdkErrorCode = /* @__PURE__ */ ((CofhesdkErrorCode2) => {
|
|
13
|
+
CofhesdkErrorCode2["InternalError"] = "INTERNAL_ERROR";
|
|
14
|
+
CofhesdkErrorCode2["UnknownEnvironment"] = "UNKNOWN_ENVIRONMENT";
|
|
15
|
+
CofhesdkErrorCode2["InitTfheFailed"] = "INIT_TFHE_FAILED";
|
|
16
|
+
CofhesdkErrorCode2["InitViemFailed"] = "INIT_VIEM_FAILED";
|
|
17
|
+
CofhesdkErrorCode2["InitEthersFailed"] = "INIT_ETHERS_FAILED";
|
|
18
|
+
CofhesdkErrorCode2["NotConnected"] = "NOT_CONNECTED";
|
|
19
|
+
CofhesdkErrorCode2["MissingPublicClient"] = "MISSING_PUBLIC_CLIENT";
|
|
20
|
+
CofhesdkErrorCode2["MissingWalletClient"] = "MISSING_WALLET_CLIENT";
|
|
21
|
+
CofhesdkErrorCode2["MissingProviderParam"] = "MISSING_PROVIDER_PARAM";
|
|
22
|
+
CofhesdkErrorCode2["EmptySecurityZonesParam"] = "EMPTY_SECURITY_ZONES_PARAM";
|
|
23
|
+
CofhesdkErrorCode2["InvalidPermitData"] = "INVALID_PERMIT_DATA";
|
|
24
|
+
CofhesdkErrorCode2["InvalidPermitDomain"] = "INVALID_PERMIT_DOMAIN";
|
|
25
|
+
CofhesdkErrorCode2["PermitNotFound"] = "PERMIT_NOT_FOUND";
|
|
26
|
+
CofhesdkErrorCode2["CannotRemoveLastPermit"] = "CANNOT_REMOVE_LAST_PERMIT";
|
|
27
|
+
CofhesdkErrorCode2["AccountUninitialized"] = "ACCOUNT_UNINITIALIZED";
|
|
28
|
+
CofhesdkErrorCode2["ChainIdUninitialized"] = "CHAIN_ID_UNINITIALIZED";
|
|
29
|
+
CofhesdkErrorCode2["SealOutputFailed"] = "SEAL_OUTPUT_FAILED";
|
|
30
|
+
CofhesdkErrorCode2["SealOutputReturnedNull"] = "SEAL_OUTPUT_RETURNED_NULL";
|
|
31
|
+
CofhesdkErrorCode2["InvalidUtype"] = "INVALID_UTYPE";
|
|
32
|
+
CofhesdkErrorCode2["DecryptFailed"] = "DECRYPT_FAILED";
|
|
33
|
+
CofhesdkErrorCode2["DecryptReturnedNull"] = "DECRYPT_RETURNED_NULL";
|
|
34
|
+
CofhesdkErrorCode2["ZkMocksInsertCtHashesFailed"] = "ZK_MOCKS_INSERT_CT_HASHES_FAILED";
|
|
35
|
+
CofhesdkErrorCode2["ZkMocksCalcCtHashesFailed"] = "ZK_MOCKS_CALC_CT_HASHES_FAILED";
|
|
36
|
+
CofhesdkErrorCode2["ZkMocksVerifySignFailed"] = "ZK_MOCKS_VERIFY_SIGN_FAILED";
|
|
37
|
+
CofhesdkErrorCode2["ZkMocksCreateProofSignatureFailed"] = "ZK_MOCKS_CREATE_PROOF_SIGNATURE_FAILED";
|
|
38
|
+
CofhesdkErrorCode2["ZkVerifyFailed"] = "ZK_VERIFY_FAILED";
|
|
39
|
+
CofhesdkErrorCode2["ZkPackFailed"] = "ZK_PACK_FAILED";
|
|
40
|
+
CofhesdkErrorCode2["ZkProveFailed"] = "ZK_PROVE_FAILED";
|
|
41
|
+
CofhesdkErrorCode2["EncryptRemainingInItems"] = "ENCRYPT_REMAINING_IN_ITEMS";
|
|
42
|
+
CofhesdkErrorCode2["ZkUninitialized"] = "ZK_UNINITIALIZED";
|
|
43
|
+
CofhesdkErrorCode2["ZkVerifierUrlUninitialized"] = "ZK_VERIFIER_URL_UNINITIALIZED";
|
|
44
|
+
CofhesdkErrorCode2["ThresholdNetworkUrlUninitialized"] = "THRESHOLD_NETWORK_URL_UNINITIALIZED";
|
|
45
|
+
CofhesdkErrorCode2["MissingConfig"] = "MISSING_CONFIG";
|
|
46
|
+
CofhesdkErrorCode2["UnsupportedChain"] = "UNSUPPORTED_CHAIN";
|
|
47
|
+
CofhesdkErrorCode2["MissingZkBuilderAndCrsGenerator"] = "MISSING_ZK_BUILDER_AND_CRS_GENERATOR";
|
|
48
|
+
CofhesdkErrorCode2["MissingTfhePublicKeyDeserializer"] = "MISSING_TFHE_PUBLIC_KEY_DESERIALIZER";
|
|
49
|
+
CofhesdkErrorCode2["MissingCompactPkeCrsDeserializer"] = "MISSING_COMPACT_PKE_CRS_DESERIALIZER";
|
|
50
|
+
CofhesdkErrorCode2["MissingFheKey"] = "MISSING_FHE_KEY";
|
|
51
|
+
CofhesdkErrorCode2["MissingCrs"] = "MISSING_CRS";
|
|
52
|
+
CofhesdkErrorCode2["FetchKeysFailed"] = "FETCH_KEYS_FAILED";
|
|
53
|
+
CofhesdkErrorCode2["PublicWalletGetChainIdFailed"] = "PUBLIC_WALLET_GET_CHAIN_ID_FAILED";
|
|
54
|
+
CofhesdkErrorCode2["PublicWalletGetAddressesFailed"] = "PUBLIC_WALLET_GET_ADDRESSES_FAILED";
|
|
55
|
+
CofhesdkErrorCode2["RehydrateKeysStoreFailed"] = "REHYDRATE_KEYS_STORE_FAILED";
|
|
56
|
+
return CofhesdkErrorCode2;
|
|
57
|
+
})(CofhesdkErrorCode || {});
|
|
58
|
+
var CofhesdkError = class _CofhesdkError extends Error {
|
|
59
|
+
code;
|
|
60
|
+
cause;
|
|
61
|
+
hint;
|
|
62
|
+
context;
|
|
63
|
+
constructor({ code, message, cause, hint, context }) {
|
|
64
|
+
const fullMessage = cause ? `${message} | Caused by: ${cause.message}` : message;
|
|
65
|
+
super(fullMessage);
|
|
66
|
+
this.name = "CofhesdkError";
|
|
67
|
+
this.code = code;
|
|
68
|
+
this.cause = cause;
|
|
69
|
+
this.hint = hint;
|
|
70
|
+
this.context = context;
|
|
71
|
+
if (Error.captureStackTrace) {
|
|
72
|
+
Error.captureStackTrace(this, _CofhesdkError);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Creates a CofhesdkError from an unknown error
|
|
77
|
+
* If the error is a CofhesdkError, it is returned unchanged, else a new CofhesdkError is created
|
|
78
|
+
* If a wrapperError is provided, it is used to create the new CofhesdkError, else a default is used
|
|
79
|
+
*/
|
|
80
|
+
static fromError(error, wrapperError) {
|
|
81
|
+
if (isCofhesdkError(error))
|
|
82
|
+
return error;
|
|
83
|
+
const cause = error instanceof Error ? error : new Error(`${error}`);
|
|
84
|
+
return new _CofhesdkError({
|
|
85
|
+
code: wrapperError?.code ?? "INTERNAL_ERROR" /* InternalError */,
|
|
86
|
+
message: wrapperError?.message ?? "An internal error occurred",
|
|
87
|
+
hint: wrapperError?.hint,
|
|
88
|
+
context: wrapperError?.context,
|
|
89
|
+
cause
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Serializes the error to JSON string with proper handling of Error objects
|
|
94
|
+
*/
|
|
95
|
+
serialize() {
|
|
96
|
+
return bigintSafeJsonStringify({
|
|
97
|
+
name: this.name,
|
|
98
|
+
code: this.code,
|
|
99
|
+
message: this.message,
|
|
100
|
+
hint: this.hint,
|
|
101
|
+
context: this.context,
|
|
102
|
+
cause: this.cause ? {
|
|
103
|
+
name: this.cause.name,
|
|
104
|
+
message: this.cause.message,
|
|
105
|
+
stack: this.cause.stack
|
|
106
|
+
} : void 0,
|
|
107
|
+
stack: this.stack
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Returns a human-readable string representation of the error
|
|
112
|
+
*/
|
|
113
|
+
toString() {
|
|
114
|
+
const parts = [`${this.name} [${this.code}]: ${this.message}`];
|
|
115
|
+
if (this.hint) {
|
|
116
|
+
parts.push(`Hint: ${this.hint}`);
|
|
117
|
+
}
|
|
118
|
+
if (this.context && Object.keys(this.context).length > 0) {
|
|
119
|
+
parts.push(`Context: ${bigintSafeJsonStringify(this.context)}`);
|
|
120
|
+
}
|
|
121
|
+
if (this.stack) {
|
|
122
|
+
parts.push(`
|
|
123
|
+
Stack trace:`);
|
|
124
|
+
parts.push(this.stack);
|
|
125
|
+
}
|
|
126
|
+
if (this.cause) {
|
|
127
|
+
parts.push(`
|
|
128
|
+
Caused by: ${this.cause.name}: ${this.cause.message}`);
|
|
129
|
+
if (this.cause.stack) {
|
|
130
|
+
parts.push(this.cause.stack);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return parts.join("\n");
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
var bigintSafeJsonStringify = (value) => {
|
|
137
|
+
return JSON.stringify(value, (key, value2) => {
|
|
138
|
+
if (typeof value2 === "bigint") {
|
|
139
|
+
return `${value2}n`;
|
|
140
|
+
}
|
|
141
|
+
return value2;
|
|
142
|
+
});
|
|
143
|
+
};
|
|
144
|
+
var isCofhesdkError = (error) => error instanceof CofhesdkError;
|
|
145
|
+
|
|
146
|
+
// core/result.ts
|
|
147
|
+
var ResultErr = (error) => ({
|
|
148
|
+
success: false,
|
|
149
|
+
data: null,
|
|
150
|
+
error
|
|
151
|
+
});
|
|
152
|
+
var ResultOk = (data) => ({
|
|
153
|
+
success: true,
|
|
154
|
+
data,
|
|
155
|
+
error: null
|
|
156
|
+
});
|
|
157
|
+
var ResultErrOrInternal = (error) => {
|
|
158
|
+
return ResultErr(CofhesdkError.fromError(error));
|
|
159
|
+
};
|
|
160
|
+
var ResultHttpError = (error, url, status) => {
|
|
161
|
+
if (error instanceof CofhesdkError)
|
|
162
|
+
return error;
|
|
163
|
+
const message = status ? `HTTP error ${status} from ${url}` : `HTTP request failed for ${url}`;
|
|
164
|
+
return new CofhesdkError({
|
|
165
|
+
code: "INTERNAL_ERROR" /* InternalError */,
|
|
166
|
+
message,
|
|
167
|
+
cause: error instanceof Error ? error : void 0
|
|
168
|
+
});
|
|
169
|
+
};
|
|
170
|
+
var ResultValidationError = (message) => {
|
|
171
|
+
return new CofhesdkError({
|
|
172
|
+
code: "INVALID_PERMIT_DATA" /* InvalidPermitData */,
|
|
173
|
+
message
|
|
174
|
+
});
|
|
175
|
+
};
|
|
176
|
+
var resultWrapper = async (tryFn, catchFn, finallyFn) => {
|
|
177
|
+
try {
|
|
178
|
+
const result = await tryFn();
|
|
179
|
+
return ResultOk(result);
|
|
180
|
+
} catch (error) {
|
|
181
|
+
const result = ResultErrOrInternal(error);
|
|
182
|
+
catchFn?.(result.error);
|
|
183
|
+
return result;
|
|
184
|
+
} finally {
|
|
185
|
+
finallyFn?.();
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
var resultWrapperSync = (fn) => {
|
|
189
|
+
try {
|
|
190
|
+
const result = fn();
|
|
191
|
+
return ResultOk(result);
|
|
192
|
+
} catch (error) {
|
|
193
|
+
return ResultErrOrInternal(error);
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
var storeActivePermit = async (permit, publicClient, walletClient) => {
|
|
197
|
+
const chainId = await publicClient.getChainId();
|
|
198
|
+
const account = walletClient.account.address;
|
|
199
|
+
permitStore.setPermit(chainId, account, permit);
|
|
200
|
+
permitStore.setActivePermitHash(chainId, account, PermitUtils.getHash(permit));
|
|
201
|
+
};
|
|
202
|
+
var createPermitWithSign = async (options, publicClient, walletClient, permitMethod) => {
|
|
203
|
+
const permit = await permitMethod(options, publicClient, walletClient);
|
|
204
|
+
await storeActivePermit(permit, publicClient, walletClient);
|
|
205
|
+
return permit;
|
|
206
|
+
};
|
|
207
|
+
var createSelf = async (options, publicClient, walletClient) => {
|
|
208
|
+
return createPermitWithSign(options, publicClient, walletClient, PermitUtils.createSelfAndSign);
|
|
209
|
+
};
|
|
210
|
+
var createSharing = async (options, publicClient, walletClient) => {
|
|
211
|
+
return createPermitWithSign(options, publicClient, walletClient, PermitUtils.createSharingAndSign);
|
|
212
|
+
};
|
|
213
|
+
var importShared = async (options, publicClient, walletClient) => {
|
|
214
|
+
return createPermitWithSign(options, publicClient, walletClient, PermitUtils.importSharedAndSign);
|
|
215
|
+
};
|
|
216
|
+
var getHash = (permit) => {
|
|
217
|
+
return PermitUtils.getHash(permit);
|
|
218
|
+
};
|
|
219
|
+
var serialize = (permit) => {
|
|
220
|
+
return PermitUtils.serialize(permit);
|
|
221
|
+
};
|
|
222
|
+
var deserialize = (serialized) => {
|
|
223
|
+
return PermitUtils.deserialize(serialized);
|
|
224
|
+
};
|
|
225
|
+
var getPermit = async (chainId, account, hash) => {
|
|
226
|
+
return permitStore.getPermit(chainId, account, hash);
|
|
227
|
+
};
|
|
228
|
+
var getPermits = async (chainId, account) => {
|
|
229
|
+
return permitStore.getPermits(chainId, account);
|
|
230
|
+
};
|
|
231
|
+
var getActivePermit = async (chainId, account) => {
|
|
232
|
+
return permitStore.getActivePermit(chainId, account);
|
|
233
|
+
};
|
|
234
|
+
var getActivePermitHash = async (chainId, account) => {
|
|
235
|
+
return permitStore.getActivePermitHash(chainId, account);
|
|
236
|
+
};
|
|
237
|
+
var selectActivePermit = async (chainId, account, hash) => {
|
|
238
|
+
await permitStore.setActivePermitHash(chainId, account, hash);
|
|
239
|
+
};
|
|
240
|
+
var removePermit = async (chainId, account, hash) => {
|
|
241
|
+
await permitStore.removePermit(chainId, account, hash);
|
|
242
|
+
};
|
|
243
|
+
var removeActivePermit = async (chainId, account) => {
|
|
244
|
+
await permitStore.removeActivePermitHash(chainId, account);
|
|
245
|
+
};
|
|
246
|
+
var permits = {
|
|
247
|
+
getSnapshot: permitStore.store.getState,
|
|
248
|
+
subscribe: permitStore.store.subscribe,
|
|
249
|
+
createSelf,
|
|
250
|
+
createSharing,
|
|
251
|
+
importShared,
|
|
252
|
+
getHash,
|
|
253
|
+
serialize,
|
|
254
|
+
deserialize,
|
|
255
|
+
getPermit,
|
|
256
|
+
getPermits,
|
|
257
|
+
getActivePermit,
|
|
258
|
+
getActivePermitHash,
|
|
259
|
+
removePermit,
|
|
260
|
+
selectActivePermit,
|
|
261
|
+
removeActivePermit
|
|
262
|
+
};
|
|
263
|
+
function uint160ToAddress(uint160) {
|
|
264
|
+
const hexStr = uint160.toString(16).padStart(40, "0");
|
|
265
|
+
return getAddress("0x" + hexStr);
|
|
266
|
+
}
|
|
267
|
+
var isValidUtype = (utype) => {
|
|
268
|
+
return utype === 0 /* Bool */ || utype === 7 /* Uint160 */ || utype == null || FheUintUTypes.includes(utype);
|
|
269
|
+
};
|
|
270
|
+
var convertViaUtype = (utype, value) => {
|
|
271
|
+
if (utype === 0 /* Bool */) {
|
|
272
|
+
return !!value;
|
|
273
|
+
} else if (utype === 7 /* Uint160 */) {
|
|
274
|
+
return uint160ToAddress(value);
|
|
275
|
+
} else if (utype == null || FheUintUTypes.includes(utype)) {
|
|
276
|
+
return value;
|
|
277
|
+
} else {
|
|
278
|
+
throw new Error(`convertViaUtype :: invalid utype :: ${utype}`);
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
var BaseBuilder = class {
|
|
282
|
+
config;
|
|
283
|
+
publicClient;
|
|
284
|
+
walletClient;
|
|
285
|
+
chainId;
|
|
286
|
+
account;
|
|
287
|
+
requireConnected;
|
|
288
|
+
constructor(params) {
|
|
289
|
+
this.config = params.config;
|
|
290
|
+
this.publicClient = params.publicClient;
|
|
291
|
+
this.walletClient = params.walletClient;
|
|
292
|
+
this.chainId = params.chainId;
|
|
293
|
+
this.account = params.account;
|
|
294
|
+
this.requireConnected = params.requireConnected;
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Gets the chain ID from the instance or fetches it from the public client
|
|
298
|
+
* @returns The chain ID
|
|
299
|
+
* @throws {CofhesdkError} If chainId is not set and publicClient is not available
|
|
300
|
+
*/
|
|
301
|
+
async getChainIdOrThrow() {
|
|
302
|
+
if (this.chainId)
|
|
303
|
+
return this.chainId;
|
|
304
|
+
throw new CofhesdkError({
|
|
305
|
+
code: "CHAIN_ID_UNINITIALIZED" /* ChainIdUninitialized */,
|
|
306
|
+
message: "Chain ID is not set",
|
|
307
|
+
hint: "Ensure client.connect() has been called and awaited, or use setChainId(...) to set the chainId explicitly.",
|
|
308
|
+
context: {
|
|
309
|
+
chainId: this.chainId
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Gets the account address from the instance or fetches it from the wallet client
|
|
315
|
+
* @returns The account address
|
|
316
|
+
* @throws {CofhesdkError} If account is not set and walletClient is not available
|
|
317
|
+
*/
|
|
318
|
+
async getAccountOrThrow() {
|
|
319
|
+
if (this.account)
|
|
320
|
+
return this.account;
|
|
321
|
+
throw new CofhesdkError({
|
|
322
|
+
code: "ACCOUNT_UNINITIALIZED" /* AccountUninitialized */,
|
|
323
|
+
message: "Account is not set",
|
|
324
|
+
hint: "Ensure client.connect() has been called and awaited, or use setAccount(...) to set the account explicitly.",
|
|
325
|
+
context: {
|
|
326
|
+
account: this.account
|
|
327
|
+
}
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Gets the config or throws an error if not available
|
|
332
|
+
* @returns The config
|
|
333
|
+
* @throws {CofhesdkError} If config is not set
|
|
334
|
+
*/
|
|
335
|
+
getConfigOrThrow() {
|
|
336
|
+
if (this.config)
|
|
337
|
+
return this.config;
|
|
338
|
+
throw new CofhesdkError({
|
|
339
|
+
code: "MISSING_CONFIG" /* MissingConfig */,
|
|
340
|
+
message: "Builder config is undefined",
|
|
341
|
+
hint: "Ensure client has been created with a config.",
|
|
342
|
+
context: {
|
|
343
|
+
config: this.config
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Gets the public client or throws an error if not available
|
|
349
|
+
* @returns The public client
|
|
350
|
+
* @throws {CofhesdkError} If publicClient is not set
|
|
351
|
+
*/
|
|
352
|
+
getPublicClientOrThrow() {
|
|
353
|
+
if (this.publicClient)
|
|
354
|
+
return this.publicClient;
|
|
355
|
+
throw new CofhesdkError({
|
|
356
|
+
code: "MISSING_PUBLIC_CLIENT" /* MissingPublicClient */,
|
|
357
|
+
message: "Public client not found",
|
|
358
|
+
hint: "Ensure client.connect() has been called with a publicClient.",
|
|
359
|
+
context: {
|
|
360
|
+
publicClient: this.publicClient
|
|
361
|
+
}
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Gets the wallet client or throws an error if not available
|
|
366
|
+
* @returns The wallet client
|
|
367
|
+
* @throws {CofhesdkError} If walletClient is not set
|
|
368
|
+
*/
|
|
369
|
+
getWalletClientOrThrow() {
|
|
370
|
+
if (this.walletClient)
|
|
371
|
+
return this.walletClient;
|
|
372
|
+
throw new CofhesdkError({
|
|
373
|
+
code: "MISSING_WALLET_CLIENT" /* MissingWalletClient */,
|
|
374
|
+
message: "Wallet client not found",
|
|
375
|
+
hint: "Ensure client.connect() has been called with a walletClient.",
|
|
376
|
+
context: {
|
|
377
|
+
walletClient: this.walletClient
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Requires the client to be connected
|
|
383
|
+
* @throws {CofhesdkError} If client is not connected
|
|
384
|
+
*/
|
|
385
|
+
requireConnectedOrThrow() {
|
|
386
|
+
if (this.requireConnected)
|
|
387
|
+
this.requireConnected();
|
|
388
|
+
}
|
|
389
|
+
};
|
|
390
|
+
var toHexString = (bytes) => bytes.reduce((str, byte) => str + byte.toString(16).padStart(2, "0"), "");
|
|
391
|
+
var toBigIntOrThrow = (value) => {
|
|
392
|
+
if (typeof value === "bigint") {
|
|
393
|
+
return value;
|
|
394
|
+
}
|
|
395
|
+
try {
|
|
396
|
+
return BigInt(value);
|
|
397
|
+
} catch (error) {
|
|
398
|
+
throw new Error("Invalid input: Unable to convert to bigint");
|
|
399
|
+
}
|
|
400
|
+
};
|
|
401
|
+
var validateBigIntInRange = (value, max, min = 0n) => {
|
|
402
|
+
if (typeof value !== "bigint") {
|
|
403
|
+
throw new Error("Value must be of type bigint");
|
|
404
|
+
}
|
|
405
|
+
if (value > max || value < min) {
|
|
406
|
+
throw new Error(`Value out of range: ${max} - ${min}, try a different uint type`);
|
|
407
|
+
}
|
|
408
|
+
};
|
|
409
|
+
var hexToBytes = (hex) => {
|
|
410
|
+
const bytes = new Uint8Array(hex.length / 2);
|
|
411
|
+
for (let i = 0; i < hex.length; i += 2) {
|
|
412
|
+
bytes[i / 2] = parseInt(hex.substr(i, 2), 16);
|
|
413
|
+
}
|
|
414
|
+
return bytes;
|
|
415
|
+
};
|
|
416
|
+
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
417
|
+
async function getPublicClientChainID(publicClient) {
|
|
418
|
+
let chainId = null;
|
|
419
|
+
try {
|
|
420
|
+
chainId = publicClient.chain?.id ?? await publicClient.getChainId();
|
|
421
|
+
} catch (e) {
|
|
422
|
+
throw new CofhesdkError({
|
|
423
|
+
code: "PUBLIC_WALLET_GET_CHAIN_ID_FAILED" /* PublicWalletGetChainIdFailed */,
|
|
424
|
+
message: "getting chain ID from public client failed",
|
|
425
|
+
cause: e instanceof Error ? e : void 0
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
if (chainId === null) {
|
|
429
|
+
throw new CofhesdkError({
|
|
430
|
+
code: "PUBLIC_WALLET_GET_CHAIN_ID_FAILED" /* PublicWalletGetChainIdFailed */,
|
|
431
|
+
message: "chain ID from public client is null"
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
return chainId;
|
|
435
|
+
}
|
|
436
|
+
async function getWalletClientAccount(walletClient) {
|
|
437
|
+
let address;
|
|
438
|
+
try {
|
|
439
|
+
address = walletClient.account?.address;
|
|
440
|
+
if (!address) {
|
|
441
|
+
address = (await walletClient.getAddresses())?.[0];
|
|
442
|
+
}
|
|
443
|
+
} catch (e) {
|
|
444
|
+
throw new CofhesdkError({
|
|
445
|
+
code: "PUBLIC_WALLET_GET_ADDRESSES_FAILED" /* PublicWalletGetAddressesFailed */,
|
|
446
|
+
message: "getting address from wallet client failed",
|
|
447
|
+
cause: e instanceof Error ? e : void 0
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
if (!address) {
|
|
451
|
+
throw new CofhesdkError({
|
|
452
|
+
code: "PUBLIC_WALLET_GET_ADDRESSES_FAILED" /* PublicWalletGetAddressesFailed */,
|
|
453
|
+
message: "address from wallet client is null"
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
return address;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// core/decrypt/MockQueryDecrypterAbi.ts
|
|
460
|
+
var MockQueryDecrypterAbi = [
|
|
461
|
+
{
|
|
462
|
+
type: "function",
|
|
463
|
+
name: "acl",
|
|
464
|
+
inputs: [],
|
|
465
|
+
outputs: [{ name: "", type: "address", internalType: "contract ACL" }],
|
|
466
|
+
stateMutability: "view"
|
|
467
|
+
},
|
|
468
|
+
{
|
|
469
|
+
type: "function",
|
|
470
|
+
name: "decodeLowLevelReversion",
|
|
471
|
+
inputs: [{ name: "data", type: "bytes", internalType: "bytes" }],
|
|
472
|
+
outputs: [{ name: "error", type: "string", internalType: "string" }],
|
|
473
|
+
stateMutability: "pure"
|
|
474
|
+
},
|
|
475
|
+
{
|
|
476
|
+
type: "function",
|
|
477
|
+
name: "exists",
|
|
478
|
+
inputs: [],
|
|
479
|
+
outputs: [{ name: "", type: "bool", internalType: "bool" }],
|
|
480
|
+
stateMutability: "pure"
|
|
481
|
+
},
|
|
482
|
+
{
|
|
483
|
+
type: "function",
|
|
484
|
+
name: "initialize",
|
|
485
|
+
inputs: [
|
|
486
|
+
{ name: "_taskManager", type: "address", internalType: "address" },
|
|
487
|
+
{ name: "_acl", type: "address", internalType: "address" }
|
|
488
|
+
],
|
|
489
|
+
outputs: [],
|
|
490
|
+
stateMutability: "nonpayable"
|
|
491
|
+
},
|
|
492
|
+
{
|
|
493
|
+
type: "function",
|
|
494
|
+
name: "queryDecrypt",
|
|
495
|
+
inputs: [
|
|
496
|
+
{ name: "ctHash", type: "uint256", internalType: "uint256" },
|
|
497
|
+
{ name: "", type: "uint256", internalType: "uint256" },
|
|
498
|
+
{
|
|
499
|
+
name: "permission",
|
|
500
|
+
type: "tuple",
|
|
501
|
+
internalType: "struct Permission",
|
|
502
|
+
components: [
|
|
503
|
+
{ name: "issuer", type: "address", internalType: "address" },
|
|
504
|
+
{ name: "expiration", type: "uint64", internalType: "uint64" },
|
|
505
|
+
{ name: "recipient", type: "address", internalType: "address" },
|
|
506
|
+
{ name: "validatorId", type: "uint256", internalType: "uint256" },
|
|
507
|
+
{
|
|
508
|
+
name: "validatorContract",
|
|
509
|
+
type: "address",
|
|
510
|
+
internalType: "address"
|
|
511
|
+
},
|
|
512
|
+
{ name: "sealingKey", type: "bytes32", internalType: "bytes32" },
|
|
513
|
+
{ name: "issuerSignature", type: "bytes", internalType: "bytes" },
|
|
514
|
+
{ name: "recipientSignature", type: "bytes", internalType: "bytes" }
|
|
515
|
+
]
|
|
516
|
+
}
|
|
517
|
+
],
|
|
518
|
+
outputs: [
|
|
519
|
+
{ name: "allowed", type: "bool", internalType: "bool" },
|
|
520
|
+
{ name: "error", type: "string", internalType: "string" },
|
|
521
|
+
{ name: "", type: "uint256", internalType: "uint256" }
|
|
522
|
+
],
|
|
523
|
+
stateMutability: "view"
|
|
524
|
+
},
|
|
525
|
+
{
|
|
526
|
+
type: "function",
|
|
527
|
+
name: "querySealOutput",
|
|
528
|
+
inputs: [
|
|
529
|
+
{ name: "ctHash", type: "uint256", internalType: "uint256" },
|
|
530
|
+
{ name: "", type: "uint256", internalType: "uint256" },
|
|
531
|
+
{
|
|
532
|
+
name: "permission",
|
|
533
|
+
type: "tuple",
|
|
534
|
+
internalType: "struct Permission",
|
|
535
|
+
components: [
|
|
536
|
+
{ name: "issuer", type: "address", internalType: "address" },
|
|
537
|
+
{ name: "expiration", type: "uint64", internalType: "uint64" },
|
|
538
|
+
{ name: "recipient", type: "address", internalType: "address" },
|
|
539
|
+
{ name: "validatorId", type: "uint256", internalType: "uint256" },
|
|
540
|
+
{
|
|
541
|
+
name: "validatorContract",
|
|
542
|
+
type: "address",
|
|
543
|
+
internalType: "address"
|
|
544
|
+
},
|
|
545
|
+
{ name: "sealingKey", type: "bytes32", internalType: "bytes32" },
|
|
546
|
+
{ name: "issuerSignature", type: "bytes", internalType: "bytes" },
|
|
547
|
+
{ name: "recipientSignature", type: "bytes", internalType: "bytes" }
|
|
548
|
+
]
|
|
549
|
+
}
|
|
550
|
+
],
|
|
551
|
+
outputs: [
|
|
552
|
+
{ name: "allowed", type: "bool", internalType: "bool" },
|
|
553
|
+
{ name: "error", type: "string", internalType: "string" },
|
|
554
|
+
{ name: "", type: "bytes32", internalType: "bytes32" }
|
|
555
|
+
],
|
|
556
|
+
stateMutability: "view"
|
|
557
|
+
},
|
|
558
|
+
{
|
|
559
|
+
type: "function",
|
|
560
|
+
name: "seal",
|
|
561
|
+
inputs: [
|
|
562
|
+
{ name: "input", type: "uint256", internalType: "uint256" },
|
|
563
|
+
{ name: "key", type: "bytes32", internalType: "bytes32" }
|
|
564
|
+
],
|
|
565
|
+
outputs: [{ name: "", type: "bytes32", internalType: "bytes32" }],
|
|
566
|
+
stateMutability: "pure"
|
|
567
|
+
},
|
|
568
|
+
{
|
|
569
|
+
type: "function",
|
|
570
|
+
name: "taskManager",
|
|
571
|
+
inputs: [],
|
|
572
|
+
outputs: [{ name: "", type: "address", internalType: "contract TaskManager" }],
|
|
573
|
+
stateMutability: "view"
|
|
574
|
+
},
|
|
575
|
+
{
|
|
576
|
+
type: "function",
|
|
577
|
+
name: "unseal",
|
|
578
|
+
inputs: [
|
|
579
|
+
{ name: "hashed", type: "bytes32", internalType: "bytes32" },
|
|
580
|
+
{ name: "key", type: "bytes32", internalType: "bytes32" }
|
|
581
|
+
],
|
|
582
|
+
outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
|
|
583
|
+
stateMutability: "pure"
|
|
584
|
+
},
|
|
585
|
+
{ type: "error", name: "NotAllowed", inputs: [] },
|
|
586
|
+
{ type: "error", name: "SealingKeyInvalid", inputs: [] },
|
|
587
|
+
{ type: "error", name: "SealingKeyMissing", inputs: [] }
|
|
588
|
+
];
|
|
589
|
+
|
|
590
|
+
// core/decrypt/cofheMocksSealOutput.ts
|
|
591
|
+
var MockQueryDecrypterAddress = "0x0000000000000000000000000000000000000200";
|
|
592
|
+
async function cofheMocksSealOutput(ctHash, utype, permit, publicClient, mocksSealOutputDelay) {
|
|
593
|
+
if (mocksSealOutputDelay > 0)
|
|
594
|
+
await sleep(mocksSealOutputDelay);
|
|
595
|
+
const permission = PermitUtils.getPermission(permit, true);
|
|
596
|
+
const permissionWithBigInts = {
|
|
597
|
+
...permission,
|
|
598
|
+
expiration: BigInt(permission.expiration),
|
|
599
|
+
validatorId: BigInt(permission.validatorId)
|
|
600
|
+
};
|
|
601
|
+
const [allowed, error, result] = await publicClient.readContract({
|
|
602
|
+
address: MockQueryDecrypterAddress,
|
|
603
|
+
abi: MockQueryDecrypterAbi,
|
|
604
|
+
functionName: "querySealOutput",
|
|
605
|
+
args: [ctHash, BigInt(utype), permissionWithBigInts]
|
|
606
|
+
});
|
|
607
|
+
if (error != "") {
|
|
608
|
+
throw new CofhesdkError({
|
|
609
|
+
code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
|
|
610
|
+
message: `mocks querySealOutput call failed: ${error}`
|
|
611
|
+
});
|
|
612
|
+
}
|
|
613
|
+
if (allowed == false) {
|
|
614
|
+
throw new CofhesdkError({
|
|
615
|
+
code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
|
|
616
|
+
message: `mocks querySealOutput call failed: ACL Access Denied (NotAllowed)`
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
const sealedBigInt = BigInt(result);
|
|
620
|
+
const sealingKeyBigInt = BigInt(permission.sealingKey);
|
|
621
|
+
const unsealed = sealedBigInt ^ sealingKeyBigInt;
|
|
622
|
+
return unsealed;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
// core/decrypt/tnSealOutput.ts
|
|
626
|
+
async function tnSealOutput(ctHash, chainId, permission, thresholdNetworkUrl) {
|
|
627
|
+
let sealed;
|
|
628
|
+
let errorMessage;
|
|
629
|
+
let sealOutputResult;
|
|
630
|
+
const body = {
|
|
631
|
+
ct_tempkey: ctHash.toString(16).padStart(64, "0"),
|
|
632
|
+
host_chain_id: chainId,
|
|
633
|
+
permit: permission
|
|
634
|
+
};
|
|
635
|
+
try {
|
|
636
|
+
const sealOutputRes = await fetch(`${thresholdNetworkUrl}/sealoutput`, {
|
|
637
|
+
method: "POST",
|
|
638
|
+
headers: {
|
|
639
|
+
"Content-Type": "application/json"
|
|
640
|
+
},
|
|
641
|
+
body: JSON.stringify(body)
|
|
642
|
+
});
|
|
643
|
+
sealOutputResult = await sealOutputRes.json();
|
|
644
|
+
sealed = sealOutputResult.sealed;
|
|
645
|
+
errorMessage = sealOutputResult.error_message;
|
|
646
|
+
} catch (e) {
|
|
647
|
+
throw new CofhesdkError({
|
|
648
|
+
code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
|
|
649
|
+
message: `sealOutput request failed`,
|
|
650
|
+
hint: "Ensure the threshold network URL is valid.",
|
|
651
|
+
cause: e instanceof Error ? e : void 0,
|
|
652
|
+
context: {
|
|
653
|
+
thresholdNetworkUrl,
|
|
654
|
+
body
|
|
655
|
+
}
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
if (sealed == null) {
|
|
659
|
+
throw new CofhesdkError({
|
|
660
|
+
code: "SEAL_OUTPUT_RETURNED_NULL" /* SealOutputReturnedNull */,
|
|
661
|
+
message: `sealOutput request returned no data | Caused by: ${errorMessage}`,
|
|
662
|
+
context: {
|
|
663
|
+
thresholdNetworkUrl,
|
|
664
|
+
body,
|
|
665
|
+
sealOutputResult
|
|
666
|
+
}
|
|
667
|
+
});
|
|
668
|
+
}
|
|
669
|
+
return sealed;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
// core/decrypt/decryptHandleBuilder.ts
|
|
673
|
+
var DecryptHandlesBuilder = class extends BaseBuilder {
|
|
674
|
+
ctHash;
|
|
675
|
+
utype;
|
|
676
|
+
permitHash;
|
|
677
|
+
permit;
|
|
678
|
+
constructor(params) {
|
|
679
|
+
super({
|
|
680
|
+
config: params.config,
|
|
681
|
+
publicClient: params.publicClient,
|
|
682
|
+
walletClient: params.walletClient,
|
|
683
|
+
chainId: params.chainId,
|
|
684
|
+
account: params.account,
|
|
685
|
+
requireConnected: params.requireConnected
|
|
686
|
+
});
|
|
687
|
+
this.ctHash = params.ctHash;
|
|
688
|
+
this.utype = params.utype;
|
|
689
|
+
this.permitHash = params.permitHash;
|
|
690
|
+
this.permit = params.permit;
|
|
691
|
+
}
|
|
692
|
+
/**
|
|
693
|
+
* @param chainId - Chain to decrypt values from. Used to fetch the threshold network URL and use the correct permit.
|
|
694
|
+
*
|
|
695
|
+
* If not provided, the chainId will be fetched from the connected publicClient.
|
|
696
|
+
*
|
|
697
|
+
* Example:
|
|
698
|
+
* ```typescript
|
|
699
|
+
* const unsealed = await decryptHandle(ctHash, utype)
|
|
700
|
+
* .setChainId(11155111)
|
|
701
|
+
* .decrypt();
|
|
702
|
+
* ```
|
|
703
|
+
*
|
|
704
|
+
* @returns The chainable DecryptHandlesBuilder instance.
|
|
705
|
+
*/
|
|
706
|
+
setChainId(chainId) {
|
|
707
|
+
this.chainId = chainId;
|
|
708
|
+
return this;
|
|
709
|
+
}
|
|
710
|
+
getChainId() {
|
|
711
|
+
return this.chainId;
|
|
712
|
+
}
|
|
713
|
+
/**
|
|
714
|
+
* @param account - Account to decrypt values from. Used to fetch the correct permit.
|
|
715
|
+
*
|
|
716
|
+
* If not provided, the account will be fetched from the connected walletClient.
|
|
717
|
+
*
|
|
718
|
+
* Example:
|
|
719
|
+
* ```typescript
|
|
720
|
+
* const unsealed = await decryptHandle(ctHash, utype)
|
|
721
|
+
* .setAccount('0x1234567890123456789012345678901234567890')
|
|
722
|
+
* .decrypt();
|
|
723
|
+
* ```
|
|
724
|
+
*
|
|
725
|
+
* @returns The chainable DecryptHandlesBuilder instance.
|
|
726
|
+
*/
|
|
727
|
+
setAccount(account) {
|
|
728
|
+
this.account = account;
|
|
729
|
+
return this;
|
|
730
|
+
}
|
|
731
|
+
getAccount() {
|
|
732
|
+
return this.account;
|
|
733
|
+
}
|
|
734
|
+
/**
|
|
735
|
+
* @param permitHash - Permit hash to decrypt values from. Used to fetch the correct permit.
|
|
736
|
+
*
|
|
737
|
+
* If not provided, the active permit for the chainId and account will be used.
|
|
738
|
+
* If `setPermit()` is called, it will be used regardless of chainId, account, or permitHash.
|
|
739
|
+
*
|
|
740
|
+
* Example:
|
|
741
|
+
* ```typescript
|
|
742
|
+
* const unsealed = await decryptHandle(ctHash, utype)
|
|
743
|
+
* .setPermitHash('0x1234567890123456789012345678901234567890')
|
|
744
|
+
* .decrypt();
|
|
745
|
+
* ```
|
|
746
|
+
*
|
|
747
|
+
* @returns The chainable DecryptHandlesBuilder instance.
|
|
748
|
+
*/
|
|
749
|
+
setPermitHash(permitHash) {
|
|
750
|
+
this.permitHash = permitHash;
|
|
751
|
+
return this;
|
|
752
|
+
}
|
|
753
|
+
getPermitHash() {
|
|
754
|
+
return this.permitHash;
|
|
755
|
+
}
|
|
756
|
+
/**
|
|
757
|
+
* @param permit - Permit to decrypt values with. If provided, it will be used regardless of chainId, account, or permitHash.
|
|
758
|
+
*
|
|
759
|
+
* If not provided, the permit will be determined by chainId, account, and permitHash.
|
|
760
|
+
*
|
|
761
|
+
* Example:
|
|
762
|
+
* ```typescript
|
|
763
|
+
* const unsealed = await decryptHandle(ctHash, utype)
|
|
764
|
+
* .setPermit(permit)
|
|
765
|
+
* .decrypt();
|
|
766
|
+
* ```
|
|
767
|
+
*
|
|
768
|
+
* @returns The chainable DecryptHandlesBuilder instance.
|
|
769
|
+
*/
|
|
770
|
+
setPermit(permit) {
|
|
771
|
+
this.permit = permit;
|
|
772
|
+
return this;
|
|
773
|
+
}
|
|
774
|
+
getPermit() {
|
|
775
|
+
return this.permit;
|
|
776
|
+
}
|
|
777
|
+
getThresholdNetworkUrl(chainId) {
|
|
778
|
+
const config = this.getConfigOrThrow();
|
|
779
|
+
return getThresholdNetworkUrlOrThrow(config, chainId);
|
|
780
|
+
}
|
|
781
|
+
validateUtypeOrThrow() {
|
|
782
|
+
if (!isValidUtype(this.utype))
|
|
783
|
+
throw new CofhesdkError({
|
|
784
|
+
code: "INVALID_UTYPE" /* InvalidUtype */,
|
|
785
|
+
message: `Invalid utype to decrypt to`,
|
|
786
|
+
context: {
|
|
787
|
+
utype: this.utype
|
|
788
|
+
}
|
|
789
|
+
});
|
|
790
|
+
}
|
|
791
|
+
async getResolvedPermit() {
|
|
792
|
+
if (this.permit)
|
|
793
|
+
return this.permit;
|
|
794
|
+
const chainId = await this.getChainIdOrThrow();
|
|
795
|
+
const account = await this.getAccountOrThrow();
|
|
796
|
+
if (this.permitHash) {
|
|
797
|
+
const permit2 = await permits.getPermit(chainId, account, this.permitHash);
|
|
798
|
+
if (!permit2) {
|
|
799
|
+
throw new CofhesdkError({
|
|
800
|
+
code: "PERMIT_NOT_FOUND" /* PermitNotFound */,
|
|
801
|
+
message: `Permit with hash <${this.permitHash}> not found for account <${account}> and chainId <${chainId}>`,
|
|
802
|
+
hint: "Ensure the permit exists and is valid.",
|
|
803
|
+
context: {
|
|
804
|
+
chainId,
|
|
805
|
+
account,
|
|
806
|
+
permitHash: this.permitHash
|
|
807
|
+
}
|
|
808
|
+
});
|
|
809
|
+
}
|
|
810
|
+
return permit2;
|
|
811
|
+
}
|
|
812
|
+
const permit = await permits.getActivePermit(chainId, account);
|
|
813
|
+
if (!permit) {
|
|
814
|
+
throw new CofhesdkError({
|
|
815
|
+
code: "PERMIT_NOT_FOUND" /* PermitNotFound */,
|
|
816
|
+
message: `Active permit not found for chainId <${chainId}> and account <${account}>`,
|
|
817
|
+
hint: "Ensure a permit exists for this account on this chain.",
|
|
818
|
+
context: {
|
|
819
|
+
chainId,
|
|
820
|
+
account
|
|
821
|
+
}
|
|
822
|
+
});
|
|
823
|
+
}
|
|
824
|
+
return permit;
|
|
825
|
+
}
|
|
826
|
+
/**
|
|
827
|
+
* On hardhat, interact with MockZkVerifier contract instead of CoFHE
|
|
828
|
+
*/
|
|
829
|
+
async mocksSealOutput(permit) {
|
|
830
|
+
const config = this.getConfigOrThrow();
|
|
831
|
+
const mocksSealOutputDelay = config.mocks.sealOutputDelay;
|
|
832
|
+
return cofheMocksSealOutput(this.ctHash, this.utype, permit, this.getPublicClientOrThrow(), mocksSealOutputDelay);
|
|
833
|
+
}
|
|
834
|
+
/**
|
|
835
|
+
* In the production context, perform a true decryption with the CoFHE coprocessor.
|
|
836
|
+
*/
|
|
837
|
+
async productionSealOutput(chainId, permit) {
|
|
838
|
+
const thresholdNetworkUrl = this.getThresholdNetworkUrl(chainId);
|
|
839
|
+
const permission = PermitUtils.getPermission(permit, true);
|
|
840
|
+
const sealed = await tnSealOutput(this.ctHash, chainId, permission, thresholdNetworkUrl);
|
|
841
|
+
return PermitUtils.unseal(permit, sealed);
|
|
842
|
+
}
|
|
843
|
+
/**
|
|
844
|
+
* Final step of the decryption process. MUST BE CALLED LAST IN THE CHAIN.
|
|
845
|
+
*
|
|
846
|
+
* This will:
|
|
847
|
+
* - Use a permit based on provided permit OR chainId + account + permitHash
|
|
848
|
+
* - Check permit validity
|
|
849
|
+
* - Call CoFHE `/sealoutput` with the permit, which returns a sealed (encrypted) item
|
|
850
|
+
* - Unseal the sealed item with the permit
|
|
851
|
+
* - Return the unsealed item
|
|
852
|
+
*
|
|
853
|
+
* Example:
|
|
854
|
+
* ```typescript
|
|
855
|
+
* const unsealed = await decryptHandle(ctHash, utype)
|
|
856
|
+
* .setChainId(11155111) // optional
|
|
857
|
+
* .setAccount('0x123...890') // optional
|
|
858
|
+
* .decrypt(); // execute
|
|
859
|
+
* ```
|
|
860
|
+
*
|
|
861
|
+
* @returns The unsealed item.
|
|
862
|
+
*/
|
|
863
|
+
decrypt() {
|
|
864
|
+
return resultWrapper(async () => {
|
|
865
|
+
await this.requireConnectedOrThrow();
|
|
866
|
+
this.validateUtypeOrThrow();
|
|
867
|
+
const permit = await this.getResolvedPermit();
|
|
868
|
+
await PermitUtils.validate(permit);
|
|
869
|
+
const chainId = permit._signedDomain.chainId;
|
|
870
|
+
let unsealed;
|
|
871
|
+
if (chainId === hardhat.id) {
|
|
872
|
+
unsealed = await this.mocksSealOutput(permit);
|
|
873
|
+
} else {
|
|
874
|
+
unsealed = await this.productionSealOutput(chainId, permit);
|
|
875
|
+
}
|
|
876
|
+
return convertViaUtype(this.utype, unsealed);
|
|
877
|
+
});
|
|
878
|
+
}
|
|
879
|
+
};
|
|
880
|
+
|
|
881
|
+
// core/encrypt/zkPackProveVerify.ts
|
|
882
|
+
var MAX_UINT8 = 255n;
|
|
883
|
+
var MAX_UINT16 = 65535n;
|
|
884
|
+
var MAX_UINT32 = 4294967295n;
|
|
885
|
+
var MAX_UINT64 = 18446744073709551615n;
|
|
886
|
+
var MAX_UINT128 = 340282366920938463463374607431768211455n;
|
|
887
|
+
var MAX_UINT160 = 1461501637330902918203684832716283019655932542975n;
|
|
888
|
+
var MAX_ENCRYPTABLE_BITS = 2048;
|
|
889
|
+
var zkPack = (items, builder) => {
|
|
890
|
+
let totalBits = 0;
|
|
891
|
+
for (const item of items) {
|
|
892
|
+
switch (item.utype) {
|
|
893
|
+
case 0 /* Bool */: {
|
|
894
|
+
builder.push_boolean(item.data);
|
|
895
|
+
totalBits += 1;
|
|
896
|
+
break;
|
|
897
|
+
}
|
|
898
|
+
case 2 /* Uint8 */: {
|
|
899
|
+
const bint = toBigIntOrThrow(item.data);
|
|
900
|
+
validateBigIntInRange(bint, MAX_UINT8);
|
|
901
|
+
builder.push_u8(parseInt(bint.toString()));
|
|
902
|
+
totalBits += 8;
|
|
903
|
+
break;
|
|
904
|
+
}
|
|
905
|
+
case 3 /* Uint16 */: {
|
|
906
|
+
const bint = toBigIntOrThrow(item.data);
|
|
907
|
+
validateBigIntInRange(bint, MAX_UINT16);
|
|
908
|
+
builder.push_u16(parseInt(bint.toString()));
|
|
909
|
+
totalBits += 16;
|
|
910
|
+
break;
|
|
911
|
+
}
|
|
912
|
+
case 4 /* Uint32 */: {
|
|
913
|
+
const bint = toBigIntOrThrow(item.data);
|
|
914
|
+
validateBigIntInRange(bint, MAX_UINT32);
|
|
915
|
+
builder.push_u32(parseInt(bint.toString()));
|
|
916
|
+
totalBits += 32;
|
|
917
|
+
break;
|
|
918
|
+
}
|
|
919
|
+
case 5 /* Uint64 */: {
|
|
920
|
+
const bint = toBigIntOrThrow(item.data);
|
|
921
|
+
validateBigIntInRange(bint, MAX_UINT64);
|
|
922
|
+
builder.push_u64(bint);
|
|
923
|
+
totalBits += 64;
|
|
924
|
+
break;
|
|
925
|
+
}
|
|
926
|
+
case 6 /* Uint128 */: {
|
|
927
|
+
const bint = toBigIntOrThrow(item.data);
|
|
928
|
+
validateBigIntInRange(bint, MAX_UINT128);
|
|
929
|
+
builder.push_u128(bint);
|
|
930
|
+
totalBits += 128;
|
|
931
|
+
break;
|
|
932
|
+
}
|
|
933
|
+
case 7 /* Uint160 */: {
|
|
934
|
+
const bint = toBigIntOrThrow(item.data);
|
|
935
|
+
validateBigIntInRange(bint, MAX_UINT160);
|
|
936
|
+
builder.push_u160(bint);
|
|
937
|
+
totalBits += 160;
|
|
938
|
+
break;
|
|
939
|
+
}
|
|
940
|
+
default: {
|
|
941
|
+
throw new CofhesdkError({
|
|
942
|
+
code: "ZK_PACK_FAILED" /* ZkPackFailed */,
|
|
943
|
+
message: `Invalid utype: ${item.utype}`,
|
|
944
|
+
hint: `Ensure that the utype is valid, using the Encryptable type, for example: Encryptable.uint128(100n)`,
|
|
945
|
+
context: {
|
|
946
|
+
item
|
|
947
|
+
}
|
|
948
|
+
});
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
if (totalBits > MAX_ENCRYPTABLE_BITS) {
|
|
953
|
+
throw new CofhesdkError({
|
|
954
|
+
code: "ZK_PACK_FAILED" /* ZkPackFailed */,
|
|
955
|
+
message: `Total bits ${totalBits} exceeds ${MAX_ENCRYPTABLE_BITS}`,
|
|
956
|
+
hint: `Ensure that the total bits of the items to encrypt does not exceed ${MAX_ENCRYPTABLE_BITS}`,
|
|
957
|
+
context: {
|
|
958
|
+
totalBits,
|
|
959
|
+
maxBits: MAX_ENCRYPTABLE_BITS,
|
|
960
|
+
items
|
|
961
|
+
}
|
|
962
|
+
});
|
|
963
|
+
}
|
|
964
|
+
return builder;
|
|
965
|
+
};
|
|
966
|
+
var zkProve = async (builder, crs, address, securityZone, chainId) => {
|
|
967
|
+
const metadata = constructZkPoKMetadata(address, securityZone, chainId);
|
|
968
|
+
return new Promise((resolve) => {
|
|
969
|
+
setTimeout(() => {
|
|
970
|
+
const compactList = builder.build_with_proof_packed(
|
|
971
|
+
crs,
|
|
972
|
+
metadata,
|
|
973
|
+
1
|
|
974
|
+
// ZkComputeLoad.Verify
|
|
975
|
+
);
|
|
976
|
+
resolve(compactList.serialize());
|
|
977
|
+
}, 0);
|
|
978
|
+
});
|
|
979
|
+
};
|
|
980
|
+
var constructZkPoKMetadata = (accountAddr, securityZone, chainId) => {
|
|
981
|
+
const accountAddrNoPrefix = accountAddr.startsWith("0x") ? accountAddr.slice(2) : accountAddr;
|
|
982
|
+
const accountBytes = hexToBytes(accountAddrNoPrefix);
|
|
983
|
+
const chainIdBytes = new Uint8Array(32);
|
|
984
|
+
let value = chainId;
|
|
985
|
+
for (let i = 31; i >= 0 && value > 0; i--) {
|
|
986
|
+
chainIdBytes[i] = value & 255;
|
|
987
|
+
value = value >>> 8;
|
|
988
|
+
}
|
|
989
|
+
const metadata = new Uint8Array(1 + accountBytes.length + 32);
|
|
990
|
+
metadata[0] = securityZone;
|
|
991
|
+
metadata.set(accountBytes, 1);
|
|
992
|
+
metadata.set(chainIdBytes, 1 + accountBytes.length);
|
|
993
|
+
return metadata;
|
|
994
|
+
};
|
|
995
|
+
var zkVerify = async (verifierUrl, serializedBytes, address, securityZone, chainId) => {
|
|
996
|
+
const packed_list = toHexString(serializedBytes);
|
|
997
|
+
const sz_byte = new Uint8Array([securityZone]);
|
|
998
|
+
const payload = {
|
|
999
|
+
packed_list,
|
|
1000
|
+
account_addr: address,
|
|
1001
|
+
security_zone: sz_byte[0],
|
|
1002
|
+
chain_id: chainId
|
|
1003
|
+
};
|
|
1004
|
+
const body = JSON.stringify(payload);
|
|
1005
|
+
try {
|
|
1006
|
+
const response = await fetch(`${verifierUrl}/verify`, {
|
|
1007
|
+
method: "POST",
|
|
1008
|
+
headers: {
|
|
1009
|
+
"Content-Type": "application/json"
|
|
1010
|
+
},
|
|
1011
|
+
body
|
|
1012
|
+
});
|
|
1013
|
+
if (!response.ok) {
|
|
1014
|
+
const errorBody = await response.text();
|
|
1015
|
+
throw new CofhesdkError({
|
|
1016
|
+
code: "ZK_VERIFY_FAILED" /* ZkVerifyFailed */,
|
|
1017
|
+
message: `HTTP error! ZK proof verification failed - ${errorBody}`
|
|
1018
|
+
});
|
|
1019
|
+
}
|
|
1020
|
+
const json = await response.json();
|
|
1021
|
+
if (json.status !== "success") {
|
|
1022
|
+
throw new CofhesdkError({
|
|
1023
|
+
code: "ZK_VERIFY_FAILED" /* ZkVerifyFailed */,
|
|
1024
|
+
message: `ZK proof verification response malformed - ${json.error}`
|
|
1025
|
+
});
|
|
1026
|
+
}
|
|
1027
|
+
return json.data.map(({ ct_hash, signature, recid }) => {
|
|
1028
|
+
return {
|
|
1029
|
+
ct_hash,
|
|
1030
|
+
signature: concatSigRecid(signature, recid)
|
|
1031
|
+
};
|
|
1032
|
+
});
|
|
1033
|
+
} catch (e) {
|
|
1034
|
+
throw new CofhesdkError({
|
|
1035
|
+
code: "ZK_VERIFY_FAILED" /* ZkVerifyFailed */,
|
|
1036
|
+
message: `ZK proof verification failed`,
|
|
1037
|
+
cause: e instanceof Error ? e : void 0
|
|
1038
|
+
});
|
|
1039
|
+
}
|
|
1040
|
+
};
|
|
1041
|
+
var concatSigRecid = (signature, recid) => {
|
|
1042
|
+
return signature + (recid + 27).toString(16).padStart(2, "0");
|
|
1043
|
+
};
|
|
1044
|
+
|
|
1045
|
+
// core/encrypt/MockZkVerifierAbi.ts
|
|
1046
|
+
var MockZkVerifierAbi = [
|
|
1047
|
+
{
|
|
1048
|
+
type: "function",
|
|
1049
|
+
name: "exists",
|
|
1050
|
+
inputs: [],
|
|
1051
|
+
outputs: [{ name: "", type: "bool", internalType: "bool" }],
|
|
1052
|
+
stateMutability: "pure"
|
|
1053
|
+
},
|
|
1054
|
+
{
|
|
1055
|
+
type: "function",
|
|
1056
|
+
name: "insertCtHash",
|
|
1057
|
+
inputs: [
|
|
1058
|
+
{ name: "ctHash", type: "uint256", internalType: "uint256" },
|
|
1059
|
+
{ name: "value", type: "uint256", internalType: "uint256" }
|
|
1060
|
+
],
|
|
1061
|
+
outputs: [],
|
|
1062
|
+
stateMutability: "nonpayable"
|
|
1063
|
+
},
|
|
1064
|
+
{
|
|
1065
|
+
type: "function",
|
|
1066
|
+
name: "insertPackedCtHashes",
|
|
1067
|
+
inputs: [
|
|
1068
|
+
{ name: "ctHashes", type: "uint256[]", internalType: "uint256[]" },
|
|
1069
|
+
{ name: "values", type: "uint256[]", internalType: "uint256[]" }
|
|
1070
|
+
],
|
|
1071
|
+
outputs: [],
|
|
1072
|
+
stateMutability: "nonpayable"
|
|
1073
|
+
},
|
|
1074
|
+
{
|
|
1075
|
+
type: "function",
|
|
1076
|
+
name: "zkVerify",
|
|
1077
|
+
inputs: [
|
|
1078
|
+
{ name: "value", type: "uint256", internalType: "uint256" },
|
|
1079
|
+
{ name: "utype", type: "uint8", internalType: "uint8" },
|
|
1080
|
+
{ name: "user", type: "address", internalType: "address" },
|
|
1081
|
+
{ name: "securityZone", type: "uint8", internalType: "uint8" },
|
|
1082
|
+
{ name: "", type: "uint256", internalType: "uint256" }
|
|
1083
|
+
],
|
|
1084
|
+
outputs: [
|
|
1085
|
+
{
|
|
1086
|
+
name: "",
|
|
1087
|
+
type: "tuple",
|
|
1088
|
+
internalType: "struct EncryptedInput",
|
|
1089
|
+
components: [
|
|
1090
|
+
{ name: "ctHash", type: "uint256", internalType: "uint256" },
|
|
1091
|
+
{ name: "securityZone", type: "uint8", internalType: "uint8" },
|
|
1092
|
+
{ name: "utype", type: "uint8", internalType: "uint8" },
|
|
1093
|
+
{ name: "signature", type: "bytes", internalType: "bytes" }
|
|
1094
|
+
]
|
|
1095
|
+
}
|
|
1096
|
+
],
|
|
1097
|
+
stateMutability: "nonpayable"
|
|
1098
|
+
},
|
|
1099
|
+
{
|
|
1100
|
+
type: "function",
|
|
1101
|
+
name: "zkVerifyCalcCtHash",
|
|
1102
|
+
inputs: [
|
|
1103
|
+
{ name: "value", type: "uint256", internalType: "uint256" },
|
|
1104
|
+
{ name: "utype", type: "uint8", internalType: "uint8" },
|
|
1105
|
+
{ name: "user", type: "address", internalType: "address" },
|
|
1106
|
+
{ name: "securityZone", type: "uint8", internalType: "uint8" },
|
|
1107
|
+
{ name: "", type: "uint256", internalType: "uint256" }
|
|
1108
|
+
],
|
|
1109
|
+
outputs: [{ name: "ctHash", type: "uint256", internalType: "uint256" }],
|
|
1110
|
+
stateMutability: "view"
|
|
1111
|
+
},
|
|
1112
|
+
{
|
|
1113
|
+
type: "function",
|
|
1114
|
+
name: "zkVerifyCalcCtHashesPacked",
|
|
1115
|
+
inputs: [
|
|
1116
|
+
{ name: "values", type: "uint256[]", internalType: "uint256[]" },
|
|
1117
|
+
{ name: "utypes", type: "uint8[]", internalType: "uint8[]" },
|
|
1118
|
+
{ name: "user", type: "address", internalType: "address" },
|
|
1119
|
+
{ name: "securityZone", type: "uint8", internalType: "uint8" },
|
|
1120
|
+
{ name: "chainId", type: "uint256", internalType: "uint256" }
|
|
1121
|
+
],
|
|
1122
|
+
outputs: [{ name: "ctHashes", type: "uint256[]", internalType: "uint256[]" }],
|
|
1123
|
+
stateMutability: "view"
|
|
1124
|
+
},
|
|
1125
|
+
{
|
|
1126
|
+
type: "function",
|
|
1127
|
+
name: "zkVerifyPacked",
|
|
1128
|
+
inputs: [
|
|
1129
|
+
{ name: "values", type: "uint256[]", internalType: "uint256[]" },
|
|
1130
|
+
{ name: "utypes", type: "uint8[]", internalType: "uint8[]" },
|
|
1131
|
+
{ name: "user", type: "address", internalType: "address" },
|
|
1132
|
+
{ name: "securityZone", type: "uint8", internalType: "uint8" },
|
|
1133
|
+
{ name: "chainId", type: "uint256", internalType: "uint256" }
|
|
1134
|
+
],
|
|
1135
|
+
outputs: [
|
|
1136
|
+
{
|
|
1137
|
+
name: "inputs",
|
|
1138
|
+
type: "tuple[]",
|
|
1139
|
+
internalType: "struct EncryptedInput[]",
|
|
1140
|
+
components: [
|
|
1141
|
+
{ name: "ctHash", type: "uint256", internalType: "uint256" },
|
|
1142
|
+
{ name: "securityZone", type: "uint8", internalType: "uint8" },
|
|
1143
|
+
{ name: "utype", type: "uint8", internalType: "uint8" },
|
|
1144
|
+
{ name: "signature", type: "bytes", internalType: "bytes" }
|
|
1145
|
+
]
|
|
1146
|
+
}
|
|
1147
|
+
],
|
|
1148
|
+
stateMutability: "nonpayable"
|
|
1149
|
+
},
|
|
1150
|
+
{ type: "error", name: "InvalidInputs", inputs: [] }
|
|
1151
|
+
];
|
|
1152
|
+
var MocksZkVerifierAddress = "0x0000000000000000000000000000000000000100";
|
|
1153
|
+
var MocksEncryptedInputSignerPkey = "0x6c8d7f768a6bb4aafe85e8a2f5a9680355239c7e14646ed62b044e39de154512";
|
|
1154
|
+
async function cofheMocksCheckEncryptableBits(items) {
|
|
1155
|
+
let totalBits = 0;
|
|
1156
|
+
for (const item of items) {
|
|
1157
|
+
switch (item.utype) {
|
|
1158
|
+
case 0 /* Bool */: {
|
|
1159
|
+
totalBits += 1;
|
|
1160
|
+
break;
|
|
1161
|
+
}
|
|
1162
|
+
case 2 /* Uint8 */: {
|
|
1163
|
+
totalBits += 8;
|
|
1164
|
+
break;
|
|
1165
|
+
}
|
|
1166
|
+
case 3 /* Uint16 */: {
|
|
1167
|
+
totalBits += 16;
|
|
1168
|
+
break;
|
|
1169
|
+
}
|
|
1170
|
+
case 4 /* Uint32 */: {
|
|
1171
|
+
totalBits += 32;
|
|
1172
|
+
break;
|
|
1173
|
+
}
|
|
1174
|
+
case 5 /* Uint64 */: {
|
|
1175
|
+
totalBits += 64;
|
|
1176
|
+
break;
|
|
1177
|
+
}
|
|
1178
|
+
case 6 /* Uint128 */: {
|
|
1179
|
+
totalBits += 128;
|
|
1180
|
+
break;
|
|
1181
|
+
}
|
|
1182
|
+
case 7 /* Uint160 */: {
|
|
1183
|
+
totalBits += 160;
|
|
1184
|
+
break;
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
if (totalBits > MAX_ENCRYPTABLE_BITS) {
|
|
1189
|
+
throw new CofhesdkError({
|
|
1190
|
+
code: "ZK_PACK_FAILED" /* ZkPackFailed */,
|
|
1191
|
+
message: `Total bits ${totalBits} exceeds ${MAX_ENCRYPTABLE_BITS}`,
|
|
1192
|
+
hint: `Ensure that the total bits of the items to encrypt does not exceed ${MAX_ENCRYPTABLE_BITS}`,
|
|
1193
|
+
context: {
|
|
1194
|
+
totalBits,
|
|
1195
|
+
maxBits: MAX_ENCRYPTABLE_BITS,
|
|
1196
|
+
items
|
|
1197
|
+
}
|
|
1198
|
+
});
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
async function calcCtHashes(items, account, securityZone, publicClient) {
|
|
1202
|
+
const calcCtHashesArgs = [
|
|
1203
|
+
items.map(({ data }) => BigInt(data)),
|
|
1204
|
+
items.map(({ utype }) => utype),
|
|
1205
|
+
account,
|
|
1206
|
+
securityZone,
|
|
1207
|
+
BigInt(hardhat$1.id)
|
|
1208
|
+
];
|
|
1209
|
+
let ctHashes;
|
|
1210
|
+
try {
|
|
1211
|
+
ctHashes = await publicClient.readContract({
|
|
1212
|
+
address: MocksZkVerifierAddress,
|
|
1213
|
+
abi: MockZkVerifierAbi,
|
|
1214
|
+
functionName: "zkVerifyCalcCtHashesPacked",
|
|
1215
|
+
args: calcCtHashesArgs
|
|
1216
|
+
});
|
|
1217
|
+
} catch (err) {
|
|
1218
|
+
throw new CofhesdkError({
|
|
1219
|
+
code: "ZK_MOCKS_CALC_CT_HASHES_FAILED" /* ZkMocksCalcCtHashesFailed */,
|
|
1220
|
+
message: `mockZkVerifySign calcCtHashes failed while calling zkVerifyCalcCtHashesPacked`,
|
|
1221
|
+
cause: err instanceof Error ? err : void 0,
|
|
1222
|
+
context: {
|
|
1223
|
+
address: MocksZkVerifierAddress,
|
|
1224
|
+
items,
|
|
1225
|
+
account,
|
|
1226
|
+
securityZone,
|
|
1227
|
+
publicClient,
|
|
1228
|
+
calcCtHashesArgs
|
|
1229
|
+
}
|
|
1230
|
+
});
|
|
1231
|
+
}
|
|
1232
|
+
if (ctHashes.length !== items.length) {
|
|
1233
|
+
throw new CofhesdkError({
|
|
1234
|
+
code: "ZK_MOCKS_CALC_CT_HASHES_FAILED" /* ZkMocksCalcCtHashesFailed */,
|
|
1235
|
+
message: `mockZkVerifySign calcCtHashes returned incorrect number of ctHashes`,
|
|
1236
|
+
context: {
|
|
1237
|
+
items,
|
|
1238
|
+
account,
|
|
1239
|
+
securityZone,
|
|
1240
|
+
publicClient,
|
|
1241
|
+
calcCtHashesArgs,
|
|
1242
|
+
ctHashes
|
|
1243
|
+
}
|
|
1244
|
+
});
|
|
1245
|
+
}
|
|
1246
|
+
return items.map((item, index) => ({
|
|
1247
|
+
...item,
|
|
1248
|
+
ctHash: ctHashes[index]
|
|
1249
|
+
}));
|
|
1250
|
+
}
|
|
1251
|
+
async function insertCtHashes(items, walletClient) {
|
|
1252
|
+
const insertPackedCtHashesArgs = [items.map(({ ctHash }) => ctHash), items.map(({ data }) => BigInt(data))];
|
|
1253
|
+
try {
|
|
1254
|
+
const account = walletClient.account;
|
|
1255
|
+
await walletClient.writeContract({
|
|
1256
|
+
address: MocksZkVerifierAddress,
|
|
1257
|
+
abi: MockZkVerifierAbi,
|
|
1258
|
+
functionName: "insertPackedCtHashes",
|
|
1259
|
+
args: insertPackedCtHashesArgs,
|
|
1260
|
+
chain: hardhat$1,
|
|
1261
|
+
account
|
|
1262
|
+
});
|
|
1263
|
+
} catch (err) {
|
|
1264
|
+
throw new CofhesdkError({
|
|
1265
|
+
code: "ZK_MOCKS_INSERT_CT_HASHES_FAILED" /* ZkMocksInsertCtHashesFailed */,
|
|
1266
|
+
message: `mockZkVerifySign insertPackedCtHashes failed while calling insertPackedCtHashes`,
|
|
1267
|
+
cause: err instanceof Error ? err : void 0,
|
|
1268
|
+
context: {
|
|
1269
|
+
items,
|
|
1270
|
+
walletClient,
|
|
1271
|
+
insertPackedCtHashesArgs
|
|
1272
|
+
}
|
|
1273
|
+
});
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
async function createProofSignatures(items, securityZone) {
|
|
1277
|
+
let signatures = [];
|
|
1278
|
+
let encInputSignerClient;
|
|
1279
|
+
try {
|
|
1280
|
+
encInputSignerClient = createWalletClient({
|
|
1281
|
+
chain: hardhat$1,
|
|
1282
|
+
transport: http(),
|
|
1283
|
+
account: privateKeyToAccount(MocksEncryptedInputSignerPkey)
|
|
1284
|
+
});
|
|
1285
|
+
} catch (err) {
|
|
1286
|
+
throw new CofhesdkError({
|
|
1287
|
+
code: "ZK_MOCKS_CREATE_PROOF_SIGNATURE_FAILED" /* ZkMocksCreateProofSignatureFailed */,
|
|
1288
|
+
message: `mockZkVerifySign createProofSignatures failed while creating wallet client`,
|
|
1289
|
+
cause: err instanceof Error ? err : void 0,
|
|
1290
|
+
context: {
|
|
1291
|
+
MocksEncryptedInputSignerPkey
|
|
1292
|
+
}
|
|
1293
|
+
});
|
|
1294
|
+
}
|
|
1295
|
+
try {
|
|
1296
|
+
for (const item of items) {
|
|
1297
|
+
const packedData = encodePacked(["uint256", "int32", "uint8"], [BigInt(item.data), securityZone, item.utype]);
|
|
1298
|
+
const messageHash = keccak256(packedData);
|
|
1299
|
+
const ethSignedHash = hashMessage({ raw: toBytes(messageHash) });
|
|
1300
|
+
const signature = await encInputSignerClient.signMessage({
|
|
1301
|
+
message: { raw: toBytes(ethSignedHash) },
|
|
1302
|
+
account: encInputSignerClient.account
|
|
1303
|
+
});
|
|
1304
|
+
signatures.push(signature);
|
|
1305
|
+
}
|
|
1306
|
+
} catch (err) {
|
|
1307
|
+
throw new CofhesdkError({
|
|
1308
|
+
code: "ZK_MOCKS_CREATE_PROOF_SIGNATURE_FAILED" /* ZkMocksCreateProofSignatureFailed */,
|
|
1309
|
+
message: `mockZkVerifySign createProofSignatures failed while calling signMessage`,
|
|
1310
|
+
cause: err instanceof Error ? err : void 0,
|
|
1311
|
+
context: {
|
|
1312
|
+
items,
|
|
1313
|
+
securityZone
|
|
1314
|
+
}
|
|
1315
|
+
});
|
|
1316
|
+
}
|
|
1317
|
+
if (signatures.length !== items.length) {
|
|
1318
|
+
throw new CofhesdkError({
|
|
1319
|
+
code: "ZK_MOCKS_CREATE_PROOF_SIGNATURE_FAILED" /* ZkMocksCreateProofSignatureFailed */,
|
|
1320
|
+
message: `mockZkVerifySign createProofSignatures returned incorrect number of signatures`,
|
|
1321
|
+
context: {
|
|
1322
|
+
items,
|
|
1323
|
+
securityZone
|
|
1324
|
+
}
|
|
1325
|
+
});
|
|
1326
|
+
}
|
|
1327
|
+
return signatures;
|
|
1328
|
+
}
|
|
1329
|
+
async function cofheMocksZkVerifySign(items, account, securityZone, publicClient, walletClient, zkvWalletClient) {
|
|
1330
|
+
const _walletClient = zkvWalletClient ?? walletClient;
|
|
1331
|
+
const encryptableItems = await calcCtHashes(items, account, securityZone, publicClient);
|
|
1332
|
+
await insertCtHashes(encryptableItems, _walletClient);
|
|
1333
|
+
const signatures = await createProofSignatures(encryptableItems, securityZone);
|
|
1334
|
+
return encryptableItems.map((item, index) => ({
|
|
1335
|
+
ct_hash: item.ctHash.toString(),
|
|
1336
|
+
signature: signatures[index]
|
|
1337
|
+
}));
|
|
1338
|
+
}
|
|
1339
|
+
function createKeysStore(storage) {
|
|
1340
|
+
const keysStore = storage ? createStore()(
|
|
1341
|
+
persist(
|
|
1342
|
+
() => ({
|
|
1343
|
+
fhe: {},
|
|
1344
|
+
crs: {}
|
|
1345
|
+
}),
|
|
1346
|
+
{
|
|
1347
|
+
name: "cofhesdk-keys",
|
|
1348
|
+
storage: createJSONStorage(() => storage),
|
|
1349
|
+
merge: (persistedState, currentState) => {
|
|
1350
|
+
const persisted = persistedState;
|
|
1351
|
+
const current = currentState;
|
|
1352
|
+
const mergedFhe = { ...persisted.fhe };
|
|
1353
|
+
const allChainIds = /* @__PURE__ */ new Set([...Object.keys(current.fhe), ...Object.keys(persisted.fhe)]);
|
|
1354
|
+
for (const chainId of allChainIds) {
|
|
1355
|
+
const persistedZones = persisted.fhe[chainId] || {};
|
|
1356
|
+
const currentZones = current.fhe[chainId] || {};
|
|
1357
|
+
mergedFhe[chainId] = { ...persistedZones, ...currentZones };
|
|
1358
|
+
}
|
|
1359
|
+
const mergedCrs = { ...persisted.crs, ...current.crs };
|
|
1360
|
+
return {
|
|
1361
|
+
fhe: mergedFhe,
|
|
1362
|
+
crs: mergedCrs
|
|
1363
|
+
};
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
)
|
|
1367
|
+
) : createStore()(() => ({
|
|
1368
|
+
fhe: {},
|
|
1369
|
+
crs: {}
|
|
1370
|
+
}));
|
|
1371
|
+
const getFheKey = (chainId, securityZone = 0) => {
|
|
1372
|
+
if (chainId == null || securityZone == null)
|
|
1373
|
+
return void 0;
|
|
1374
|
+
const stored = keysStore.getState().fhe[chainId]?.[securityZone];
|
|
1375
|
+
return stored;
|
|
1376
|
+
};
|
|
1377
|
+
const getCrs = (chainId) => {
|
|
1378
|
+
if (chainId == null)
|
|
1379
|
+
return void 0;
|
|
1380
|
+
const stored = keysStore.getState().crs[chainId];
|
|
1381
|
+
return stored;
|
|
1382
|
+
};
|
|
1383
|
+
const setFheKey = (chainId, securityZone, key) => {
|
|
1384
|
+
keysStore.setState(
|
|
1385
|
+
produce((state) => {
|
|
1386
|
+
if (state.fhe[chainId] == null)
|
|
1387
|
+
state.fhe[chainId] = {};
|
|
1388
|
+
state.fhe[chainId][securityZone] = key;
|
|
1389
|
+
})
|
|
1390
|
+
);
|
|
1391
|
+
};
|
|
1392
|
+
const setCrs = (chainId, crs) => {
|
|
1393
|
+
keysStore.setState(
|
|
1394
|
+
produce((state) => {
|
|
1395
|
+
state.crs[chainId] = crs;
|
|
1396
|
+
})
|
|
1397
|
+
);
|
|
1398
|
+
};
|
|
1399
|
+
const clearKeysStorage = async () => {
|
|
1400
|
+
if (storage) {
|
|
1401
|
+
await storage.removeItem("cofhesdk-keys");
|
|
1402
|
+
}
|
|
1403
|
+
};
|
|
1404
|
+
const rehydrateKeysStore = async () => {
|
|
1405
|
+
if ("persist" in keysStore) {
|
|
1406
|
+
if (keysStore.persist.hasHydrated())
|
|
1407
|
+
return;
|
|
1408
|
+
await keysStore.persist.rehydrate();
|
|
1409
|
+
}
|
|
1410
|
+
};
|
|
1411
|
+
return {
|
|
1412
|
+
store: keysStore,
|
|
1413
|
+
getFheKey,
|
|
1414
|
+
getCrs,
|
|
1415
|
+
setFheKey,
|
|
1416
|
+
setCrs,
|
|
1417
|
+
clearKeysStorage,
|
|
1418
|
+
rehydrateKeysStore
|
|
1419
|
+
};
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
// core/encrypt/encryptInputsBuilder.ts
|
|
1423
|
+
var EncryptInputsBuilder = class extends BaseBuilder {
|
|
1424
|
+
securityZone;
|
|
1425
|
+
stepCallback;
|
|
1426
|
+
inputItems;
|
|
1427
|
+
zkvWalletClient;
|
|
1428
|
+
tfhePublicKeyDeserializer;
|
|
1429
|
+
compactPkeCrsDeserializer;
|
|
1430
|
+
zkBuilderAndCrsGenerator;
|
|
1431
|
+
initTfhe;
|
|
1432
|
+
keysStorage;
|
|
1433
|
+
stepTimestamps = {
|
|
1434
|
+
["initTfhe" /* InitTfhe */]: 0,
|
|
1435
|
+
["fetchKeys" /* FetchKeys */]: 0,
|
|
1436
|
+
["pack" /* Pack */]: 0,
|
|
1437
|
+
["prove" /* Prove */]: 0,
|
|
1438
|
+
["verify" /* Verify */]: 0
|
|
1439
|
+
};
|
|
1440
|
+
constructor(params) {
|
|
1441
|
+
super({
|
|
1442
|
+
config: params.config,
|
|
1443
|
+
publicClient: params.publicClient,
|
|
1444
|
+
walletClient: params.walletClient,
|
|
1445
|
+
chainId: params.chainId,
|
|
1446
|
+
account: params.account,
|
|
1447
|
+
requireConnected: params.requireConnected
|
|
1448
|
+
});
|
|
1449
|
+
this.inputItems = params.inputs;
|
|
1450
|
+
this.securityZone = params.securityZone ?? 0;
|
|
1451
|
+
this.zkvWalletClient = params.zkvWalletClient;
|
|
1452
|
+
this.tfhePublicKeyDeserializer = params.tfhePublicKeyDeserializer;
|
|
1453
|
+
this.compactPkeCrsDeserializer = params.compactPkeCrsDeserializer;
|
|
1454
|
+
this.zkBuilderAndCrsGenerator = params.zkBuilderAndCrsGenerator;
|
|
1455
|
+
this.initTfhe = params.initTfhe;
|
|
1456
|
+
this.keysStorage = params.keysStorage;
|
|
1457
|
+
}
|
|
1458
|
+
/**
|
|
1459
|
+
* @param account - Account that will create the tx using the encrypted inputs.
|
|
1460
|
+
*
|
|
1461
|
+
* If not provided, the account will be fetched from the connected walletClient.
|
|
1462
|
+
*
|
|
1463
|
+
* Example:
|
|
1464
|
+
* ```typescript
|
|
1465
|
+
* const encrypted = await encryptInputs([Encryptable.uint128(10n)])
|
|
1466
|
+
* .setAccount("0x123")
|
|
1467
|
+
* .encrypt();
|
|
1468
|
+
* ```
|
|
1469
|
+
*
|
|
1470
|
+
* @returns The chainable EncryptInputsBuilder instance.
|
|
1471
|
+
*/
|
|
1472
|
+
setAccount(account) {
|
|
1473
|
+
this.account = account;
|
|
1474
|
+
return this;
|
|
1475
|
+
}
|
|
1476
|
+
getAccount() {
|
|
1477
|
+
return this.account;
|
|
1478
|
+
}
|
|
1479
|
+
/**
|
|
1480
|
+
* @param chainId - Chain that will consume the encrypted inputs.
|
|
1481
|
+
*
|
|
1482
|
+
* If not provided, the chainId will be fetched from the connected publicClient.
|
|
1483
|
+
*
|
|
1484
|
+
* Example:
|
|
1485
|
+
* ```typescript
|
|
1486
|
+
* const encrypted = await encryptInputs([Encryptable.uint128(10n)])
|
|
1487
|
+
* .setChainId(11155111)
|
|
1488
|
+
* .encrypt();
|
|
1489
|
+
* ```
|
|
1490
|
+
*
|
|
1491
|
+
* @returns The chainable EncryptInputsBuilder instance.
|
|
1492
|
+
*/
|
|
1493
|
+
setChainId(chainId) {
|
|
1494
|
+
this.chainId = chainId;
|
|
1495
|
+
return this;
|
|
1496
|
+
}
|
|
1497
|
+
getChainId() {
|
|
1498
|
+
return this.chainId;
|
|
1499
|
+
}
|
|
1500
|
+
/**
|
|
1501
|
+
* @param securityZone - Security zone to encrypt the inputs for.
|
|
1502
|
+
*
|
|
1503
|
+
* If not provided, the default securityZone 0 will be used.
|
|
1504
|
+
*
|
|
1505
|
+
* Example:
|
|
1506
|
+
* ```typescript
|
|
1507
|
+
* const encrypted = await encryptInputs([Encryptable.uint128(10n)])
|
|
1508
|
+
* .setSecurityZone(1)
|
|
1509
|
+
* .encrypt();
|
|
1510
|
+
* ```
|
|
1511
|
+
*
|
|
1512
|
+
* @returns The chainable EncryptInputsBuilder instance.
|
|
1513
|
+
*/
|
|
1514
|
+
setSecurityZone(securityZone) {
|
|
1515
|
+
this.securityZone = securityZone;
|
|
1516
|
+
return this;
|
|
1517
|
+
}
|
|
1518
|
+
getSecurityZone() {
|
|
1519
|
+
return this.securityZone;
|
|
1520
|
+
}
|
|
1521
|
+
/**
|
|
1522
|
+
* @param callback - Function to be called with the encryption step.
|
|
1523
|
+
*
|
|
1524
|
+
* Useful for debugging and tracking the progress of the encryption process.
|
|
1525
|
+
* Useful for a UI element that shows the progress of the encryption process.
|
|
1526
|
+
*
|
|
1527
|
+
* Example:
|
|
1528
|
+
* ```typescript
|
|
1529
|
+
* const encrypted = await encryptInputs([Encryptable.uint128(10n)])
|
|
1530
|
+
* .setStepCallback((step: EncryptStep) => console.log(step))
|
|
1531
|
+
* .encrypt();
|
|
1532
|
+
* ```
|
|
1533
|
+
*
|
|
1534
|
+
* @returns The EncryptInputsBuilder instance.
|
|
1535
|
+
*/
|
|
1536
|
+
setStepCallback(callback) {
|
|
1537
|
+
this.stepCallback = callback;
|
|
1538
|
+
return this;
|
|
1539
|
+
}
|
|
1540
|
+
getStepCallback() {
|
|
1541
|
+
return this.stepCallback;
|
|
1542
|
+
}
|
|
1543
|
+
/**
|
|
1544
|
+
* Fires the step callback if set
|
|
1545
|
+
*/
|
|
1546
|
+
fireStepStart(step, context = {}) {
|
|
1547
|
+
if (!this.stepCallback)
|
|
1548
|
+
return;
|
|
1549
|
+
this.stepTimestamps[step] = Date.now();
|
|
1550
|
+
this.stepCallback(step, { ...context, isStart: true, isEnd: false, duration: 0 });
|
|
1551
|
+
}
|
|
1552
|
+
fireStepEnd(step, context = {}) {
|
|
1553
|
+
if (!this.stepCallback)
|
|
1554
|
+
return;
|
|
1555
|
+
const duration = Date.now() - this.stepTimestamps[step];
|
|
1556
|
+
this.stepCallback(step, { ...context, isStart: false, isEnd: true, duration });
|
|
1557
|
+
}
|
|
1558
|
+
/**
|
|
1559
|
+
* tfhePublicKeyDeserializer is a platform-specific dependency injected into core/createCofhesdkClientBase by web/createCofhesdkClient and node/createCofhesdkClient
|
|
1560
|
+
* web/ uses zama "tfhe"
|
|
1561
|
+
* node/ uses zama "node-tfhe"
|
|
1562
|
+
* Users should not set this manually.
|
|
1563
|
+
*/
|
|
1564
|
+
getTfhePublicKeyDeserializerOrThrow() {
|
|
1565
|
+
if (this.tfhePublicKeyDeserializer)
|
|
1566
|
+
return this.tfhePublicKeyDeserializer;
|
|
1567
|
+
throw new CofhesdkError({
|
|
1568
|
+
code: "MISSING_TFHE_PUBLIC_KEY_DESERIALIZER" /* MissingTfhePublicKeyDeserializer */,
|
|
1569
|
+
message: "EncryptInputsBuilder tfhePublicKeyDeserializer is undefined",
|
|
1570
|
+
hint: "Ensure client has been created with a tfhePublicKeyDeserializer.",
|
|
1571
|
+
context: {
|
|
1572
|
+
tfhePublicKeyDeserializer: this.tfhePublicKeyDeserializer
|
|
1573
|
+
}
|
|
1574
|
+
});
|
|
1575
|
+
}
|
|
1576
|
+
/**
|
|
1577
|
+
* compactPkeCrsDeserializer is a platform-specific dependency injected into core/createCofhesdkClientBase by web/createCofhesdkClient and node/createCofhesdkClient
|
|
1578
|
+
* web/ uses zama "tfhe"
|
|
1579
|
+
* node/ uses zama "node-tfhe"
|
|
1580
|
+
* Users should not set this manually.
|
|
1581
|
+
*/
|
|
1582
|
+
getCompactPkeCrsDeserializerOrThrow() {
|
|
1583
|
+
if (this.compactPkeCrsDeserializer)
|
|
1584
|
+
return this.compactPkeCrsDeserializer;
|
|
1585
|
+
throw new CofhesdkError({
|
|
1586
|
+
code: "MISSING_COMPACT_PKE_CRS_DESERIALIZER" /* MissingCompactPkeCrsDeserializer */,
|
|
1587
|
+
message: "EncryptInputsBuilder compactPkeCrsDeserializer is undefined",
|
|
1588
|
+
hint: "Ensure client has been created with a compactPkeCrsDeserializer.",
|
|
1589
|
+
context: {
|
|
1590
|
+
compactPkeCrsDeserializer: this.compactPkeCrsDeserializer
|
|
1591
|
+
}
|
|
1592
|
+
});
|
|
1593
|
+
}
|
|
1594
|
+
/**
|
|
1595
|
+
* zkVerifierUrl is included in the chains exported from cofhesdk/chains for use in CofhesdkConfig.supportedChains
|
|
1596
|
+
* Users should generally not set this manually.
|
|
1597
|
+
*/
|
|
1598
|
+
async getZkVerifierUrl() {
|
|
1599
|
+
const config = this.getConfigOrThrow();
|
|
1600
|
+
const chainId = await this.getChainIdOrThrow();
|
|
1601
|
+
return getZkVerifierUrlOrThrow(config, chainId);
|
|
1602
|
+
}
|
|
1603
|
+
/**
|
|
1604
|
+
* initTfhe is a platform-specific dependency injected into core/createCofhesdkClientBase by web/createCofhesdkClient and node/createCofhesdkClient
|
|
1605
|
+
* web/ uses zama "tfhe"
|
|
1606
|
+
* node/ uses zama "node-tfhe"
|
|
1607
|
+
* Users should not set this manually.
|
|
1608
|
+
*/
|
|
1609
|
+
async initTfheOrThrow() {
|
|
1610
|
+
if (!this.initTfhe)
|
|
1611
|
+
return false;
|
|
1612
|
+
try {
|
|
1613
|
+
return await this.initTfhe();
|
|
1614
|
+
} catch (error) {
|
|
1615
|
+
throw CofhesdkError.fromError(error, {
|
|
1616
|
+
code: "INIT_TFHE_FAILED" /* InitTfheFailed */,
|
|
1617
|
+
message: `Failed to initialize TFHE`,
|
|
1618
|
+
context: {
|
|
1619
|
+
initTfhe: this.initTfhe
|
|
1620
|
+
}
|
|
1621
|
+
});
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
1624
|
+
/**
|
|
1625
|
+
* Fetches the FHE key and CRS from the CoFHE API
|
|
1626
|
+
* If the key/crs already exists in the store it is returned, else it is fetched, stored, and returned
|
|
1627
|
+
*/
|
|
1628
|
+
async fetchFheKeyAndCrs() {
|
|
1629
|
+
const config = this.getConfigOrThrow();
|
|
1630
|
+
const chainId = await this.getChainIdOrThrow();
|
|
1631
|
+
const compactPkeCrsDeserializer = this.getCompactPkeCrsDeserializerOrThrow();
|
|
1632
|
+
const tfhePublicKeyDeserializer = this.getTfhePublicKeyDeserializerOrThrow();
|
|
1633
|
+
const securityZone = this.getSecurityZone();
|
|
1634
|
+
try {
|
|
1635
|
+
await this.keysStorage?.rehydrateKeysStore();
|
|
1636
|
+
} catch (error) {
|
|
1637
|
+
throw CofhesdkError.fromError(error, {
|
|
1638
|
+
code: "REHYDRATE_KEYS_STORE_FAILED" /* RehydrateKeysStoreFailed */,
|
|
1639
|
+
message: `Failed to rehydrate keys store`,
|
|
1640
|
+
context: {
|
|
1641
|
+
keysStorage: this.keysStorage
|
|
1642
|
+
}
|
|
1643
|
+
});
|
|
1644
|
+
}
|
|
1645
|
+
let fheKey;
|
|
1646
|
+
let fheKeyFetchedFromCoFHE = false;
|
|
1647
|
+
let crs;
|
|
1648
|
+
let crsFetchedFromCoFHE = false;
|
|
1649
|
+
try {
|
|
1650
|
+
[[fheKey, fheKeyFetchedFromCoFHE], [crs, crsFetchedFromCoFHE]] = await fetchKeys(
|
|
1651
|
+
config,
|
|
1652
|
+
chainId,
|
|
1653
|
+
securityZone,
|
|
1654
|
+
tfhePublicKeyDeserializer,
|
|
1655
|
+
compactPkeCrsDeserializer,
|
|
1656
|
+
this.keysStorage
|
|
1657
|
+
);
|
|
1658
|
+
} catch (error) {
|
|
1659
|
+
throw CofhesdkError.fromError(error, {
|
|
1660
|
+
code: "FETCH_KEYS_FAILED" /* FetchKeysFailed */,
|
|
1661
|
+
message: `Failed to fetch FHE key and CRS`,
|
|
1662
|
+
context: {
|
|
1663
|
+
config,
|
|
1664
|
+
chainId,
|
|
1665
|
+
securityZone,
|
|
1666
|
+
compactPkeCrsDeserializer,
|
|
1667
|
+
tfhePublicKeyDeserializer
|
|
1668
|
+
}
|
|
1669
|
+
});
|
|
1670
|
+
}
|
|
1671
|
+
if (!fheKey) {
|
|
1672
|
+
throw new CofhesdkError({
|
|
1673
|
+
code: "MISSING_FHE_KEY" /* MissingFheKey */,
|
|
1674
|
+
message: `FHE key not found`,
|
|
1675
|
+
context: {
|
|
1676
|
+
chainId,
|
|
1677
|
+
securityZone
|
|
1678
|
+
}
|
|
1679
|
+
});
|
|
1680
|
+
}
|
|
1681
|
+
if (!crs) {
|
|
1682
|
+
throw new CofhesdkError({
|
|
1683
|
+
code: "MISSING_CRS" /* MissingCrs */,
|
|
1684
|
+
message: `CRS not found for chainId <${this.chainId}>`,
|
|
1685
|
+
context: {
|
|
1686
|
+
chainId
|
|
1687
|
+
}
|
|
1688
|
+
});
|
|
1689
|
+
}
|
|
1690
|
+
return { fheKey, fheKeyFetchedFromCoFHE, crs, crsFetchedFromCoFHE };
|
|
1691
|
+
}
|
|
1692
|
+
/**
|
|
1693
|
+
* zkBuilderAndCrsGenerator is a platform-specific dependency injected into core/createCofhesdkClientBase by web/createCofhesdkClient and node/createCofhesdkClient
|
|
1694
|
+
* web/ uses zama "tfhe"
|
|
1695
|
+
* node/ uses zama "node-tfhe"
|
|
1696
|
+
* Users should not set this manually.
|
|
1697
|
+
*
|
|
1698
|
+
* Generates the zkBuilder and zkCrs from the fheKey and crs
|
|
1699
|
+
*/
|
|
1700
|
+
generateZkBuilderAndCrs(fheKey, crs) {
|
|
1701
|
+
const zkBuilderAndCrsGenerator = this.zkBuilderAndCrsGenerator;
|
|
1702
|
+
if (!zkBuilderAndCrsGenerator) {
|
|
1703
|
+
throw new CofhesdkError({
|
|
1704
|
+
code: "MISSING_ZK_BUILDER_AND_CRS_GENERATOR" /* MissingZkBuilderAndCrsGenerator */,
|
|
1705
|
+
message: `zkBuilderAndCrsGenerator is undefined`,
|
|
1706
|
+
hint: "Ensure client has been created with a zkBuilderAndCrsGenerator.",
|
|
1707
|
+
context: {
|
|
1708
|
+
zkBuilderAndCrsGenerator: this.zkBuilderAndCrsGenerator
|
|
1709
|
+
}
|
|
1710
|
+
});
|
|
1711
|
+
}
|
|
1712
|
+
return zkBuilderAndCrsGenerator(fheKey, crs);
|
|
1713
|
+
}
|
|
1714
|
+
/**
|
|
1715
|
+
* @dev Encrypt against the cofheMocks instead of CoFHE
|
|
1716
|
+
*
|
|
1717
|
+
* In the cofheMocks, the MockZkVerifier contract is deployed on hardhat to a fixed address, this contract handles mocking the zk verifying.
|
|
1718
|
+
* cofheMocksInsertPackedHashes - stores the ctHashes and their plaintext values for on-chain mocking of FHE operations.
|
|
1719
|
+
* cofheMocksZkCreateProofSignatures - creates signatures to be included in the encrypted inputs. The signers address is known and verified in the mock contracts.
|
|
1720
|
+
*/
|
|
1721
|
+
async mocksEncrypt(account) {
|
|
1722
|
+
this.fireStepStart("initTfhe" /* InitTfhe */);
|
|
1723
|
+
await sleep(100);
|
|
1724
|
+
this.fireStepEnd("initTfhe" /* InitTfhe */, { tfheInitializationExecuted: false });
|
|
1725
|
+
this.fireStepStart("fetchKeys" /* FetchKeys */);
|
|
1726
|
+
await sleep(100);
|
|
1727
|
+
this.fireStepEnd("fetchKeys" /* FetchKeys */, { fheKeyFetchedFromCoFHE: false, crsFetchedFromCoFHE: false });
|
|
1728
|
+
this.fireStepStart("pack" /* Pack */);
|
|
1729
|
+
await cofheMocksCheckEncryptableBits(this.inputItems);
|
|
1730
|
+
await sleep(100);
|
|
1731
|
+
this.fireStepEnd("pack" /* Pack */);
|
|
1732
|
+
this.fireStepStart("prove" /* Prove */);
|
|
1733
|
+
await sleep(500);
|
|
1734
|
+
this.fireStepEnd("prove" /* Prove */);
|
|
1735
|
+
this.fireStepStart("verify" /* Verify */);
|
|
1736
|
+
await sleep(500);
|
|
1737
|
+
const signedResults = await cofheMocksZkVerifySign(
|
|
1738
|
+
this.inputItems,
|
|
1739
|
+
account,
|
|
1740
|
+
this.securityZone,
|
|
1741
|
+
this.getPublicClientOrThrow(),
|
|
1742
|
+
this.getWalletClientOrThrow(),
|
|
1743
|
+
this.zkvWalletClient
|
|
1744
|
+
);
|
|
1745
|
+
const encryptedInputs = signedResults.map(({ ct_hash, signature }, index) => ({
|
|
1746
|
+
ctHash: BigInt(ct_hash),
|
|
1747
|
+
securityZone: this.securityZone,
|
|
1748
|
+
utype: this.inputItems[index].utype,
|
|
1749
|
+
signature
|
|
1750
|
+
}));
|
|
1751
|
+
this.fireStepEnd("verify" /* Verify */);
|
|
1752
|
+
return encryptedInputs;
|
|
1753
|
+
}
|
|
1754
|
+
/**
|
|
1755
|
+
* In the production context, perform a true encryption with the CoFHE coprocessor.
|
|
1756
|
+
*/
|
|
1757
|
+
async productionEncrypt(account, chainId) {
|
|
1758
|
+
this.fireStepStart("initTfhe" /* InitTfhe */);
|
|
1759
|
+
const tfheInitializationExecuted = await this.initTfheOrThrow();
|
|
1760
|
+
this.fireStepEnd("initTfhe" /* InitTfhe */, { tfheInitializationExecuted });
|
|
1761
|
+
this.fireStepStart("fetchKeys" /* FetchKeys */);
|
|
1762
|
+
const { fheKey, fheKeyFetchedFromCoFHE, crs, crsFetchedFromCoFHE } = await this.fetchFheKeyAndCrs();
|
|
1763
|
+
let { zkBuilder, zkCrs } = this.generateZkBuilderAndCrs(fheKey, crs);
|
|
1764
|
+
this.fireStepEnd("fetchKeys" /* FetchKeys */, { fheKeyFetchedFromCoFHE, crsFetchedFromCoFHE });
|
|
1765
|
+
this.fireStepStart("pack" /* Pack */);
|
|
1766
|
+
zkBuilder = zkPack(this.inputItems, zkBuilder);
|
|
1767
|
+
this.fireStepEnd("pack" /* Pack */);
|
|
1768
|
+
this.fireStepStart("prove" /* Prove */);
|
|
1769
|
+
const proof = await zkProve(zkBuilder, zkCrs, account, this.securityZone, chainId);
|
|
1770
|
+
this.fireStepEnd("prove" /* Prove */);
|
|
1771
|
+
this.fireStepStart("verify" /* Verify */);
|
|
1772
|
+
const zkVerifierUrl = await this.getZkVerifierUrl();
|
|
1773
|
+
const verifyResults = await zkVerify(zkVerifierUrl, proof, account, this.securityZone, chainId);
|
|
1774
|
+
const encryptedInputs = verifyResults.map(
|
|
1775
|
+
({ ct_hash, signature }, index) => ({
|
|
1776
|
+
ctHash: BigInt(ct_hash),
|
|
1777
|
+
securityZone: this.securityZone,
|
|
1778
|
+
utype: this.inputItems[index].utype,
|
|
1779
|
+
signature
|
|
1780
|
+
})
|
|
1781
|
+
);
|
|
1782
|
+
this.fireStepEnd("verify" /* Verify */);
|
|
1783
|
+
return encryptedInputs;
|
|
1784
|
+
}
|
|
1785
|
+
/**
|
|
1786
|
+
* Final step of the encryption process. MUST BE CALLED LAST IN THE CHAIN.
|
|
1787
|
+
*
|
|
1788
|
+
* This will:
|
|
1789
|
+
* - Pack the encryptable items into a zk proof
|
|
1790
|
+
* - Prove the zk proof
|
|
1791
|
+
* - Verify the zk proof with CoFHE
|
|
1792
|
+
* - Package and return the encrypted inputs
|
|
1793
|
+
*
|
|
1794
|
+
* Example:
|
|
1795
|
+
* ```typescript
|
|
1796
|
+
* const encrypted = await encryptInputs([Encryptable.uint128(10n)])
|
|
1797
|
+
* .setAccount('0x123...890') // optional
|
|
1798
|
+
* .setChainId(11155111) // optional
|
|
1799
|
+
* .encrypt(); // execute
|
|
1800
|
+
* ```
|
|
1801
|
+
*
|
|
1802
|
+
* @returns The encrypted inputs.
|
|
1803
|
+
*/
|
|
1804
|
+
async encrypt() {
|
|
1805
|
+
return resultWrapper(async () => {
|
|
1806
|
+
await this.requireConnectedOrThrow();
|
|
1807
|
+
const account = await this.getAccountOrThrow();
|
|
1808
|
+
const chainId = await this.getChainIdOrThrow();
|
|
1809
|
+
if (chainId === hardhat$1.id) {
|
|
1810
|
+
return await this.mocksEncrypt(account);
|
|
1811
|
+
}
|
|
1812
|
+
return await this.productionEncrypt(account, chainId);
|
|
1813
|
+
});
|
|
1814
|
+
}
|
|
1815
|
+
};
|
|
1816
|
+
|
|
1817
|
+
// core/types.ts
|
|
1818
|
+
var FheTypes = /* @__PURE__ */ ((FheTypes2) => {
|
|
1819
|
+
FheTypes2[FheTypes2["Bool"] = 0] = "Bool";
|
|
1820
|
+
FheTypes2[FheTypes2["Uint4"] = 1] = "Uint4";
|
|
1821
|
+
FheTypes2[FheTypes2["Uint8"] = 2] = "Uint8";
|
|
1822
|
+
FheTypes2[FheTypes2["Uint16"] = 3] = "Uint16";
|
|
1823
|
+
FheTypes2[FheTypes2["Uint32"] = 4] = "Uint32";
|
|
1824
|
+
FheTypes2[FheTypes2["Uint64"] = 5] = "Uint64";
|
|
1825
|
+
FheTypes2[FheTypes2["Uint128"] = 6] = "Uint128";
|
|
1826
|
+
FheTypes2[FheTypes2["Uint160"] = 7] = "Uint160";
|
|
1827
|
+
FheTypes2[FheTypes2["Uint256"] = 8] = "Uint256";
|
|
1828
|
+
FheTypes2[FheTypes2["Uint512"] = 9] = "Uint512";
|
|
1829
|
+
FheTypes2[FheTypes2["Uint1024"] = 10] = "Uint1024";
|
|
1830
|
+
FheTypes2[FheTypes2["Uint2048"] = 11] = "Uint2048";
|
|
1831
|
+
FheTypes2[FheTypes2["Uint2"] = 12] = "Uint2";
|
|
1832
|
+
FheTypes2[FheTypes2["Uint6"] = 13] = "Uint6";
|
|
1833
|
+
FheTypes2[FheTypes2["Uint10"] = 14] = "Uint10";
|
|
1834
|
+
FheTypes2[FheTypes2["Uint12"] = 15] = "Uint12";
|
|
1835
|
+
FheTypes2[FheTypes2["Uint14"] = 16] = "Uint14";
|
|
1836
|
+
FheTypes2[FheTypes2["Int2"] = 17] = "Int2";
|
|
1837
|
+
FheTypes2[FheTypes2["Int4"] = 18] = "Int4";
|
|
1838
|
+
FheTypes2[FheTypes2["Int6"] = 19] = "Int6";
|
|
1839
|
+
FheTypes2[FheTypes2["Int8"] = 20] = "Int8";
|
|
1840
|
+
FheTypes2[FheTypes2["Int10"] = 21] = "Int10";
|
|
1841
|
+
FheTypes2[FheTypes2["Int12"] = 22] = "Int12";
|
|
1842
|
+
FheTypes2[FheTypes2["Int14"] = 23] = "Int14";
|
|
1843
|
+
FheTypes2[FheTypes2["Int16"] = 24] = "Int16";
|
|
1844
|
+
FheTypes2[FheTypes2["Int32"] = 25] = "Int32";
|
|
1845
|
+
FheTypes2[FheTypes2["Int64"] = 26] = "Int64";
|
|
1846
|
+
FheTypes2[FheTypes2["Int128"] = 27] = "Int128";
|
|
1847
|
+
FheTypes2[FheTypes2["Int160"] = 28] = "Int160";
|
|
1848
|
+
FheTypes2[FheTypes2["Int256"] = 29] = "Int256";
|
|
1849
|
+
return FheTypes2;
|
|
1850
|
+
})(FheTypes || {});
|
|
1851
|
+
var FheUintUTypes = [
|
|
1852
|
+
2 /* Uint8 */,
|
|
1853
|
+
3 /* Uint16 */,
|
|
1854
|
+
4 /* Uint32 */,
|
|
1855
|
+
5 /* Uint64 */,
|
|
1856
|
+
6 /* Uint128 */
|
|
1857
|
+
// [U256-DISABLED]
|
|
1858
|
+
// FheTypes.Uint256,
|
|
1859
|
+
];
|
|
1860
|
+
var FheAllUTypes = [
|
|
1861
|
+
0 /* Bool */,
|
|
1862
|
+
2 /* Uint8 */,
|
|
1863
|
+
3 /* Uint16 */,
|
|
1864
|
+
4 /* Uint32 */,
|
|
1865
|
+
5 /* Uint64 */,
|
|
1866
|
+
6 /* Uint128 */,
|
|
1867
|
+
// [U256-DISABLED]
|
|
1868
|
+
// FheTypes.Uint256,
|
|
1869
|
+
7 /* Uint160 */
|
|
1870
|
+
];
|
|
1871
|
+
var Encryptable = {
|
|
1872
|
+
bool: (data, securityZone = 0) => ({ data, securityZone, utype: 0 /* Bool */ }),
|
|
1873
|
+
address: (data, securityZone = 0) => ({ data, securityZone, utype: 7 /* Uint160 */ }),
|
|
1874
|
+
uint8: (data, securityZone = 0) => ({ data, securityZone, utype: 2 /* Uint8 */ }),
|
|
1875
|
+
uint16: (data, securityZone = 0) => ({ data, securityZone, utype: 3 /* Uint16 */ }),
|
|
1876
|
+
uint32: (data, securityZone = 0) => ({ data, securityZone, utype: 4 /* Uint32 */ }),
|
|
1877
|
+
uint64: (data, securityZone = 0) => ({ data, securityZone, utype: 5 /* Uint64 */ }),
|
|
1878
|
+
uint128: (data, securityZone = 0) => ({ data, securityZone, utype: 6 /* Uint128 */ })
|
|
1879
|
+
// [U256-DISABLED]
|
|
1880
|
+
// uint256: (data: EncryptableUint256['data'], securityZone = 0) =>
|
|
1881
|
+
// ({ data, securityZone, utype: FheTypes.Uint256 }) as EncryptableUint256,
|
|
1882
|
+
};
|
|
1883
|
+
function isEncryptableItem(value) {
|
|
1884
|
+
return (
|
|
1885
|
+
// Is object and exists
|
|
1886
|
+
typeof value === "object" && value !== null && // Has securityZone
|
|
1887
|
+
"securityZone" in value && typeof value.securityZone === "number" && // Has utype
|
|
1888
|
+
"utype" in value && FheAllUTypes.includes(value.utype) && // Has data
|
|
1889
|
+
"data" in value && ["string", "number", "bigint", "boolean"].includes(typeof value.data)
|
|
1890
|
+
);
|
|
1891
|
+
}
|
|
1892
|
+
var EncryptStep = /* @__PURE__ */ ((EncryptStep2) => {
|
|
1893
|
+
EncryptStep2["InitTfhe"] = "initTfhe";
|
|
1894
|
+
EncryptStep2["FetchKeys"] = "fetchKeys";
|
|
1895
|
+
EncryptStep2["Pack"] = "pack";
|
|
1896
|
+
EncryptStep2["Prove"] = "prove";
|
|
1897
|
+
EncryptStep2["Verify"] = "verify";
|
|
1898
|
+
return EncryptStep2;
|
|
1899
|
+
})(EncryptStep || {});
|
|
1900
|
+
|
|
1901
|
+
// core/config.ts
|
|
1902
|
+
var CofhesdkConfigSchema = z.object({
|
|
1903
|
+
/** List of supported chain configurations */
|
|
1904
|
+
supportedChains: z.array(z.custom()),
|
|
1905
|
+
/** Strategy for fetching FHE keys */
|
|
1906
|
+
fheKeysPrefetching: z.enum(["CONNECTED_CHAIN", "SUPPORTED_CHAINS", "OFF"]).optional().default("OFF"),
|
|
1907
|
+
/** How permits are generated */
|
|
1908
|
+
permitGeneration: z.enum(["ON_CONNECT", "ON_DECRYPT_HANDLES", "MANUAL"]).optional().default("ON_CONNECT"),
|
|
1909
|
+
/** Default permit expiration in seconds, default is 30 days */
|
|
1910
|
+
defaultPermitExpiration: z.number().optional().default(60 * 60 * 24 * 30),
|
|
1911
|
+
/** Storage method for fhe keys (defaults to indexedDB on web, filesystem on node) */
|
|
1912
|
+
fheKeyStorage: z.object({
|
|
1913
|
+
getItem: z.function().args(z.string()).returns(z.promise(z.any())),
|
|
1914
|
+
setItem: z.function().args(z.string(), z.any()).returns(z.promise(z.void())),
|
|
1915
|
+
removeItem: z.function().args(z.string()).returns(z.promise(z.void()))
|
|
1916
|
+
}).or(z.null()).default(null),
|
|
1917
|
+
/** Mocks configs */
|
|
1918
|
+
mocks: z.object({
|
|
1919
|
+
sealOutputDelay: z.number().optional().default(0)
|
|
1920
|
+
}).optional().default({ sealOutputDelay: 0 }),
|
|
1921
|
+
/** Internal configuration */
|
|
1922
|
+
_internal: z.object({
|
|
1923
|
+
zkvWalletClient: z.any().optional()
|
|
1924
|
+
}).optional()
|
|
1925
|
+
});
|
|
1926
|
+
function createCofhesdkConfigBase(config) {
|
|
1927
|
+
const result = CofhesdkConfigSchema.safeParse(config);
|
|
1928
|
+
if (!result.success) {
|
|
1929
|
+
throw new Error(`Invalid cofhesdk configuration: ${result.error.message}`);
|
|
1930
|
+
}
|
|
1931
|
+
return result.data;
|
|
1932
|
+
}
|
|
1933
|
+
var getCofhesdkConfigItem = (config, key) => {
|
|
1934
|
+
return config[key];
|
|
1935
|
+
};
|
|
1936
|
+
function getSupportedChainOrThrow(config, chainId) {
|
|
1937
|
+
const supportedChain = config.supportedChains.find((chain) => chain.id === chainId);
|
|
1938
|
+
if (!supportedChain) {
|
|
1939
|
+
throw new CofhesdkError({
|
|
1940
|
+
code: "UNSUPPORTED_CHAIN" /* UnsupportedChain */,
|
|
1941
|
+
message: `Config does not support chain <${chainId}>`,
|
|
1942
|
+
hint: "Ensure config passed to client has been created with this chain in the config.supportedChains array.",
|
|
1943
|
+
context: {
|
|
1944
|
+
chainId,
|
|
1945
|
+
supportedChainIds: config.supportedChains.map((c) => c.id)
|
|
1946
|
+
}
|
|
1947
|
+
});
|
|
1948
|
+
}
|
|
1949
|
+
return supportedChain;
|
|
1950
|
+
}
|
|
1951
|
+
function getCoFheUrlOrThrow(config, chainId) {
|
|
1952
|
+
const supportedChain = getSupportedChainOrThrow(config, chainId);
|
|
1953
|
+
const url = supportedChain.coFheUrl;
|
|
1954
|
+
if (!url) {
|
|
1955
|
+
throw new CofhesdkError({
|
|
1956
|
+
code: "MISSING_CONFIG" /* MissingConfig */,
|
|
1957
|
+
message: `CoFHE URL is not configured for chain <${chainId}>`,
|
|
1958
|
+
hint: "Ensure this chain config includes a coFheUrl property.",
|
|
1959
|
+
context: { chainId }
|
|
1960
|
+
});
|
|
1961
|
+
}
|
|
1962
|
+
return url;
|
|
1963
|
+
}
|
|
1964
|
+
function getZkVerifierUrlOrThrow(config, chainId) {
|
|
1965
|
+
const supportedChain = getSupportedChainOrThrow(config, chainId);
|
|
1966
|
+
const url = supportedChain.verifierUrl;
|
|
1967
|
+
if (!url) {
|
|
1968
|
+
throw new CofhesdkError({
|
|
1969
|
+
code: "ZK_VERIFIER_URL_UNINITIALIZED" /* ZkVerifierUrlUninitialized */,
|
|
1970
|
+
message: `ZK verifier URL is not configured for chain <${chainId}>`,
|
|
1971
|
+
hint: "Ensure this chain config includes a verifierUrl property.",
|
|
1972
|
+
context: { chainId }
|
|
1973
|
+
});
|
|
1974
|
+
}
|
|
1975
|
+
return url;
|
|
1976
|
+
}
|
|
1977
|
+
function getThresholdNetworkUrlOrThrow(config, chainId) {
|
|
1978
|
+
const supportedChain = getSupportedChainOrThrow(config, chainId);
|
|
1979
|
+
const url = supportedChain.thresholdNetworkUrl;
|
|
1980
|
+
if (!url) {
|
|
1981
|
+
throw new CofhesdkError({
|
|
1982
|
+
code: "THRESHOLD_NETWORK_URL_UNINITIALIZED" /* ThresholdNetworkUrlUninitialized */,
|
|
1983
|
+
message: `Threshold network URL is not configured for chain <${chainId}>`,
|
|
1984
|
+
hint: "Ensure this chain config includes a thresholdNetworkUrl property.",
|
|
1985
|
+
context: { chainId }
|
|
1986
|
+
});
|
|
1987
|
+
}
|
|
1988
|
+
return url;
|
|
1989
|
+
}
|
|
1990
|
+
|
|
1991
|
+
// core/fetchKeys.ts
|
|
1992
|
+
var PUBLIC_KEY_LENGTH_MIN = 15e3;
|
|
1993
|
+
var checkKeyValidity = (key, serializer) => {
|
|
1994
|
+
if (key == null || key.length === 0)
|
|
1995
|
+
return [false, `Key is null or empty <${key}>`];
|
|
1996
|
+
try {
|
|
1997
|
+
serializer(key);
|
|
1998
|
+
return [true, `Key is valid`];
|
|
1999
|
+
} catch (err) {
|
|
2000
|
+
return [false, `Serialization failed <${err}> key length <${key.length}>`];
|
|
2001
|
+
}
|
|
2002
|
+
};
|
|
2003
|
+
var fetchFhePublicKey = async (coFheUrl, chainId, securityZone, tfhePublicKeyDeserializer, keysStorage) => {
|
|
2004
|
+
const storedKey = keysStorage?.getFheKey(chainId, securityZone);
|
|
2005
|
+
const [storedKeyValid] = checkKeyValidity(storedKey, tfhePublicKeyDeserializer);
|
|
2006
|
+
if (storedKeyValid)
|
|
2007
|
+
return [storedKey, false];
|
|
2008
|
+
let pk_data = void 0;
|
|
2009
|
+
try {
|
|
2010
|
+
const pk_res = await fetch(`${coFheUrl}/GetNetworkPublicKey`, {
|
|
2011
|
+
method: "POST",
|
|
2012
|
+
headers: {
|
|
2013
|
+
"Content-Type": "application/json"
|
|
2014
|
+
},
|
|
2015
|
+
body: JSON.stringify({ securityZone })
|
|
2016
|
+
});
|
|
2017
|
+
const json = await pk_res.json();
|
|
2018
|
+
pk_data = json.publicKey;
|
|
2019
|
+
} catch (err) {
|
|
2020
|
+
throw new Error(`Error fetching FHE publicKey; fetching from CoFHE failed with error ${err}`);
|
|
2021
|
+
}
|
|
2022
|
+
if (pk_data == null || typeof pk_data !== "string") {
|
|
2023
|
+
throw new Error(`Error fetching FHE publicKey; fetched result invalid: missing or not a string`);
|
|
2024
|
+
}
|
|
2025
|
+
if (pk_data === "0x") {
|
|
2026
|
+
throw new Error("Error fetching FHE publicKey; provided chain is not FHE enabled / not found");
|
|
2027
|
+
}
|
|
2028
|
+
if (pk_data.length < PUBLIC_KEY_LENGTH_MIN) {
|
|
2029
|
+
throw new Error(
|
|
2030
|
+
`Error fetching FHE publicKey; got shorter than expected key length: ${pk_data.length}. Expected length >= ${PUBLIC_KEY_LENGTH_MIN}`
|
|
2031
|
+
);
|
|
2032
|
+
}
|
|
2033
|
+
try {
|
|
2034
|
+
tfhePublicKeyDeserializer(pk_data);
|
|
2035
|
+
} catch (err) {
|
|
2036
|
+
throw new Error(`Error serializing FHE publicKey; ${err}`);
|
|
2037
|
+
}
|
|
2038
|
+
keysStorage?.setFheKey(chainId, securityZone, pk_data);
|
|
2039
|
+
return [pk_data, true];
|
|
2040
|
+
};
|
|
2041
|
+
var fetchCrs = async (coFheUrl, chainId, securityZone, compactPkeCrsDeserializer, keysStorage) => {
|
|
2042
|
+
const storedKey = keysStorage?.getCrs(chainId);
|
|
2043
|
+
const [storedKeyValid] = checkKeyValidity(storedKey, compactPkeCrsDeserializer);
|
|
2044
|
+
if (storedKeyValid)
|
|
2045
|
+
return [storedKey, false];
|
|
2046
|
+
let crs_data = void 0;
|
|
2047
|
+
try {
|
|
2048
|
+
const crs_res = await fetch(`${coFheUrl}/GetCrs`, {
|
|
2049
|
+
method: "POST",
|
|
2050
|
+
headers: {
|
|
2051
|
+
"Content-Type": "application/json"
|
|
2052
|
+
},
|
|
2053
|
+
body: JSON.stringify({ securityZone })
|
|
2054
|
+
});
|
|
2055
|
+
const json = await crs_res.json();
|
|
2056
|
+
crs_data = json.crs;
|
|
2057
|
+
} catch (err) {
|
|
2058
|
+
throw new Error(`Error fetching CRS; fetching failed with error ${err}`);
|
|
2059
|
+
}
|
|
2060
|
+
if (crs_data == null || typeof crs_data !== "string") {
|
|
2061
|
+
throw new Error(`Error fetching CRS; invalid: missing or not a string`);
|
|
2062
|
+
}
|
|
2063
|
+
try {
|
|
2064
|
+
compactPkeCrsDeserializer(crs_data);
|
|
2065
|
+
} catch (err) {
|
|
2066
|
+
console.error(`Error serializing CRS ${err}`);
|
|
2067
|
+
throw new Error(`Error serializing CRS; ${err}`);
|
|
2068
|
+
}
|
|
2069
|
+
keysStorage?.setCrs(chainId, crs_data);
|
|
2070
|
+
return [crs_data, true];
|
|
2071
|
+
};
|
|
2072
|
+
var fetchKeys = async (config, chainId, securityZone = 0, tfhePublicKeyDeserializer, compactPkeCrsDeserializer, keysStorage) => {
|
|
2073
|
+
const coFheUrl = getCoFheUrlOrThrow(config, chainId);
|
|
2074
|
+
return await Promise.all([
|
|
2075
|
+
fetchFhePublicKey(coFheUrl, chainId, securityZone, tfhePublicKeyDeserializer, keysStorage),
|
|
2076
|
+
fetchCrs(coFheUrl, chainId, securityZone, compactPkeCrsDeserializer, keysStorage)
|
|
2077
|
+
]);
|
|
2078
|
+
};
|
|
2079
|
+
var fetchMultichainKeys = async (config, securityZone = 0, tfhePublicKeyDeserializer, compactPkeCrsDeserializer, keysStorage) => {
|
|
2080
|
+
await Promise.all(
|
|
2081
|
+
config.supportedChains.filter((chain) => chain.id !== hardhat.id).map(
|
|
2082
|
+
(chain) => fetchKeys(config, chain.id, securityZone, tfhePublicKeyDeserializer, compactPkeCrsDeserializer, keysStorage)
|
|
2083
|
+
)
|
|
2084
|
+
);
|
|
2085
|
+
};
|
|
2086
|
+
|
|
2087
|
+
// core/client.ts
|
|
2088
|
+
function createCofhesdkClientBase(opts) {
|
|
2089
|
+
const keysStorage = createKeysStore(opts.config.fheKeyStorage);
|
|
2090
|
+
let _publicClient = void 0;
|
|
2091
|
+
let _walletClient = void 0;
|
|
2092
|
+
const connectStore = createStore(() => ({
|
|
2093
|
+
connected: false,
|
|
2094
|
+
connecting: false,
|
|
2095
|
+
connectError: void 0,
|
|
2096
|
+
chainId: void 0,
|
|
2097
|
+
account: void 0
|
|
2098
|
+
}));
|
|
2099
|
+
const updateConnectState = (partial) => {
|
|
2100
|
+
connectStore.setState((state) => ({ ...state, ...partial }));
|
|
2101
|
+
};
|
|
2102
|
+
let _connectPromise = void 0;
|
|
2103
|
+
const _requireConnected = () => {
|
|
2104
|
+
const state = connectStore.getState();
|
|
2105
|
+
const notConnected = !state.connected || !_publicClient || !_walletClient || !state.account || !state.chainId;
|
|
2106
|
+
if (notConnected) {
|
|
2107
|
+
throw new CofhesdkError({
|
|
2108
|
+
code: "NOT_CONNECTED" /* NotConnected */,
|
|
2109
|
+
message: "Client must be connected, account and chainId must be initialized",
|
|
2110
|
+
hint: "Ensure client.connect() has been called and awaited.",
|
|
2111
|
+
context: {
|
|
2112
|
+
connected: state.connected,
|
|
2113
|
+
account: state.account,
|
|
2114
|
+
chainId: state.chainId,
|
|
2115
|
+
publicClient: _publicClient,
|
|
2116
|
+
walletClient: _walletClient
|
|
2117
|
+
}
|
|
2118
|
+
});
|
|
2119
|
+
}
|
|
2120
|
+
};
|
|
2121
|
+
const keyFetchResult = resultWrapper(async () => {
|
|
2122
|
+
if (opts.config.fheKeysPrefetching === "SUPPORTED_CHAINS") {
|
|
2123
|
+
await fetchMultichainKeys(
|
|
2124
|
+
opts.config,
|
|
2125
|
+
0,
|
|
2126
|
+
opts.tfhePublicKeyDeserializer,
|
|
2127
|
+
opts.compactPkeCrsDeserializer,
|
|
2128
|
+
keysStorage
|
|
2129
|
+
);
|
|
2130
|
+
return true;
|
|
2131
|
+
}
|
|
2132
|
+
return false;
|
|
2133
|
+
});
|
|
2134
|
+
async function connect(publicClient, walletClient) {
|
|
2135
|
+
const state = connectStore.getState();
|
|
2136
|
+
if (state.connected && _publicClient === publicClient && _walletClient === walletClient) {
|
|
2137
|
+
return Promise.resolve(ResultOk(true));
|
|
2138
|
+
}
|
|
2139
|
+
if (_connectPromise && _publicClient === publicClient && _walletClient === walletClient) {
|
|
2140
|
+
return _connectPromise;
|
|
2141
|
+
}
|
|
2142
|
+
updateConnectState({ connecting: true, connectError: null, connected: false });
|
|
2143
|
+
_connectPromise = resultWrapper(
|
|
2144
|
+
// try
|
|
2145
|
+
async () => {
|
|
2146
|
+
_publicClient = publicClient;
|
|
2147
|
+
_walletClient = walletClient;
|
|
2148
|
+
const chainId = await getPublicClientChainID(publicClient);
|
|
2149
|
+
const account = await getWalletClientAccount(walletClient);
|
|
2150
|
+
updateConnectState({ connecting: false, connected: true, chainId, account });
|
|
2151
|
+
return true;
|
|
2152
|
+
},
|
|
2153
|
+
// catch
|
|
2154
|
+
(e) => {
|
|
2155
|
+
updateConnectState({ connecting: false, connected: false, connectError: e });
|
|
2156
|
+
return false;
|
|
2157
|
+
},
|
|
2158
|
+
// finally
|
|
2159
|
+
() => {
|
|
2160
|
+
_connectPromise = void 0;
|
|
2161
|
+
}
|
|
2162
|
+
);
|
|
2163
|
+
return _connectPromise;
|
|
2164
|
+
}
|
|
2165
|
+
function encryptInputs(inputs) {
|
|
2166
|
+
const state = connectStore.getState();
|
|
2167
|
+
return new EncryptInputsBuilder({
|
|
2168
|
+
inputs,
|
|
2169
|
+
account: state.account ?? void 0,
|
|
2170
|
+
chainId: state.chainId ?? void 0,
|
|
2171
|
+
config: opts.config,
|
|
2172
|
+
publicClient: _publicClient ?? void 0,
|
|
2173
|
+
walletClient: _walletClient ?? void 0,
|
|
2174
|
+
zkvWalletClient: opts.config._internal?.zkvWalletClient,
|
|
2175
|
+
tfhePublicKeyDeserializer: opts.tfhePublicKeyDeserializer,
|
|
2176
|
+
compactPkeCrsDeserializer: opts.compactPkeCrsDeserializer,
|
|
2177
|
+
zkBuilderAndCrsGenerator: opts.zkBuilderAndCrsGenerator,
|
|
2178
|
+
initTfhe: opts.initTfhe,
|
|
2179
|
+
keysStorage,
|
|
2180
|
+
requireConnected: _requireConnected
|
|
2181
|
+
});
|
|
2182
|
+
}
|
|
2183
|
+
function decryptHandle(ctHash, utype) {
|
|
2184
|
+
const state = connectStore.getState();
|
|
2185
|
+
return new DecryptHandlesBuilder({
|
|
2186
|
+
ctHash,
|
|
2187
|
+
utype,
|
|
2188
|
+
chainId: state.chainId ?? void 0,
|
|
2189
|
+
account: state.account ?? void 0,
|
|
2190
|
+
config: opts.config,
|
|
2191
|
+
publicClient: _publicClient ?? void 0,
|
|
2192
|
+
walletClient: _walletClient ?? void 0,
|
|
2193
|
+
requireConnected: _requireConnected
|
|
2194
|
+
});
|
|
2195
|
+
}
|
|
2196
|
+
const _getChainIdAndAccount = (chainId, account) => {
|
|
2197
|
+
const state = connectStore.getState();
|
|
2198
|
+
const _chainId = chainId ?? state.chainId;
|
|
2199
|
+
const _account = account ?? state.account;
|
|
2200
|
+
if (_chainId == null || _account == null) {
|
|
2201
|
+
throw new CofhesdkError({
|
|
2202
|
+
code: "NOT_CONNECTED" /* NotConnected */,
|
|
2203
|
+
message: "ChainId or account not available.",
|
|
2204
|
+
hint: "Ensure client.connect() has been called, or provide chainId and account explicitly.",
|
|
2205
|
+
context: {
|
|
2206
|
+
chainId: _chainId,
|
|
2207
|
+
account: _account
|
|
2208
|
+
}
|
|
2209
|
+
});
|
|
2210
|
+
}
|
|
2211
|
+
return { chainId: _chainId, account: _account };
|
|
2212
|
+
};
|
|
2213
|
+
const clientPermits = {
|
|
2214
|
+
// Pass through store access
|
|
2215
|
+
getSnapshot: permits.getSnapshot,
|
|
2216
|
+
subscribe: permits.subscribe,
|
|
2217
|
+
// Creation methods (require connection)
|
|
2218
|
+
createSelf: async (options) => resultWrapper(async () => {
|
|
2219
|
+
_requireConnected();
|
|
2220
|
+
return permits.createSelf(options, _publicClient, _walletClient);
|
|
2221
|
+
}),
|
|
2222
|
+
createSharing: async (options) => resultWrapper(async () => {
|
|
2223
|
+
_requireConnected();
|
|
2224
|
+
return permits.createSharing(options, _publicClient, _walletClient);
|
|
2225
|
+
}),
|
|
2226
|
+
importShared: async (options) => resultWrapper(async () => {
|
|
2227
|
+
_requireConnected();
|
|
2228
|
+
return permits.importShared(options, _publicClient, _walletClient);
|
|
2229
|
+
}),
|
|
2230
|
+
// Retrieval methods (auto-fill chainId/account)
|
|
2231
|
+
getPermit: async (hash, chainId, account) => resultWrapper(async () => {
|
|
2232
|
+
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
2233
|
+
return permits.getPermit(_chainId, _account, hash);
|
|
2234
|
+
}),
|
|
2235
|
+
getPermits: async (chainId, account) => resultWrapper(async () => {
|
|
2236
|
+
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
2237
|
+
return permits.getPermits(_chainId, _account);
|
|
2238
|
+
}),
|
|
2239
|
+
getActivePermit: async (chainId, account) => resultWrapper(async () => {
|
|
2240
|
+
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
2241
|
+
return permits.getActivePermit(_chainId, _account);
|
|
2242
|
+
}),
|
|
2243
|
+
getActivePermitHash: async (chainId, account) => resultWrapper(async () => {
|
|
2244
|
+
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
2245
|
+
return permits.getActivePermitHash(_chainId, _account);
|
|
2246
|
+
}),
|
|
2247
|
+
// Mutation methods (auto-fill chainId/account)
|
|
2248
|
+
selectActivePermit: async (hash, chainId, account) => resultWrapper(async () => {
|
|
2249
|
+
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
2250
|
+
return permits.selectActivePermit(_chainId, _account, hash);
|
|
2251
|
+
}),
|
|
2252
|
+
removePermit: async (hash, chainId, account) => resultWrapper(async () => {
|
|
2253
|
+
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
2254
|
+
return permits.removePermit(_chainId, _account, hash);
|
|
2255
|
+
}),
|
|
2256
|
+
removeActivePermit: async (chainId, account) => resultWrapper(async () => {
|
|
2257
|
+
const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
|
|
2258
|
+
return permits.removeActivePermit(_chainId, _account);
|
|
2259
|
+
}),
|
|
2260
|
+
// Utils (no context needed)
|
|
2261
|
+
getHash: permits.getHash,
|
|
2262
|
+
serialize: permits.serialize,
|
|
2263
|
+
deserialize: permits.deserialize
|
|
2264
|
+
};
|
|
2265
|
+
return {
|
|
2266
|
+
// Zustand reactive accessors (don't export store directly to prevent mutation)
|
|
2267
|
+
getSnapshot: connectStore.getState,
|
|
2268
|
+
subscribe: connectStore.subscribe,
|
|
2269
|
+
// initialization results
|
|
2270
|
+
initializationResults: {
|
|
2271
|
+
keyFetchResult
|
|
2272
|
+
},
|
|
2273
|
+
// flags (read-only: reflect snapshot)
|
|
2274
|
+
get connected() {
|
|
2275
|
+
return connectStore.getState().connected;
|
|
2276
|
+
},
|
|
2277
|
+
get connecting() {
|
|
2278
|
+
return connectStore.getState().connecting;
|
|
2279
|
+
},
|
|
2280
|
+
// config & platform-specific (read-only)
|
|
2281
|
+
config: opts.config,
|
|
2282
|
+
connect,
|
|
2283
|
+
encryptInputs,
|
|
2284
|
+
decryptHandle,
|
|
2285
|
+
permits: clientPermits
|
|
2286
|
+
// Add SDK-specific methods below that require connection
|
|
2287
|
+
// Example:
|
|
2288
|
+
// async encryptData(data: unknown) {
|
|
2289
|
+
// requireConnected();
|
|
2290
|
+
// // Use _publicClient and _walletClient for implementation
|
|
2291
|
+
// },
|
|
2292
|
+
};
|
|
2293
|
+
}
|
|
2294
|
+
|
|
2295
|
+
export { CofhesdkError, CofhesdkErrorCode, DecryptHandlesBuilder, EncryptInputsBuilder, EncryptStep, Encryptable, FheAllUTypes, FheTypes, FheUintUTypes, ResultErr, ResultErrOrInternal, ResultHttpError, ResultOk, ResultValidationError, createCofhesdkClientBase, createCofhesdkConfigBase, createKeysStore, fetchKeys, fetchMultichainKeys, getCofhesdkConfigItem, isCofhesdkError, isEncryptableItem, resultWrapper, resultWrapperSync };
|