@cofhe/sdk 0.0.0-alpha-20260409113701
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 +146 -0
- package/adapters/ethers5.test.ts +174 -0
- package/adapters/ethers5.ts +36 -0
- package/adapters/ethers6.test.ts +169 -0
- package/adapters/ethers6.ts +36 -0
- package/adapters/hardhat-node.ts +167 -0
- package/adapters/hardhat.hh2.test.ts +159 -0
- package/adapters/hardhat.ts +36 -0
- package/adapters/index.test.ts +20 -0
- package/adapters/index.ts +5 -0
- package/adapters/smartWallet.ts +99 -0
- package/adapters/test-utils.ts +53 -0
- package/adapters/types.ts +6 -0
- package/adapters/wagmi.test.ts +156 -0
- package/adapters/wagmi.ts +17 -0
- package/chains/chains/arbSepolia.ts +14 -0
- package/chains/chains/baseSepolia.ts +14 -0
- package/chains/chains/hardhat.ts +15 -0
- package/chains/chains/localcofhe.ts +14 -0
- package/chains/chains/sepolia.ts +14 -0
- package/chains/chains.test.ts +50 -0
- package/chains/defineChain.ts +18 -0
- package/chains/index.ts +35 -0
- package/chains/types.ts +32 -0
- package/core/baseBuilder.ts +119 -0
- package/core/client.test.ts +429 -0
- package/core/client.ts +341 -0
- package/core/clientTypes.ts +119 -0
- package/core/config.test.ts +242 -0
- package/core/config.ts +225 -0
- package/core/consts.ts +22 -0
- package/core/decrypt/MockThresholdNetworkAbi.ts +179 -0
- package/core/decrypt/cofheMocksDecryptForTx.ts +84 -0
- package/core/decrypt/cofheMocksDecryptForView.ts +48 -0
- package/core/decrypt/decryptForTxBuilder.ts +359 -0
- package/core/decrypt/decryptForViewBuilder.ts +332 -0
- package/core/decrypt/decryptUtils.ts +28 -0
- package/core/decrypt/pollCallbacks.test.ts +194 -0
- package/core/decrypt/polling.ts +14 -0
- package/core/decrypt/tnDecryptUtils.ts +65 -0
- package/core/decrypt/tnDecryptV1.ts +171 -0
- package/core/decrypt/tnDecryptV2.ts +365 -0
- package/core/decrypt/tnSealOutputV1.ts +59 -0
- package/core/decrypt/tnSealOutputV2.ts +324 -0
- package/core/decrypt/verifyDecryptResult.ts +52 -0
- package/core/encrypt/MockZkVerifierAbi.ts +106 -0
- package/core/encrypt/cofheMocksZkVerifySign.ts +281 -0
- package/core/encrypt/encryptInputsBuilder.test.ts +747 -0
- package/core/encrypt/encryptInputsBuilder.ts +583 -0
- package/core/encrypt/encryptUtils.ts +67 -0
- package/core/encrypt/zkPackProveVerify.ts +335 -0
- package/core/error.ts +168 -0
- package/core/fetchKeys.test.ts +195 -0
- package/core/fetchKeys.ts +144 -0
- package/core/index.ts +106 -0
- package/core/keyStore.test.ts +226 -0
- package/core/keyStore.ts +154 -0
- package/core/permits.test.ts +493 -0
- package/core/permits.ts +201 -0
- package/core/types.ts +419 -0
- package/core/utils.ts +130 -0
- package/dist/adapters.cjs +88 -0
- package/dist/adapters.d.cts +14576 -0
- package/dist/adapters.d.ts +14576 -0
- package/dist/adapters.js +83 -0
- package/dist/chains.cjs +111 -0
- package/dist/chains.d.cts +121 -0
- package/dist/chains.d.ts +121 -0
- package/dist/chains.js +1 -0
- package/dist/chunk-36FBWLUS.js +3310 -0
- package/dist/chunk-7HLGHV67.js +990 -0
- package/dist/chunk-TBLR7NNE.js +102 -0
- package/dist/clientTypes-AVSCBet7.d.cts +998 -0
- package/dist/clientTypes-flH1ju82.d.ts +998 -0
- package/dist/core.cjs +4362 -0
- package/dist/core.d.cts +138 -0
- package/dist/core.d.ts +138 -0
- package/dist/core.js +3 -0
- package/dist/node.cjs +4225 -0
- package/dist/node.d.cts +22 -0
- package/dist/node.d.ts +22 -0
- package/dist/node.js +91 -0
- package/dist/permit-jRirYqFt.d.cts +376 -0
- package/dist/permit-jRirYqFt.d.ts +376 -0
- package/dist/permits.cjs +1025 -0
- package/dist/permits.d.cts +353 -0
- package/dist/permits.d.ts +353 -0
- package/dist/permits.js +1 -0
- package/dist/types-YiAC4gig.d.cts +33 -0
- package/dist/types-YiAC4gig.d.ts +33 -0
- package/dist/web.cjs +4434 -0
- package/dist/web.d.cts +42 -0
- package/dist/web.d.ts +42 -0
- package/dist/web.js +256 -0
- package/dist/zkProve.worker.cjs +93 -0
- package/dist/zkProve.worker.d.cts +2 -0
- package/dist/zkProve.worker.d.ts +2 -0
- package/dist/zkProve.worker.js +91 -0
- package/node/client.test.ts +159 -0
- package/node/config.test.ts +68 -0
- package/node/encryptInputs.test.ts +155 -0
- package/node/index.ts +97 -0
- package/node/storage.ts +51 -0
- package/package.json +121 -0
- package/permits/index.ts +68 -0
- package/permits/localstorage.test.ts +113 -0
- package/permits/onchain-utils.ts +221 -0
- package/permits/permit.test.ts +534 -0
- package/permits/permit.ts +386 -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 +88 -0
- package/permits/store.ts +156 -0
- package/permits/test-utils.ts +28 -0
- package/permits/types.ts +204 -0
- package/permits/utils.ts +58 -0
- package/permits/validation.test.ts +361 -0
- package/permits/validation.ts +327 -0
- package/web/client.web.test.ts +159 -0
- package/web/config.web.test.ts +69 -0
- package/web/const.ts +2 -0
- package/web/encryptInputs.web.test.ts +172 -0
- package/web/index.ts +166 -0
- package/web/storage.ts +49 -0
- package/web/worker.builder.web.test.ts +148 -0
- package/web/worker.config.web.test.ts +329 -0
- package/web/worker.output.web.test.ts +84 -0
- package/web/workerManager.test.ts +80 -0
- package/web/workerManager.ts +214 -0
- package/web/workerManager.web.test.ts +114 -0
- package/web/zkProve.worker.ts +133 -0
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
import { type Permission, type EthEncryptedData } from '@/permits';
|
|
2
|
+
|
|
3
|
+
import { CofheError, CofheErrorCode } from '../error.js';
|
|
4
|
+
import { type DecryptPollCallbackFunction } from '../types.js';
|
|
5
|
+
import { computeMinuteRampPollIntervalMs } from './polling.js';
|
|
6
|
+
|
|
7
|
+
// Polling configuration
|
|
8
|
+
const POLL_INTERVAL_MS = 1000; // 1 second
|
|
9
|
+
const POLL_MAX_INTERVAL_MS = 10_000; // 10 seconds
|
|
10
|
+
const POLL_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes
|
|
11
|
+
|
|
12
|
+
// V2 API response types
|
|
13
|
+
type SealOutputSubmitResponse = {
|
|
14
|
+
request_id: string;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
type SealOutputStatusResponse = {
|
|
18
|
+
request_id: string;
|
|
19
|
+
status: 'PROCESSING' | 'COMPLETED';
|
|
20
|
+
submitted_at: string;
|
|
21
|
+
completed_at?: string;
|
|
22
|
+
is_succeed?: boolean;
|
|
23
|
+
sealed?: {
|
|
24
|
+
data: number[];
|
|
25
|
+
public_key: number[];
|
|
26
|
+
nonce: number[];
|
|
27
|
+
};
|
|
28
|
+
signature?: string;
|
|
29
|
+
encryption_type?: number;
|
|
30
|
+
error_message?: string | null;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Converts a number array to Uint8Array
|
|
35
|
+
*/
|
|
36
|
+
function numberArrayToUint8Array(arr: number[]): Uint8Array {
|
|
37
|
+
return new Uint8Array(arr);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Converts the sealed data from the API response to EthEncryptedData
|
|
42
|
+
*/
|
|
43
|
+
function convertSealedData(sealed: SealOutputStatusResponse['sealed']): EthEncryptedData {
|
|
44
|
+
if (!sealed) {
|
|
45
|
+
throw new CofheError({
|
|
46
|
+
code: CofheErrorCode.SealOutputReturnedNull,
|
|
47
|
+
message: 'Sealed data is missing from completed response',
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
data: numberArrayToUint8Array(sealed.data),
|
|
53
|
+
public_key: numberArrayToUint8Array(sealed.public_key),
|
|
54
|
+
nonce: numberArrayToUint8Array(sealed.nonce),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Submits a sealoutput request to the v2 API and returns the request_id
|
|
60
|
+
*/
|
|
61
|
+
async function submitSealOutputRequest(
|
|
62
|
+
thresholdNetworkUrl: string,
|
|
63
|
+
ctHash: bigint | string,
|
|
64
|
+
chainId: number,
|
|
65
|
+
permission: Permission
|
|
66
|
+
): Promise<string> {
|
|
67
|
+
const body = {
|
|
68
|
+
ct_tempkey: BigInt(ctHash).toString(16).padStart(64, '0'),
|
|
69
|
+
host_chain_id: chainId,
|
|
70
|
+
permit: permission,
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
let response: Response;
|
|
74
|
+
try {
|
|
75
|
+
response = await fetch(`${thresholdNetworkUrl}/v2/sealoutput`, {
|
|
76
|
+
method: 'POST',
|
|
77
|
+
headers: {
|
|
78
|
+
'Content-Type': 'application/json',
|
|
79
|
+
},
|
|
80
|
+
body: JSON.stringify(body),
|
|
81
|
+
});
|
|
82
|
+
} catch (e) {
|
|
83
|
+
throw new CofheError({
|
|
84
|
+
code: CofheErrorCode.SealOutputFailed,
|
|
85
|
+
message: `sealOutput request failed`,
|
|
86
|
+
hint: 'Ensure the threshold network URL is valid and reachable.',
|
|
87
|
+
cause: e instanceof Error ? e : undefined,
|
|
88
|
+
context: {
|
|
89
|
+
thresholdNetworkUrl,
|
|
90
|
+
body,
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Handle non-200 status codes
|
|
96
|
+
if (!response.ok) {
|
|
97
|
+
let errorMessage = `HTTP ${response.status}`;
|
|
98
|
+
try {
|
|
99
|
+
const errorBody = await response.json();
|
|
100
|
+
errorMessage = errorBody.error_message || errorBody.message || errorMessage;
|
|
101
|
+
} catch {
|
|
102
|
+
// Ignore JSON parse errors, use status text
|
|
103
|
+
errorMessage = response.statusText || errorMessage;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
throw new CofheError({
|
|
107
|
+
code: CofheErrorCode.SealOutputFailed,
|
|
108
|
+
message: `sealOutput request failed: ${errorMessage}`,
|
|
109
|
+
hint: 'Check the threshold network URL and request parameters.',
|
|
110
|
+
context: {
|
|
111
|
+
thresholdNetworkUrl,
|
|
112
|
+
status: response.status,
|
|
113
|
+
statusText: response.statusText,
|
|
114
|
+
body,
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
let submitResponse: SealOutputSubmitResponse;
|
|
120
|
+
try {
|
|
121
|
+
submitResponse = (await response.json()) as SealOutputSubmitResponse;
|
|
122
|
+
} catch (e) {
|
|
123
|
+
throw new CofheError({
|
|
124
|
+
code: CofheErrorCode.SealOutputFailed,
|
|
125
|
+
message: `Failed to parse sealOutput submit response`,
|
|
126
|
+
cause: e instanceof Error ? e : undefined,
|
|
127
|
+
context: {
|
|
128
|
+
thresholdNetworkUrl,
|
|
129
|
+
body,
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (!submitResponse.request_id) {
|
|
135
|
+
throw new CofheError({
|
|
136
|
+
code: CofheErrorCode.SealOutputFailed,
|
|
137
|
+
message: `sealOutput submit response missing request_id`,
|
|
138
|
+
context: {
|
|
139
|
+
thresholdNetworkUrl,
|
|
140
|
+
body,
|
|
141
|
+
submitResponse,
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return submitResponse.request_id;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Polls for the sealoutput status until completed or timeout
|
|
151
|
+
*/
|
|
152
|
+
async function pollSealOutputStatus(
|
|
153
|
+
thresholdNetworkUrl: string,
|
|
154
|
+
requestId: string,
|
|
155
|
+
onPoll?: DecryptPollCallbackFunction
|
|
156
|
+
): Promise<EthEncryptedData> {
|
|
157
|
+
const startTime = Date.now();
|
|
158
|
+
let attemptIndex = 0;
|
|
159
|
+
let completed = false;
|
|
160
|
+
|
|
161
|
+
while (!completed) {
|
|
162
|
+
const elapsedMs = Date.now() - startTime;
|
|
163
|
+
const intervalMs = computeMinuteRampPollIntervalMs(elapsedMs, {
|
|
164
|
+
minIntervalMs: POLL_INTERVAL_MS,
|
|
165
|
+
maxIntervalMs: POLL_MAX_INTERVAL_MS,
|
|
166
|
+
});
|
|
167
|
+
onPoll?.({
|
|
168
|
+
operation: 'sealoutput',
|
|
169
|
+
requestId,
|
|
170
|
+
attemptIndex,
|
|
171
|
+
elapsedMs,
|
|
172
|
+
intervalMs,
|
|
173
|
+
timeoutMs: POLL_TIMEOUT_MS,
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
// Check timeout
|
|
177
|
+
if (elapsedMs > POLL_TIMEOUT_MS) {
|
|
178
|
+
throw new CofheError({
|
|
179
|
+
code: CofheErrorCode.SealOutputFailed,
|
|
180
|
+
message: `sealOutput polling timed out after ${POLL_TIMEOUT_MS}ms`,
|
|
181
|
+
hint: 'The request may still be processing. Try again later.',
|
|
182
|
+
context: {
|
|
183
|
+
thresholdNetworkUrl,
|
|
184
|
+
requestId,
|
|
185
|
+
timeoutMs: POLL_TIMEOUT_MS,
|
|
186
|
+
},
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
let response: Response;
|
|
191
|
+
try {
|
|
192
|
+
response = await fetch(`${thresholdNetworkUrl}/v2/sealoutput/${requestId}`, {
|
|
193
|
+
method: 'GET',
|
|
194
|
+
headers: {
|
|
195
|
+
'Content-Type': 'application/json',
|
|
196
|
+
},
|
|
197
|
+
});
|
|
198
|
+
} catch (e) {
|
|
199
|
+
throw new CofheError({
|
|
200
|
+
code: CofheErrorCode.SealOutputFailed,
|
|
201
|
+
message: `sealOutput status poll failed`,
|
|
202
|
+
hint: 'Ensure the threshold network URL is valid and reachable.',
|
|
203
|
+
cause: e instanceof Error ? e : undefined,
|
|
204
|
+
context: {
|
|
205
|
+
thresholdNetworkUrl,
|
|
206
|
+
requestId,
|
|
207
|
+
},
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Handle 404 - request not found
|
|
212
|
+
if (response.status === 404) {
|
|
213
|
+
throw new CofheError({
|
|
214
|
+
code: CofheErrorCode.SealOutputFailed,
|
|
215
|
+
message: `sealOutput request not found: ${requestId}`,
|
|
216
|
+
hint: 'The request may have expired or been invalid.',
|
|
217
|
+
context: {
|
|
218
|
+
thresholdNetworkUrl,
|
|
219
|
+
requestId,
|
|
220
|
+
},
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Handle other non-200 status codes
|
|
225
|
+
if (!response.ok) {
|
|
226
|
+
let errorMessage = `HTTP ${response.status}`;
|
|
227
|
+
try {
|
|
228
|
+
const errorBody = await response.json();
|
|
229
|
+
errorMessage = errorBody.error_message || errorBody.message || errorMessage;
|
|
230
|
+
} catch {
|
|
231
|
+
errorMessage = response.statusText || errorMessage;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
throw new CofheError({
|
|
235
|
+
code: CofheErrorCode.SealOutputFailed,
|
|
236
|
+
message: `sealOutput status poll failed: ${errorMessage}`,
|
|
237
|
+
context: {
|
|
238
|
+
thresholdNetworkUrl,
|
|
239
|
+
requestId,
|
|
240
|
+
status: response.status,
|
|
241
|
+
statusText: response.statusText,
|
|
242
|
+
},
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
let statusResponse: SealOutputStatusResponse;
|
|
247
|
+
try {
|
|
248
|
+
statusResponse = (await response.json()) as SealOutputStatusResponse;
|
|
249
|
+
} catch (e) {
|
|
250
|
+
throw new CofheError({
|
|
251
|
+
code: CofheErrorCode.SealOutputFailed,
|
|
252
|
+
message: `Failed to parse sealOutput status response`,
|
|
253
|
+
cause: e instanceof Error ? e : undefined,
|
|
254
|
+
context: {
|
|
255
|
+
thresholdNetworkUrl,
|
|
256
|
+
requestId,
|
|
257
|
+
},
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// Check if completed
|
|
262
|
+
if (statusResponse.status === 'COMPLETED') {
|
|
263
|
+
// Check if succeeded
|
|
264
|
+
if (statusResponse.is_succeed === false) {
|
|
265
|
+
const errorMessage = statusResponse.error_message || 'Unknown error';
|
|
266
|
+
throw new CofheError({
|
|
267
|
+
code: CofheErrorCode.SealOutputFailed,
|
|
268
|
+
message: `sealOutput request failed: ${errorMessage}`,
|
|
269
|
+
context: {
|
|
270
|
+
thresholdNetworkUrl,
|
|
271
|
+
requestId,
|
|
272
|
+
statusResponse,
|
|
273
|
+
},
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Check if sealed data exists
|
|
278
|
+
if (!statusResponse.sealed) {
|
|
279
|
+
throw new CofheError({
|
|
280
|
+
code: CofheErrorCode.SealOutputReturnedNull,
|
|
281
|
+
message: `sealOutput request completed but returned no sealed data`,
|
|
282
|
+
context: {
|
|
283
|
+
thresholdNetworkUrl,
|
|
284
|
+
requestId,
|
|
285
|
+
statusResponse,
|
|
286
|
+
},
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// Convert and return the sealed data
|
|
291
|
+
return convertSealedData(statusResponse.sealed);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Still processing, wait before next poll
|
|
295
|
+
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
296
|
+
attemptIndex += 1;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// This should never be reached, but TypeScript requires it
|
|
300
|
+
throw new CofheError({
|
|
301
|
+
code: CofheErrorCode.SealOutputFailed,
|
|
302
|
+
message: 'Polling loop exited unexpectedly',
|
|
303
|
+
context: {
|
|
304
|
+
thresholdNetworkUrl,
|
|
305
|
+
requestId,
|
|
306
|
+
},
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export async function tnSealOutputV2(params: {
|
|
311
|
+
ctHash: bigint | string;
|
|
312
|
+
chainId: number;
|
|
313
|
+
permission: Permission;
|
|
314
|
+
thresholdNetworkUrl: string;
|
|
315
|
+
onPoll?: DecryptPollCallbackFunction;
|
|
316
|
+
}): Promise<EthEncryptedData> {
|
|
317
|
+
const { thresholdNetworkUrl, ctHash, chainId, permission, onPoll } = params;
|
|
318
|
+
|
|
319
|
+
// Step 1: Submit the request and get request_id
|
|
320
|
+
const requestId = await submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, permission);
|
|
321
|
+
|
|
322
|
+
// Step 2: Poll for status until completed
|
|
323
|
+
return await pollSealOutputStatus(thresholdNetworkUrl, requestId, onPoll);
|
|
324
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import {
|
|
2
|
+
encodePacked,
|
|
3
|
+
isAddressEqual,
|
|
4
|
+
keccak256,
|
|
5
|
+
parseAbi,
|
|
6
|
+
recoverAddress,
|
|
7
|
+
zeroAddress,
|
|
8
|
+
type Address,
|
|
9
|
+
type Hex,
|
|
10
|
+
type PublicClient,
|
|
11
|
+
} from 'viem';
|
|
12
|
+
import { TASK_MANAGER_ADDRESS } from '../consts.js';
|
|
13
|
+
|
|
14
|
+
const decryptResultSignerAbi = parseAbi(['function decryptResultSigner() view returns (address)']);
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Verifies a decrypt result signature **locally** (no `ctHash`/plaintext sent over RPC).
|
|
18
|
+
*
|
|
19
|
+
* This matches the TaskManager contract logic:
|
|
20
|
+
* - messageHash = keccak256(abi.encodePacked(ctHash, result))
|
|
21
|
+
* - recovered = ecrecover(messageHash, signature)
|
|
22
|
+
* - recovered must equal the on-chain configured `decryptResultSigner`
|
|
23
|
+
*
|
|
24
|
+
* The only on-chain read performed is `TaskManager.decryptResultSigner()` (via `eth_call`).
|
|
25
|
+
*
|
|
26
|
+
* Works with both production and mock deployments.
|
|
27
|
+
*/
|
|
28
|
+
export async function verifyDecryptResult(
|
|
29
|
+
handle: bigint | string,
|
|
30
|
+
cleartext: bigint,
|
|
31
|
+
signature: Hex,
|
|
32
|
+
publicClient: PublicClient
|
|
33
|
+
): Promise<boolean> {
|
|
34
|
+
const expectedSigner = await publicClient.readContract({
|
|
35
|
+
address: TASK_MANAGER_ADDRESS,
|
|
36
|
+
abi: decryptResultSignerAbi,
|
|
37
|
+
functionName: 'decryptResultSigner',
|
|
38
|
+
args: [],
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
if (isAddressEqual(expectedSigner, zeroAddress)) return true;
|
|
42
|
+
|
|
43
|
+
const ctHash = BigInt(handle);
|
|
44
|
+
const messageHash = keccak256(encodePacked(['uint256', 'uint256'], [ctHash, cleartext]));
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
const recovered = await recoverAddress({ hash: messageHash, signature });
|
|
48
|
+
return isAddressEqual(recovered, expectedSigner);
|
|
49
|
+
} catch {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
export const MockZkVerifierAbi = [
|
|
2
|
+
{
|
|
3
|
+
type: 'function',
|
|
4
|
+
name: 'exists',
|
|
5
|
+
inputs: [],
|
|
6
|
+
outputs: [{ name: '', type: 'bool', internalType: 'bool' }],
|
|
7
|
+
stateMutability: 'pure',
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
type: 'function',
|
|
11
|
+
name: 'insertCtHash',
|
|
12
|
+
inputs: [
|
|
13
|
+
{ name: 'ctHash', type: 'uint256', internalType: 'uint256' },
|
|
14
|
+
{ name: 'value', type: 'uint256', internalType: 'uint256' },
|
|
15
|
+
],
|
|
16
|
+
outputs: [],
|
|
17
|
+
stateMutability: 'nonpayable',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
type: 'function',
|
|
21
|
+
name: 'insertPackedCtHashes',
|
|
22
|
+
inputs: [
|
|
23
|
+
{ name: 'ctHashes', type: 'uint256[]', internalType: 'uint256[]' },
|
|
24
|
+
{ name: 'values', type: 'uint256[]', internalType: 'uint256[]' },
|
|
25
|
+
],
|
|
26
|
+
outputs: [],
|
|
27
|
+
stateMutability: 'nonpayable',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
type: 'function',
|
|
31
|
+
name: 'zkVerify',
|
|
32
|
+
inputs: [
|
|
33
|
+
{ name: 'value', type: 'uint256', internalType: 'uint256' },
|
|
34
|
+
{ name: 'utype', type: 'uint8', internalType: 'uint8' },
|
|
35
|
+
{ name: 'user', type: 'address', internalType: 'address' },
|
|
36
|
+
{ name: 'securityZone', type: 'uint8', internalType: 'uint8' },
|
|
37
|
+
{ name: '', type: 'uint256', internalType: 'uint256' },
|
|
38
|
+
],
|
|
39
|
+
outputs: [
|
|
40
|
+
{
|
|
41
|
+
name: '',
|
|
42
|
+
type: 'tuple',
|
|
43
|
+
internalType: 'struct EncryptedInput',
|
|
44
|
+
components: [
|
|
45
|
+
{ name: 'ctHash', type: 'uint256', internalType: 'uint256' },
|
|
46
|
+
{ name: 'securityZone', type: 'uint8', internalType: 'uint8' },
|
|
47
|
+
{ name: 'utype', type: 'uint8', internalType: 'uint8' },
|
|
48
|
+
{ name: 'signature', type: 'bytes', internalType: 'bytes' },
|
|
49
|
+
],
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
stateMutability: 'nonpayable',
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
type: 'function',
|
|
56
|
+
name: 'zkVerifyCalcCtHash',
|
|
57
|
+
inputs: [
|
|
58
|
+
{ name: 'value', type: 'uint256', internalType: 'uint256' },
|
|
59
|
+
{ name: 'utype', type: 'uint8', internalType: 'uint8' },
|
|
60
|
+
{ name: 'user', type: 'address', internalType: 'address' },
|
|
61
|
+
{ name: 'securityZone', type: 'uint8', internalType: 'uint8' },
|
|
62
|
+
{ name: '', type: 'uint256', internalType: 'uint256' },
|
|
63
|
+
],
|
|
64
|
+
outputs: [{ name: 'ctHash', type: 'uint256', internalType: 'uint256' }],
|
|
65
|
+
stateMutability: 'view',
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
type: 'function',
|
|
69
|
+
name: 'zkVerifyCalcCtHashesPacked',
|
|
70
|
+
inputs: [
|
|
71
|
+
{ name: 'values', type: 'uint256[]', internalType: 'uint256[]' },
|
|
72
|
+
{ name: 'utypes', type: 'uint8[]', internalType: 'uint8[]' },
|
|
73
|
+
{ name: 'user', type: 'address', internalType: 'address' },
|
|
74
|
+
{ name: 'securityZone', type: 'uint8', internalType: 'uint8' },
|
|
75
|
+
{ name: 'chainId', type: 'uint256', internalType: 'uint256' },
|
|
76
|
+
],
|
|
77
|
+
outputs: [{ name: 'ctHashes', type: 'uint256[]', internalType: 'uint256[]' }],
|
|
78
|
+
stateMutability: 'view',
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
type: 'function',
|
|
82
|
+
name: 'zkVerifyPacked',
|
|
83
|
+
inputs: [
|
|
84
|
+
{ name: 'values', type: 'uint256[]', internalType: 'uint256[]' },
|
|
85
|
+
{ name: 'utypes', type: 'uint8[]', internalType: 'uint8[]' },
|
|
86
|
+
{ name: 'user', type: 'address', internalType: 'address' },
|
|
87
|
+
{ name: 'securityZone', type: 'uint8', internalType: 'uint8' },
|
|
88
|
+
{ name: 'chainId', type: 'uint256', internalType: 'uint256' },
|
|
89
|
+
],
|
|
90
|
+
outputs: [
|
|
91
|
+
{
|
|
92
|
+
name: 'inputs',
|
|
93
|
+
type: 'tuple[]',
|
|
94
|
+
internalType: 'struct EncryptedInput[]',
|
|
95
|
+
components: [
|
|
96
|
+
{ name: 'ctHash', type: 'uint256', internalType: 'uint256' },
|
|
97
|
+
{ name: 'securityZone', type: 'uint8', internalType: 'uint8' },
|
|
98
|
+
{ name: 'utype', type: 'uint8', internalType: 'uint8' },
|
|
99
|
+
{ name: 'signature', type: 'bytes', internalType: 'bytes' },
|
|
100
|
+
],
|
|
101
|
+
},
|
|
102
|
+
],
|
|
103
|
+
stateMutability: 'nonpayable',
|
|
104
|
+
},
|
|
105
|
+
{ type: 'error', name: 'InvalidInputs', inputs: [] },
|
|
106
|
+
] as const;
|