@cofhe/sdk 0.6.0 → 0.7.0
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 +49 -0
- package/acps/acp.ts +411 -0
- package/acps/index.ts +70 -0
- package/{permits → acps}/onchain-utils.ts +49 -24
- package/acps/sealing.ts +90 -0
- package/acps/signature.ts +89 -0
- package/acps/store.ts +172 -0
- package/acps/test/acp.test.ts +615 -0
- package/acps/test/localstorage.test.ts +105 -0
- package/acps/test/sealing.test.ts +77 -0
- package/acps/test/store.test.ts +88 -0
- package/acps/test/validation.test.ts +361 -0
- package/acps/test-utils.ts +32 -0
- package/acps/types.ts +252 -0
- package/acps/validation.ts +392 -0
- package/adapters/test/ethers5.test.ts +4 -1
- package/adapters/test/ethers6.test.ts +4 -1
- package/adapters/test/wagmi.test.ts +5 -2
- package/chains/chains/stagingCofhe.ts +21 -0
- package/chains/index.ts +3 -1
- package/chains/test/chains.test.ts +2 -1
- package/core/acps.ts +625 -0
- package/core/client.ts +136 -39
- package/core/clientTypes.ts +52 -41
- package/core/config.ts +66 -5
- package/core/debug.ts +72 -0
- package/core/decrypt/MockThresholdNetworkAbi.ts +20 -11
- package/core/decrypt/apiError.ts +104 -0
- package/core/decrypt/cofheMocksDecryptForTx.ts +11 -11
- package/core/decrypt/cofheMocksDecryptForView.ts +7 -7
- package/core/decrypt/decryptForTxBuilder.ts +102 -102
- package/core/decrypt/decryptForViewBuilder.ts +90 -90
- package/core/decrypt/submitRetry.ts +38 -30
- package/core/decrypt/tnDecryptV1.ts +5 -5
- package/core/decrypt/tnDecryptV2.ts +45 -34
- package/core/decrypt/tnSealOutputV1.ts +4 -3
- package/core/decrypt/tnSealOutputV2.ts +44 -31
- package/core/encrypt/cofheMocksZkVerifySign.ts +59 -74
- package/core/encrypt/encryptInputsBuilder.ts +86 -52
- package/core/encrypt/zkPackProveVerify.ts +25 -18
- package/core/error.ts +34 -6
- package/core/index.ts +14 -14
- package/core/test/acpDefaults.test.ts +52 -0
- package/core/test/acps.test.ts +596 -0
- package/core/test/apiError.test.ts +130 -0
- package/core/test/client.test.ts +22 -19
- package/core/test/config.test.ts +25 -5
- package/core/test/decrypt.test.ts +40 -35
- package/core/test/decryptBuilders.test.ts +68 -68
- package/core/test/decryptErrorCodes.test.ts +217 -0
- package/core/test/encryptInputsBuilder.test.ts +72 -41
- package/core/test/pollCallbacks.test.ts +89 -18
- package/core/test/stagingRedirect.ts +18 -0
- package/core/test/submitRetry.test.ts +182 -0
- package/core/types.ts +9 -69
- package/dist/acp-Wi6isVQI.d.cts +407 -0
- package/dist/acp-Wi6isVQI.d.ts +407 -0
- package/dist/acps.cjs +1081 -0
- package/dist/acps.d.cts +480 -0
- package/dist/acps.d.ts +480 -0
- package/dist/acps.js +2 -0
- package/dist/chains.cjs +14 -1
- package/dist/chains.d.cts +30 -1
- package/dist/chains.d.ts +30 -1
- package/dist/chains.js +1 -1
- package/dist/{chunk-PE5V5CCV.js → chunk-43USWPEH.js} +1000 -604
- package/dist/{chunk-MTRAXQXC.js → chunk-N6IDQRRU.js} +14 -2
- package/dist/chunk-Q7CBWGQX.js +1029 -0
- package/dist/{clientTypes-CyUvRRzA.d.ts → clientTypes-BN3nbzYM.d.ts} +342 -165
- package/dist/{clientTypes-BDy1qIBu.d.cts → clientTypes-CYZjFznO.d.cts} +342 -165
- package/dist/core.cjs +1431 -1026
- package/dist/core.d.cts +55 -10
- package/dist/core.d.ts +55 -10
- package/dist/core.js +3 -3
- package/dist/node.cjs +1356 -976
- package/dist/node.d.cts +2 -2
- package/dist/node.d.ts +2 -2
- package/dist/node.js +3 -3
- package/dist/web.cjs +1356 -976
- package/dist/web.d.cts +2 -2
- package/dist/web.d.ts +2 -2
- package/dist/web.js +3 -3
- package/node/test/inherited.test.ts +75 -65
- package/node/test/tfheinit.test.ts +23 -8
- package/package.json +6 -6
- package/web/test/client.web.test.ts +5 -1
- package/web/test/inherited.web.test.ts +75 -65
- package/web/test/tfheinit.web.test.ts +14 -5
- package/web/test/worker.config.web.test.ts +38 -23
- package/web/test/worker.output.web.test.ts +25 -24
- package/core/encrypt/encryptUtils.ts +0 -67
- package/core/permits.ts +0 -206
- package/core/test/permits.test.ts +0 -534
- package/dist/chunk-VB62WYPL.js +0 -978
- package/dist/permit-DnVMDT5h.d.cts +0 -376
- package/dist/permit-DnVMDT5h.d.ts +0 -376
- package/dist/permits.cjs +0 -1026
- package/dist/permits.d.cts +0 -353
- package/dist/permits.d.ts +0 -353
- package/dist/permits.js +0 -2
- package/permits/index.ts +0 -68
- package/permits/permit.ts +0 -385
- package/permits/sealing.ts +0 -131
- package/permits/signature.ts +0 -79
- package/permits/store.ts +0 -157
- package/permits/test/localstorage.test.ts +0 -113
- package/permits/test/permit.test.ts +0 -557
- package/permits/test/sealing.test.ts +0 -84
- package/permits/test/store.test.ts +0 -88
- package/permits/test/validation.test.ts +0 -361
- package/permits/test-utils.ts +0 -28
- package/permits/types.ts +0 -204
- package/permits/validation.ts +0 -327
- /package/{permits → acps}/utils.ts +0 -0
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type ACPPublic } from '@/acps';
|
|
2
|
+
import { cofheFetch } from '../debug.js';
|
|
2
3
|
|
|
3
4
|
import { CofheError, CofheErrorCode } from '../error';
|
|
4
5
|
import { type DecryptPollCallbackFunction } from '../types';
|
|
5
6
|
import { normalizeTnSignature, parseDecryptedBytesToBigInt } from './tnDecryptUtils';
|
|
6
7
|
import { computeMinuteRampPollIntervalMs } from './polling.js';
|
|
8
|
+
import { mapApiErrorCodeToCofheErrorCode, parseApiErrorResponseBody } from './apiError.js';
|
|
7
9
|
import { classifySubmitResponse, normalize404RetryTimeoutMs, throwIfSubmitRetryTimedOut } from './submitRetry.js';
|
|
8
10
|
|
|
9
11
|
// Polling configuration
|
|
@@ -177,7 +179,7 @@ async function submitDecryptRequestV2(
|
|
|
177
179
|
thresholdNetworkUrl: string,
|
|
178
180
|
ctHash: bigint | string,
|
|
179
181
|
chainId: number,
|
|
180
|
-
|
|
182
|
+
acp: ACPPublic | null,
|
|
181
183
|
overallStartTime: number,
|
|
182
184
|
retry404TimeoutMs: number,
|
|
183
185
|
onPoll?: DecryptPollCallbackFunction
|
|
@@ -185,28 +187,32 @@ async function submitDecryptRequestV2(
|
|
|
185
187
|
const body: {
|
|
186
188
|
ct_tempkey: string;
|
|
187
189
|
host_chain_id: number;
|
|
188
|
-
|
|
190
|
+
acp?: ACPPublic;
|
|
189
191
|
} = {
|
|
190
192
|
ct_tempkey: BigInt(ctHash).toString(16).padStart(64, '0'),
|
|
191
193
|
host_chain_id: chainId,
|
|
192
194
|
};
|
|
193
195
|
|
|
194
|
-
if (
|
|
195
|
-
body.
|
|
196
|
+
if (acp) {
|
|
197
|
+
body.acp = acp;
|
|
196
198
|
}
|
|
197
199
|
|
|
198
200
|
let attemptIndex = 0;
|
|
201
|
+
let last404ApiErrorMessage: string | undefined;
|
|
199
202
|
|
|
200
203
|
for (;;) {
|
|
201
204
|
let response: Response;
|
|
202
205
|
try {
|
|
203
|
-
response = await
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
206
|
+
response = await cofheFetch(
|
|
207
|
+
`${thresholdNetworkUrl}/v2/decrypt`,
|
|
208
|
+
/*op:decrypt*/ {
|
|
209
|
+
method: 'POST',
|
|
210
|
+
headers: {
|
|
211
|
+
'Content-Type': 'application/json',
|
|
212
|
+
},
|
|
213
|
+
body: JSON.stringify(body),
|
|
214
|
+
}
|
|
215
|
+
);
|
|
210
216
|
} catch (e) {
|
|
211
217
|
throw new CofheError({
|
|
212
218
|
code: CofheErrorCode.DecryptFailed,
|
|
@@ -221,17 +227,20 @@ async function submitDecryptRequestV2(
|
|
|
221
227
|
});
|
|
222
228
|
}
|
|
223
229
|
|
|
224
|
-
const responseClassification = await classifySubmitResponse({
|
|
230
|
+
const responseClassification = await classifySubmitResponse({
|
|
231
|
+
response,
|
|
232
|
+
fallbackErrorCode: CofheErrorCode.DecryptFailed,
|
|
233
|
+
});
|
|
225
234
|
|
|
226
235
|
if (responseClassification.kind === 'fatal-http') {
|
|
227
236
|
throw new CofheError({
|
|
228
|
-
code:
|
|
237
|
+
code: responseClassification.cofheErrorCode,
|
|
238
|
+
apiErrorCode: responseClassification.apiErrorCode,
|
|
229
239
|
message: `decrypt request failed: ${responseClassification.errorMessage}`,
|
|
230
240
|
hint: 'Check the threshold network URL and request parameters.',
|
|
231
241
|
context: {
|
|
232
242
|
thresholdNetworkUrl,
|
|
233
|
-
status:
|
|
234
|
-
statusText: response.statusText,
|
|
243
|
+
status: responseClassification.status,
|
|
235
244
|
body,
|
|
236
245
|
attemptIndex,
|
|
237
246
|
},
|
|
@@ -285,6 +294,10 @@ async function submitDecryptRequestV2(
|
|
|
285
294
|
});
|
|
286
295
|
}
|
|
287
296
|
|
|
297
|
+
if (responseClassification.status === 404) {
|
|
298
|
+
last404ApiErrorMessage = responseClassification.apiErrorMessage;
|
|
299
|
+
}
|
|
300
|
+
|
|
288
301
|
const elapsedMs = Date.now() - overallStartTime;
|
|
289
302
|
|
|
290
303
|
throwIfSubmitRetryTimedOut({
|
|
@@ -297,6 +310,7 @@ async function submitDecryptRequestV2(
|
|
|
297
310
|
thresholdNetworkUrl,
|
|
298
311
|
body,
|
|
299
312
|
attemptIndex,
|
|
313
|
+
lastKnownErrorMessage: last404ApiErrorMessage,
|
|
300
314
|
});
|
|
301
315
|
|
|
302
316
|
onPoll?.({
|
|
@@ -352,12 +366,15 @@ async function pollDecryptStatusV2(
|
|
|
352
366
|
|
|
353
367
|
let response: Response;
|
|
354
368
|
try {
|
|
355
|
-
response = await
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
369
|
+
response = await cofheFetch(
|
|
370
|
+
`${thresholdNetworkUrl}/v2/decrypt/${requestId}`,
|
|
371
|
+
/*op:decrypt-poll*/ {
|
|
372
|
+
method: 'GET',
|
|
373
|
+
headers: {
|
|
374
|
+
'Content-Type': 'application/json',
|
|
375
|
+
},
|
|
376
|
+
}
|
|
377
|
+
);
|
|
361
378
|
} catch (e) {
|
|
362
379
|
throw new CofheError({
|
|
363
380
|
code: CofheErrorCode.DecryptFailed,
|
|
@@ -384,17 +401,11 @@ async function pollDecryptStatusV2(
|
|
|
384
401
|
}
|
|
385
402
|
|
|
386
403
|
if (!response.ok) {
|
|
387
|
-
|
|
388
|
-
try {
|
|
389
|
-
const errorBody = (await response.json()) as Record<string, unknown>;
|
|
390
|
-
const maybeMessage = (errorBody.error_message || errorBody.message) as unknown;
|
|
391
|
-
if (typeof maybeMessage === 'string' && maybeMessage.length > 0) errorMessage = maybeMessage;
|
|
392
|
-
} catch {
|
|
393
|
-
errorMessage = response.statusText || errorMessage;
|
|
394
|
-
}
|
|
404
|
+
const { apiErrorCode, errorMessage } = await parseApiErrorResponseBody(response);
|
|
395
405
|
|
|
396
406
|
throw new CofheError({
|
|
397
|
-
code: CofheErrorCode.DecryptFailed,
|
|
407
|
+
code: mapApiErrorCodeToCofheErrorCode(apiErrorCode, CofheErrorCode.DecryptFailed),
|
|
408
|
+
apiErrorCode,
|
|
398
409
|
message: `decrypt status poll failed: ${errorMessage}`,
|
|
399
410
|
context: {
|
|
400
411
|
thresholdNetworkUrl,
|
|
@@ -448,12 +459,12 @@ async function pollDecryptStatusV2(
|
|
|
448
459
|
export async function tnDecryptV2(params: {
|
|
449
460
|
ctHash: bigint | string;
|
|
450
461
|
chainId: number;
|
|
451
|
-
|
|
462
|
+
acp: ACPPublic | null;
|
|
452
463
|
thresholdNetworkUrl: string;
|
|
453
464
|
retry404TimeoutMs?: number;
|
|
454
465
|
onPoll?: DecryptPollCallbackFunction;
|
|
455
466
|
}): Promise<{ decryptedValue: bigint; signature: `0x${string}` }> {
|
|
456
|
-
const { thresholdNetworkUrl, ctHash, chainId,
|
|
467
|
+
const { thresholdNetworkUrl, ctHash, chainId, acp, retry404TimeoutMs, onPoll } = params;
|
|
457
468
|
const normalized404RetryTimeoutMs = normalize404RetryTimeoutMs({
|
|
458
469
|
timeoutMs: retry404TimeoutMs,
|
|
459
470
|
operationLabel: 'decrypt',
|
|
@@ -464,7 +475,7 @@ export async function tnDecryptV2(params: {
|
|
|
464
475
|
thresholdNetworkUrl,
|
|
465
476
|
ctHash,
|
|
466
477
|
chainId,
|
|
467
|
-
|
|
478
|
+
acp,
|
|
468
479
|
overallStartTime,
|
|
469
480
|
normalized404RetryTimeoutMs,
|
|
470
481
|
onPoll
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type ACPPublic, type EthEncryptedData } from '@/acps';
|
|
2
2
|
|
|
3
3
|
import { CofheError, CofheErrorCode } from '../error.js';
|
|
4
|
+
import {} from './tnDecryptUtils.js';
|
|
4
5
|
|
|
5
6
|
export async function tnSealOutputV1(
|
|
6
7
|
ctHash: bigint,
|
|
7
8
|
chainId: number,
|
|
8
|
-
|
|
9
|
+
acp: ACPPublic,
|
|
9
10
|
thresholdNetworkUrl: string
|
|
10
11
|
): Promise<EthEncryptedData> {
|
|
11
12
|
let sealed: EthEncryptedData | undefined;
|
|
@@ -15,7 +16,7 @@ export async function tnSealOutputV1(
|
|
|
15
16
|
const body = {
|
|
16
17
|
ct_tempkey: ctHash.toString(16).padStart(64, '0'),
|
|
17
18
|
host_chain_id: chainId,
|
|
18
|
-
|
|
19
|
+
acp: acp,
|
|
19
20
|
};
|
|
20
21
|
|
|
21
22
|
try {
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type ACPPublic, type EthEncryptedData } from '@/acps';
|
|
2
|
+
import { cofheFetch } from '../debug.js';
|
|
2
3
|
|
|
3
4
|
import { CofheError, CofheErrorCode } from '../error.js';
|
|
4
5
|
import { type DecryptPollCallbackFunction } from '../types.js';
|
|
5
6
|
import { computeMinuteRampPollIntervalMs } from './polling.js';
|
|
7
|
+
import { mapApiErrorCodeToCofheErrorCode, parseApiErrorResponseBody } from './apiError.js';
|
|
6
8
|
import { classifySubmitResponse, normalize404RetryTimeoutMs, throwIfSubmitRetryTimedOut } from './submitRetry.js';
|
|
9
|
+
import {} from './tnDecryptUtils.js';
|
|
7
10
|
|
|
8
11
|
// Polling configuration
|
|
9
12
|
const POLL_INTERVAL_MS = 1000; // 1 second
|
|
@@ -135,7 +138,7 @@ async function submitSealOutputRequest(
|
|
|
135
138
|
thresholdNetworkUrl: string,
|
|
136
139
|
ctHash: bigint | string,
|
|
137
140
|
chainId: number,
|
|
138
|
-
|
|
141
|
+
acp: ACPPublic,
|
|
139
142
|
overallStartTime: number,
|
|
140
143
|
retry404TimeoutMs: number,
|
|
141
144
|
onPoll?: DecryptPollCallbackFunction
|
|
@@ -143,20 +146,24 @@ async function submitSealOutputRequest(
|
|
|
143
146
|
const body = {
|
|
144
147
|
ct_tempkey: BigInt(ctHash).toString(16).padStart(64, '0'),
|
|
145
148
|
host_chain_id: chainId,
|
|
146
|
-
|
|
149
|
+
acp,
|
|
147
150
|
};
|
|
148
151
|
let attemptIndex = 0;
|
|
152
|
+
let last404ApiErrorMessage: string | undefined;
|
|
149
153
|
|
|
150
154
|
for (;;) {
|
|
151
155
|
let response: Response;
|
|
152
156
|
try {
|
|
153
|
-
response = await
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
157
|
+
response = await cofheFetch(
|
|
158
|
+
`${thresholdNetworkUrl}/v2/sealoutput`,
|
|
159
|
+
/*op:sealoutput*/ {
|
|
160
|
+
method: 'POST',
|
|
161
|
+
headers: {
|
|
162
|
+
'Content-Type': 'application/json',
|
|
163
|
+
},
|
|
164
|
+
body: JSON.stringify(body),
|
|
165
|
+
}
|
|
166
|
+
);
|
|
160
167
|
} catch (e) {
|
|
161
168
|
throw new CofheError({
|
|
162
169
|
code: CofheErrorCode.SealOutputFailed,
|
|
@@ -171,17 +178,20 @@ async function submitSealOutputRequest(
|
|
|
171
178
|
});
|
|
172
179
|
}
|
|
173
180
|
|
|
174
|
-
const responseClassification = await classifySubmitResponse({
|
|
181
|
+
const responseClassification = await classifySubmitResponse({
|
|
182
|
+
response,
|
|
183
|
+
fallbackErrorCode: CofheErrorCode.SealOutputFailed,
|
|
184
|
+
});
|
|
175
185
|
|
|
176
186
|
if (responseClassification.kind === 'fatal-http') {
|
|
177
187
|
throw new CofheError({
|
|
178
|
-
code:
|
|
188
|
+
code: responseClassification.cofheErrorCode,
|
|
189
|
+
apiErrorCode: responseClassification.apiErrorCode,
|
|
179
190
|
message: `sealOutput request failed: ${responseClassification.errorMessage}`,
|
|
180
191
|
hint: 'Check the threshold network URL and request parameters.',
|
|
181
192
|
context: {
|
|
182
193
|
thresholdNetworkUrl,
|
|
183
|
-
status:
|
|
184
|
-
statusText: response.statusText,
|
|
194
|
+
status: responseClassification.status,
|
|
185
195
|
body,
|
|
186
196
|
attemptIndex,
|
|
187
197
|
},
|
|
@@ -232,6 +242,10 @@ async function submitSealOutputRequest(
|
|
|
232
242
|
});
|
|
233
243
|
}
|
|
234
244
|
|
|
245
|
+
if (responseClassification.status === 404) {
|
|
246
|
+
last404ApiErrorMessage = responseClassification.apiErrorMessage;
|
|
247
|
+
}
|
|
248
|
+
|
|
235
249
|
const elapsedMs = Date.now() - overallStartTime;
|
|
236
250
|
|
|
237
251
|
throwIfSubmitRetryTimedOut({
|
|
@@ -244,6 +258,7 @@ async function submitSealOutputRequest(
|
|
|
244
258
|
thresholdNetworkUrl,
|
|
245
259
|
body,
|
|
246
260
|
attemptIndex,
|
|
261
|
+
lastKnownErrorMessage: last404ApiErrorMessage,
|
|
247
262
|
});
|
|
248
263
|
|
|
249
264
|
onPoll?.({
|
|
@@ -303,12 +318,15 @@ async function pollSealOutputStatus(
|
|
|
303
318
|
|
|
304
319
|
let response: Response;
|
|
305
320
|
try {
|
|
306
|
-
response = await
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
321
|
+
response = await cofheFetch(
|
|
322
|
+
`${thresholdNetworkUrl}/v2/sealoutput/${requestId}`,
|
|
323
|
+
/*op:sealoutput-poll*/ {
|
|
324
|
+
method: 'GET',
|
|
325
|
+
headers: {
|
|
326
|
+
'Content-Type': 'application/json',
|
|
327
|
+
},
|
|
328
|
+
}
|
|
329
|
+
);
|
|
312
330
|
} catch (e) {
|
|
313
331
|
throw new CofheError({
|
|
314
332
|
code: CofheErrorCode.SealOutputFailed,
|
|
@@ -337,16 +355,11 @@ async function pollSealOutputStatus(
|
|
|
337
355
|
|
|
338
356
|
// Handle other non-200 status codes
|
|
339
357
|
if (!response.ok) {
|
|
340
|
-
|
|
341
|
-
try {
|
|
342
|
-
const errorBody = await response.json();
|
|
343
|
-
errorMessage = errorBody.error_message || errorBody.message || errorMessage;
|
|
344
|
-
} catch {
|
|
345
|
-
errorMessage = response.statusText || errorMessage;
|
|
346
|
-
}
|
|
358
|
+
const { apiErrorCode, errorMessage } = await parseApiErrorResponseBody(response);
|
|
347
359
|
|
|
348
360
|
throw new CofheError({
|
|
349
|
-
code: CofheErrorCode.SealOutputFailed,
|
|
361
|
+
code: mapApiErrorCodeToCofheErrorCode(apiErrorCode, CofheErrorCode.SealOutputFailed),
|
|
362
|
+
apiErrorCode,
|
|
350
363
|
message: `sealOutput status poll failed: ${errorMessage}`,
|
|
351
364
|
context: {
|
|
352
365
|
thresholdNetworkUrl,
|
|
@@ -400,12 +413,12 @@ async function pollSealOutputStatus(
|
|
|
400
413
|
export async function tnSealOutputV2(params: {
|
|
401
414
|
ctHash: bigint | string;
|
|
402
415
|
chainId: number;
|
|
403
|
-
|
|
416
|
+
acp: ACPPublic;
|
|
404
417
|
thresholdNetworkUrl: string;
|
|
405
418
|
retry404TimeoutMs?: number;
|
|
406
419
|
onPoll?: DecryptPollCallbackFunction;
|
|
407
420
|
}): Promise<EthEncryptedData> {
|
|
408
|
-
const { thresholdNetworkUrl, ctHash, chainId,
|
|
421
|
+
const { thresholdNetworkUrl, ctHash, chainId, acp, retry404TimeoutMs, onPoll } = params;
|
|
409
422
|
const normalized404RetryTimeoutMs = normalize404RetryTimeoutMs({
|
|
410
423
|
timeoutMs: retry404TimeoutMs,
|
|
411
424
|
operationLabel: 'sealOutput',
|
|
@@ -418,7 +431,7 @@ export async function tnSealOutputV2(params: {
|
|
|
418
431
|
thresholdNetworkUrl,
|
|
419
432
|
ctHash,
|
|
420
433
|
chainId,
|
|
421
|
-
|
|
434
|
+
acp,
|
|
422
435
|
overallStartTime,
|
|
423
436
|
normalized404RetryTimeoutMs,
|
|
424
437
|
onPoll
|
|
@@ -1,15 +1,6 @@
|
|
|
1
1
|
import { type EncryptableItem, FheTypes } from '../types.js';
|
|
2
|
-
import { type
|
|
3
|
-
import {
|
|
4
|
-
createWalletClient,
|
|
5
|
-
http,
|
|
6
|
-
encodePacked,
|
|
7
|
-
keccak256,
|
|
8
|
-
hashMessage,
|
|
9
|
-
toBytes,
|
|
10
|
-
type PublicClient,
|
|
11
|
-
type WalletClient,
|
|
12
|
-
} from 'viem';
|
|
2
|
+
import { type VerifyBatchResult } from './zkPackProveVerify.js';
|
|
3
|
+
import { createWalletClient, http, encodePacked, keccak256, type PublicClient, type WalletClient } from 'viem';
|
|
13
4
|
import { MockZkVerifierAbi } from './MockZkVerifierAbi.js';
|
|
14
5
|
import { hardhat } from 'viem/chains';
|
|
15
6
|
import { CofheError, CofheErrorCode } from '../error.js';
|
|
@@ -178,89 +169,80 @@ async function insertCtHashes(items: EncryptableItemWithCtHash[], walletClient:
|
|
|
178
169
|
}
|
|
179
170
|
|
|
180
171
|
/**
|
|
181
|
-
* The mocks verify
|
|
182
|
-
* Locally, we create the
|
|
172
|
+
* The mocks verify a batch's signature against the known verifier signer account.
|
|
173
|
+
* Locally, we create the single batch signature from the known signer account, over
|
|
174
|
+
* keccak256(h_0 || h_1 || ... || h_n), where each h_i is the same per-item message hash
|
|
175
|
+
* used by the on-chain digest (`ctHash || utype || securityZone || sender || chainId ||
|
|
176
|
+
* consumingContract`, per cofhe-contracts#77's contract-binding fix). This is the one
|
|
177
|
+
* canonical signer implementation used by the mocks - there is no separate per-item signing
|
|
178
|
+
* path.
|
|
183
179
|
*/
|
|
184
|
-
async function
|
|
180
|
+
async function createBatchProofSignature(
|
|
185
181
|
items: EncryptableItemWithCtHash[],
|
|
186
182
|
securityZone: number,
|
|
187
|
-
account: string
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
// Create wallet client for the encrypted input signer
|
|
192
|
-
// This wallet won't send a transaction, so gas isn't needed
|
|
193
|
-
// This wallet doesn't need to be connected to the network
|
|
194
|
-
let encInputSignerClient: WalletClient | undefined;
|
|
195
|
-
|
|
196
|
-
try {
|
|
197
|
-
encInputSignerClient = createMockZkVerifierSigner();
|
|
198
|
-
} catch (err) {
|
|
199
|
-
throw new CofheError({
|
|
200
|
-
code: CofheErrorCode.ZkMocksCreateProofSignatureFailed,
|
|
201
|
-
message: `mockZkVerifySign createProofSignatures failed while creating wallet client`,
|
|
202
|
-
cause: err instanceof Error ? err : undefined,
|
|
203
|
-
context: {
|
|
204
|
-
MOCKS_ZK_VERIFIER_SIGNER_PRIVATE_KEY,
|
|
205
|
-
},
|
|
206
|
-
});
|
|
207
|
-
}
|
|
208
|
-
|
|
183
|
+
account: string,
|
|
184
|
+
consumingContract: string
|
|
185
|
+
): Promise<`0x${string}`> {
|
|
209
186
|
try {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
187
|
+
// Compute each item's per-item message hash h_i
|
|
188
|
+
const itemHashes = items.map((item) =>
|
|
189
|
+
keccak256(
|
|
190
|
+
encodePacked(
|
|
191
|
+
['uint256', 'uint8', 'uint8', 'address', 'uint256', 'address'],
|
|
192
|
+
[
|
|
193
|
+
BigInt(item.ctHash),
|
|
194
|
+
item.utype,
|
|
195
|
+
securityZone,
|
|
196
|
+
account as `0x${string}`,
|
|
197
|
+
BigInt(hardhat.id),
|
|
198
|
+
consumingContract as `0x${string}`,
|
|
199
|
+
]
|
|
200
|
+
)
|
|
201
|
+
)
|
|
202
|
+
);
|
|
217
203
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
204
|
+
// Fold into one batch digest: keccak256(h_0 || h_1 || ... || h_n)
|
|
205
|
+
const batchDigest = keccak256(
|
|
206
|
+
encodePacked(
|
|
207
|
+
itemHashes.map(() => 'bytes32' as const),
|
|
208
|
+
itemHashes
|
|
209
|
+
)
|
|
210
|
+
);
|
|
223
211
|
|
|
224
|
-
|
|
225
|
-
|
|
212
|
+
// Sign once for the whole batch
|
|
213
|
+
return await sign({
|
|
214
|
+
hash: batchDigest,
|
|
215
|
+
privateKey: MOCKS_ZK_VERIFIER_SIGNER_PRIVATE_KEY,
|
|
216
|
+
to: 'hex',
|
|
217
|
+
});
|
|
226
218
|
} catch (err) {
|
|
227
219
|
throw new CofheError({
|
|
228
220
|
code: CofheErrorCode.ZkMocksCreateProofSignatureFailed,
|
|
229
|
-
message: `mockZkVerifySign
|
|
221
|
+
message: `mockZkVerifySign createBatchProofSignature failed while signing the batch digest`,
|
|
230
222
|
cause: err instanceof Error ? err : undefined,
|
|
231
223
|
context: {
|
|
232
224
|
items,
|
|
233
225
|
securityZone,
|
|
226
|
+
consumingContract,
|
|
234
227
|
},
|
|
235
228
|
});
|
|
236
229
|
}
|
|
237
|
-
|
|
238
|
-
if (signatures.length !== items.length) {
|
|
239
|
-
throw new CofheError({
|
|
240
|
-
code: CofheErrorCode.ZkMocksCreateProofSignatureFailed,
|
|
241
|
-
message: `mockZkVerifySign createProofSignatures returned incorrect number of signatures`,
|
|
242
|
-
context: {
|
|
243
|
-
items,
|
|
244
|
-
securityZone,
|
|
245
|
-
},
|
|
246
|
-
});
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
return signatures;
|
|
250
230
|
}
|
|
251
231
|
|
|
252
232
|
/**
|
|
253
|
-
* Transforms the encryptable items into
|
|
254
|
-
*
|
|
233
|
+
* Transforms the encryptable items into a batch-verified result ready to be used in a
|
|
234
|
+
* transaction on the hardhat chain. Mirrors the shape returned by CoFHE's `/verifyBatch`:
|
|
235
|
+
* per-item ctHash/ctType, plus one shared on-chain verifiable signature for the whole batch.
|
|
255
236
|
*/
|
|
256
237
|
export async function cofheMocksZkVerifySign(
|
|
257
238
|
items: EncryptableItem[],
|
|
258
239
|
account: string,
|
|
259
240
|
securityZone: number,
|
|
241
|
+
consumingContract: string,
|
|
260
242
|
publicClient: PublicClient,
|
|
261
243
|
walletClient: WalletClient,
|
|
262
244
|
zkvWalletClient: WalletClient | undefined
|
|
263
|
-
): Promise<
|
|
245
|
+
): Promise<VerifyBatchResult> {
|
|
264
246
|
// Use config._internal?.zkvWalletClient if provided, otherwise use a mock zk verifier signer
|
|
265
247
|
const _walletClient = zkvWalletClient ?? createMockZkVerifierSigner();
|
|
266
248
|
|
|
@@ -270,12 +252,15 @@ export async function cofheMocksZkVerifySign(
|
|
|
270
252
|
// Insert the ctHashes into the MockZkVerifier contract
|
|
271
253
|
await insertCtHashes(encryptableItems, _walletClient);
|
|
272
254
|
|
|
273
|
-
// Locally create the
|
|
274
|
-
const
|
|
255
|
+
// Locally create the single batch signature from the known signer account
|
|
256
|
+
const signature = await createBatchProofSignature(encryptableItems, securityZone, account, consumingContract);
|
|
275
257
|
|
|
276
|
-
// Return the ctHashes and
|
|
277
|
-
return
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
258
|
+
// Return the ctHashes/ctTypes and the batch signature, in the same shape as CoFHE's /verifyBatch
|
|
259
|
+
return {
|
|
260
|
+
outputs: encryptableItems.map((item) => ({
|
|
261
|
+
ct_hash: item.ctHash.toString(),
|
|
262
|
+
ct_type: item.utype,
|
|
263
|
+
})),
|
|
264
|
+
signature,
|
|
265
|
+
};
|
|
281
266
|
}
|