@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,10 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type ZkBuilderAndCrsGenerator,
|
|
3
3
|
type ZkProveWorkerFunction,
|
|
4
|
+
type VerifyBatchResult,
|
|
4
5
|
zkPack,
|
|
5
6
|
zkProve,
|
|
6
7
|
zkProveWithWorker,
|
|
7
|
-
|
|
8
|
+
zkVerifyBatch,
|
|
8
9
|
constructZkPoKMetadata,
|
|
9
10
|
} from './zkPackProveVerify.js';
|
|
10
11
|
import { CofheError, CofheErrorCode } from '../error.js';
|
|
@@ -12,8 +13,6 @@ import {
|
|
|
12
13
|
type EncryptStepCallbackFunction,
|
|
13
14
|
EncryptStep,
|
|
14
15
|
type EncryptableItem,
|
|
15
|
-
type EncryptedItemInput,
|
|
16
|
-
type EncryptedItemInputs,
|
|
17
16
|
type TfheInitializer,
|
|
18
17
|
type EncryptStepCallbackContext,
|
|
19
18
|
type HashPlusProofResult,
|
|
@@ -48,11 +47,20 @@ type EncryptInputsBuilderParams<T extends EncryptableItem[]> = BaseBuilderParams
|
|
|
48
47
|
* config, tfhePublicKeyDeserializer, compactPkeCrsDeserializer, and zkBuilderAndCrsGenerator are required to be set in the builder.
|
|
49
48
|
*/
|
|
50
49
|
|
|
51
|
-
|
|
50
|
+
/**
|
|
51
|
+
* The builder as returned by `client.encryptInputs(...)`, before a consuming contract has been set.
|
|
52
|
+
*
|
|
53
|
+
* `execute()` is intentionally absent: the verifier binds the consuming contract into the signed
|
|
54
|
+
* digest, so no batch can be produced until the caller commits to the contract that will consume it.
|
|
55
|
+
* `setConsumingContract(...)` returns the full {@link EncryptInputsBuilder}, unlocking `execute()`.
|
|
56
|
+
*/
|
|
57
|
+
export type EncryptInputsBuilderUnset<T extends EncryptableItem[]> = Omit<EncryptInputsBuilder<T>, 'execute'>;
|
|
58
|
+
|
|
59
|
+
export class EncryptInputsBuilder<T extends EncryptableItem[]> extends BaseBuilder {
|
|
52
60
|
private securityZone: number;
|
|
61
|
+
protected consumingContract: string | undefined;
|
|
53
62
|
private stepCallback?: EncryptStepCallbackFunction;
|
|
54
63
|
private inputItems: [...T];
|
|
55
|
-
private hpp: boolean = false;
|
|
56
64
|
|
|
57
65
|
private zkvWalletClient: WalletClient | undefined;
|
|
58
66
|
|
|
@@ -156,7 +164,9 @@ export class EncryptInputsBuilder<T extends EncryptableItem[], HPP extends boole
|
|
|
156
164
|
*
|
|
157
165
|
* @returns The chainable EncryptInputsBuilder instance.
|
|
158
166
|
*/
|
|
159
|
-
setAccount(account: string): EncryptInputsBuilder<T
|
|
167
|
+
setAccount(this: EncryptInputsBuilder<T>, account: string): EncryptInputsBuilder<T>;
|
|
168
|
+
setAccount(this: EncryptInputsBuilderUnset<T>, account: string): EncryptInputsBuilderUnset<T>;
|
|
169
|
+
setAccount(account: string): EncryptInputsBuilder<T> {
|
|
160
170
|
this.account = account;
|
|
161
171
|
return this;
|
|
162
172
|
}
|
|
@@ -179,7 +189,9 @@ export class EncryptInputsBuilder<T extends EncryptableItem[], HPP extends boole
|
|
|
179
189
|
*
|
|
180
190
|
* @returns The chainable EncryptInputsBuilder instance.
|
|
181
191
|
*/
|
|
182
|
-
setChainId(chainId: number): EncryptInputsBuilder<T
|
|
192
|
+
setChainId(this: EncryptInputsBuilder<T>, chainId: number): EncryptInputsBuilder<T>;
|
|
193
|
+
setChainId(this: EncryptInputsBuilderUnset<T>, chainId: number): EncryptInputsBuilderUnset<T>;
|
|
194
|
+
setChainId(chainId: number): EncryptInputsBuilder<T> {
|
|
183
195
|
this.chainId = chainId;
|
|
184
196
|
return this;
|
|
185
197
|
}
|
|
@@ -202,7 +214,9 @@ export class EncryptInputsBuilder<T extends EncryptableItem[], HPP extends boole
|
|
|
202
214
|
*
|
|
203
215
|
* @returns The chainable EncryptInputsBuilder instance.
|
|
204
216
|
*/
|
|
205
|
-
setSecurityZone(securityZone: number): EncryptInputsBuilder<T
|
|
217
|
+
setSecurityZone(this: EncryptInputsBuilder<T>, securityZone: number): EncryptInputsBuilder<T>;
|
|
218
|
+
setSecurityZone(this: EncryptInputsBuilderUnset<T>, securityZone: number): EncryptInputsBuilderUnset<T>;
|
|
219
|
+
setSecurityZone(securityZone: number): EncryptInputsBuilder<T> {
|
|
206
220
|
this.securityZone = securityZone;
|
|
207
221
|
return this;
|
|
208
222
|
}
|
|
@@ -212,18 +226,44 @@ export class EncryptInputsBuilder<T extends EncryptableItem[], HPP extends boole
|
|
|
212
226
|
}
|
|
213
227
|
|
|
214
228
|
/**
|
|
229
|
+
* @param address - The contract that will consume the resulting hashes+signature (i.e. the
|
|
230
|
+
* contract that will call `FHE.asEuint*`/`FHE.asEuint*s` with them).
|
|
231
|
+
*
|
|
232
|
+
* Required before `execute()` - the verifier binds this address into the signed digest, so a
|
|
233
|
+
* batch signed for one contract cannot be replayed into another.
|
|
234
|
+
*
|
|
215
235
|
* Example:
|
|
216
236
|
* ```typescript
|
|
217
237
|
* const encrypted = await encryptInputs([Encryptable.uint128(10n)])
|
|
218
|
-
* .
|
|
238
|
+
* .setConsumingContract("0x123...890")
|
|
219
239
|
* .execute();
|
|
220
240
|
* ```
|
|
221
241
|
*
|
|
222
|
-
* @returns
|
|
242
|
+
* @returns The chainable EncryptInputsBuilder instance.
|
|
223
243
|
*/
|
|
224
|
-
|
|
225
|
-
this.
|
|
226
|
-
return this
|
|
244
|
+
setConsumingContract(address: string): EncryptInputsBuilder<T> {
|
|
245
|
+
this.consumingContract = address;
|
|
246
|
+
return this;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
getConsumingContract(): string | undefined {
|
|
250
|
+
return this.consumingContract;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Asserts that this.consumingContract is populated
|
|
255
|
+
* @throws {CofheError} If consumingContract is not set
|
|
256
|
+
*/
|
|
257
|
+
private assertConsumingContract(): asserts this is this & { consumingContract: string } {
|
|
258
|
+
if (this.consumingContract) return;
|
|
259
|
+
throw new CofheError({
|
|
260
|
+
code: CofheErrorCode.ConsumingContractUninitialized,
|
|
261
|
+
message: 'Consuming contract is not set',
|
|
262
|
+
hint: 'Use setConsumingContract(...) to set the contract that will consume the encrypted inputs.',
|
|
263
|
+
context: {
|
|
264
|
+
consumingContract: this.consumingContract,
|
|
265
|
+
},
|
|
266
|
+
});
|
|
227
267
|
}
|
|
228
268
|
|
|
229
269
|
/**
|
|
@@ -240,7 +280,9 @@ export class EncryptInputsBuilder<T extends EncryptableItem[], HPP extends boole
|
|
|
240
280
|
*
|
|
241
281
|
* @returns The chainable EncryptInputsBuilder instance.
|
|
242
282
|
*/
|
|
243
|
-
setUseWorker(useWorker: boolean): EncryptInputsBuilder<T
|
|
283
|
+
setUseWorker(this: EncryptInputsBuilder<T>, useWorker: boolean): EncryptInputsBuilder<T>;
|
|
284
|
+
setUseWorker(this: EncryptInputsBuilderUnset<T>, useWorker: boolean): EncryptInputsBuilderUnset<T>;
|
|
285
|
+
setUseWorker(useWorker: boolean): EncryptInputsBuilder<T> {
|
|
244
286
|
this.useWorker = useWorker;
|
|
245
287
|
return this;
|
|
246
288
|
}
|
|
@@ -277,7 +319,9 @@ export class EncryptInputsBuilder<T extends EncryptableItem[], HPP extends boole
|
|
|
277
319
|
*
|
|
278
320
|
* @returns The EncryptInputsBuilder instance.
|
|
279
321
|
*/
|
|
280
|
-
onStep(callback: EncryptStepCallbackFunction): EncryptInputsBuilder<T
|
|
322
|
+
onStep(this: EncryptInputsBuilder<T>, callback: EncryptStepCallbackFunction): EncryptInputsBuilder<T>;
|
|
323
|
+
onStep(this: EncryptInputsBuilderUnset<T>, callback: EncryptStepCallbackFunction): EncryptInputsBuilderUnset<T>;
|
|
324
|
+
onStep(callback: EncryptStepCallbackFunction): EncryptInputsBuilder<T> {
|
|
281
325
|
this.stepCallback = callback;
|
|
282
326
|
return this;
|
|
283
327
|
}
|
|
@@ -433,10 +477,11 @@ export class EncryptInputsBuilder<T extends EncryptableItem[], HPP extends boole
|
|
|
433
477
|
* cofheMocksInsertPackedHashes - stores the ctHashes and their plaintext values for on-chain mocking of FHE operations.
|
|
434
478
|
* cofheMocksZkCreateProofSignatures - creates signatures to be included in the encrypted inputs. The signers address is known and verified in the mock contracts.
|
|
435
479
|
*/
|
|
436
|
-
private async mocksExecute(): Promise<
|
|
480
|
+
private async mocksExecute(): Promise<VerifyBatchResult> {
|
|
437
481
|
this.assertAccount();
|
|
438
482
|
this.assertPublicClient();
|
|
439
483
|
this.assertWalletClient();
|
|
484
|
+
this.assertConsumingContract();
|
|
440
485
|
|
|
441
486
|
const [initTfheDelay, fetchKeysDelay, packDelay, proveDelay, verifyDelay] = this.resolveEncryptDelays();
|
|
442
487
|
|
|
@@ -468,31 +513,27 @@ export class EncryptInputsBuilder<T extends EncryptableItem[], HPP extends boole
|
|
|
468
513
|
|
|
469
514
|
this.fireStepStart(EncryptStep.Verify);
|
|
470
515
|
await sleep(verifyDelay);
|
|
471
|
-
const
|
|
516
|
+
const result = await cofheMocksZkVerifySign(
|
|
472
517
|
this.inputItems,
|
|
473
518
|
this.account,
|
|
474
519
|
this.securityZone,
|
|
520
|
+
this.consumingContract,
|
|
475
521
|
this.publicClient,
|
|
476
522
|
this.walletClient,
|
|
477
523
|
this.zkvWalletClient
|
|
478
524
|
);
|
|
479
|
-
const encryptedInputs: EncryptedItemInput[] = signedResults.map(({ ct_hash, signature }, index) => ({
|
|
480
|
-
ctHash: BigInt(ct_hash),
|
|
481
|
-
securityZone: this.securityZone,
|
|
482
|
-
utype: this.inputItems[index].utype,
|
|
483
|
-
signature,
|
|
484
|
-
}));
|
|
485
525
|
this.fireStepEnd(EncryptStep.Verify, { isMocks: true, mockSleep: verifyDelay });
|
|
486
526
|
|
|
487
|
-
return
|
|
527
|
+
return result;
|
|
488
528
|
}
|
|
489
529
|
|
|
490
530
|
/**
|
|
491
531
|
* In the production context, perform a true encryption with the CoFHE coprocessor.
|
|
492
532
|
*/
|
|
493
|
-
private async productionExecute(): Promise<
|
|
533
|
+
private async productionExecute(): Promise<VerifyBatchResult> {
|
|
494
534
|
this.assertAccount();
|
|
495
535
|
this.assertChainId();
|
|
536
|
+
this.assertConsumingContract();
|
|
496
537
|
|
|
497
538
|
this.fireStepStart(EncryptStep.InitTfhe);
|
|
498
539
|
|
|
@@ -555,32 +596,28 @@ export class EncryptInputsBuilder<T extends EncryptableItem[], HPP extends boole
|
|
|
555
596
|
|
|
556
597
|
const zkVerifierUrl = await this.getZkVerifierUrl();
|
|
557
598
|
|
|
558
|
-
const
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
signature,
|
|
566
|
-
})
|
|
599
|
+
const result = await zkVerifyBatch(
|
|
600
|
+
zkVerifierUrl,
|
|
601
|
+
proof,
|
|
602
|
+
this.account,
|
|
603
|
+
this.securityZone,
|
|
604
|
+
this.chainId,
|
|
605
|
+
this.consumingContract
|
|
567
606
|
);
|
|
568
607
|
|
|
569
608
|
this.fireStepEnd(EncryptStep.Verify);
|
|
570
609
|
|
|
571
|
-
return
|
|
610
|
+
return result;
|
|
572
611
|
}
|
|
573
612
|
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
proof += item.signature;
|
|
581
|
-
}
|
|
613
|
+
/**
|
|
614
|
+
* Converts a batch-verified result (per-item ctHash/ctType + one shared signature) into the
|
|
615
|
+
* tuple returned by `execute()`: per-item hashes in input order, followed by the single signature.
|
|
616
|
+
*/
|
|
617
|
+
private buildBatchResult(result: VerifyBatchResult): HashPlusProofResult<T> {
|
|
618
|
+
const hashes = result.outputs.map((output) => '0x' + BigInt(output.ct_hash).toString(16).padStart(64, '0'));
|
|
582
619
|
|
|
583
|
-
return [...hashes,
|
|
620
|
+
return [...hashes, result.signature] as unknown as HashPlusProofResult<T>;
|
|
584
621
|
}
|
|
585
622
|
|
|
586
623
|
/**
|
|
@@ -602,17 +639,14 @@ export class EncryptInputsBuilder<T extends EncryptableItem[], HPP extends boole
|
|
|
602
639
|
*
|
|
603
640
|
* @returns The encrypted inputs.
|
|
604
641
|
*/
|
|
605
|
-
async execute(): Promise<
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
let items: [...EncryptedItemInputs<T>];
|
|
642
|
+
async execute(): Promise<HashPlusProofResult<T>> {
|
|
643
|
+
let result: VerifyBatchResult;
|
|
609
644
|
|
|
610
645
|
// On hardhat chain, interact with MockZkVerifier contract instead of CoFHE
|
|
611
|
-
if (this.chainId === hardhat.id)
|
|
646
|
+
if (this.chainId === hardhat.id) result = await this.mocksExecute();
|
|
612
647
|
// On other chains, interact with CoFHE coprocessor
|
|
613
|
-
else
|
|
648
|
+
else result = await this.productionExecute();
|
|
614
649
|
|
|
615
|
-
|
|
616
|
-
return items as unknown as Result;
|
|
650
|
+
return this.buildBatchResult(result);
|
|
617
651
|
}
|
|
618
652
|
}
|
|
@@ -41,14 +41,19 @@ export interface ZkProveWorkerResponse {
|
|
|
41
41
|
error?: string;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
export type
|
|
44
|
+
export type VerifyBatchOutputRaw = {
|
|
45
45
|
ct_hash: string;
|
|
46
|
+
ct_type: number;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export type VerifyBatchResultRaw = {
|
|
50
|
+
ciphertexts: VerifyBatchOutputRaw[];
|
|
46
51
|
signature: string;
|
|
47
52
|
recid: number;
|
|
48
53
|
};
|
|
49
54
|
|
|
50
|
-
export type
|
|
51
|
-
|
|
55
|
+
export type VerifyBatchResult = {
|
|
56
|
+
outputs: VerifyBatchOutputRaw[];
|
|
52
57
|
signature: `0x${string}`;
|
|
53
58
|
};
|
|
54
59
|
|
|
@@ -256,13 +261,14 @@ export const constructZkPoKMetadata = (accountAddr: string, securityZone: number
|
|
|
256
261
|
return metadata;
|
|
257
262
|
};
|
|
258
263
|
|
|
259
|
-
export const
|
|
264
|
+
export const zkVerifyBatch = async (
|
|
260
265
|
verifierUrl: string,
|
|
261
266
|
serializedBytes: Uint8Array,
|
|
262
267
|
address: string,
|
|
263
268
|
securityZone: number,
|
|
264
|
-
chainId: number
|
|
265
|
-
|
|
269
|
+
chainId: number,
|
|
270
|
+
consumingContract: string
|
|
271
|
+
): Promise<VerifyBatchResult> => {
|
|
266
272
|
// Convert bytearray to hex string
|
|
267
273
|
const packed_list = toHexString(serializedBytes);
|
|
268
274
|
|
|
@@ -274,13 +280,14 @@ export const zkVerify = async (
|
|
|
274
280
|
account_addr: address,
|
|
275
281
|
security_zone: sz_byte[0],
|
|
276
282
|
chain_id: chainId,
|
|
283
|
+
contract_address: consumingContract,
|
|
277
284
|
};
|
|
278
285
|
|
|
279
286
|
const body = JSON.stringify(payload);
|
|
280
287
|
|
|
281
288
|
// Send request to verification server
|
|
282
289
|
try {
|
|
283
|
-
const response = await fetch(`${verifierUrl}/
|
|
290
|
+
const response = await fetch(`${verifierUrl}/verifyBatch`, {
|
|
284
291
|
method: 'POST',
|
|
285
292
|
headers: {
|
|
286
293
|
'Content-Type': 'application/json',
|
|
@@ -293,34 +300,34 @@ export const zkVerify = async (
|
|
|
293
300
|
const errorBody = await response.text();
|
|
294
301
|
throw new CofheError({
|
|
295
302
|
code: CofheErrorCode.ZkVerifyFailed,
|
|
296
|
-
message: `HTTP error! ZK proof verification failed - ${errorBody}`,
|
|
303
|
+
message: `HTTP error! ZK batch proof verification failed - ${errorBody}`,
|
|
297
304
|
});
|
|
298
305
|
}
|
|
299
306
|
|
|
300
|
-
const json = (await response.json()) as { status: string; data:
|
|
307
|
+
const json = (await response.json()) as { status: string; data: VerifyBatchResultRaw; error: string };
|
|
301
308
|
|
|
302
309
|
if (json.status !== 'success') {
|
|
303
310
|
throw new CofheError({
|
|
304
311
|
code: CofheErrorCode.ZkVerifyFailed,
|
|
305
|
-
message: `ZK proof verification response malformed - ${json.error}`,
|
|
312
|
+
message: `ZK batch proof verification response malformed - ${json.error}`,
|
|
306
313
|
});
|
|
307
314
|
}
|
|
308
315
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
}
|
|
316
|
+
const { ciphertexts, signature, recid } = json.data;
|
|
317
|
+
|
|
318
|
+
return {
|
|
319
|
+
outputs: ciphertexts,
|
|
320
|
+
signature: concatSigRecid(signature, recid),
|
|
321
|
+
};
|
|
315
322
|
} catch (e) {
|
|
316
323
|
throw new CofheError({
|
|
317
324
|
code: CofheErrorCode.ZkVerifyFailed,
|
|
318
|
-
message: `ZK proof verification failed`,
|
|
325
|
+
message: `ZK batch proof verification failed`,
|
|
319
326
|
cause: e instanceof Error ? e : undefined,
|
|
320
327
|
});
|
|
321
328
|
}
|
|
322
329
|
};
|
|
323
330
|
|
|
324
|
-
const concatSigRecid = (signature: string, recid: number): `0x${string}` => {
|
|
331
|
+
export const concatSigRecid = (signature: string, recid: number): `0x${string}` => {
|
|
325
332
|
return `${signature}${(recid + 27).toString(16).padStart(2, '0')}` as `0x${string}`;
|
|
326
333
|
};
|
package/core/error.ts
CHANGED
|
@@ -9,12 +9,13 @@ export enum CofheErrorCode {
|
|
|
9
9
|
MissingWalletClient = 'MISSING_WALLET_CLIENT',
|
|
10
10
|
MissingProviderParam = 'MISSING_PROVIDER_PARAM',
|
|
11
11
|
EmptySecurityZonesParam = 'EMPTY_SECURITY_ZONES_PARAM',
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
InvalidACPData = 'INVALID_ACP_DATA',
|
|
13
|
+
InvalidACPDomain = 'INVALID_ACP_DOMAIN',
|
|
14
|
+
ACPNotFound = 'ACP_NOT_FOUND',
|
|
15
|
+
CannotRemoveLastACP = 'CANNOT_REMOVE_LAST_ACP',
|
|
16
16
|
AccountUninitialized = 'ACCOUNT_UNINITIALIZED',
|
|
17
17
|
ChainIdUninitialized = 'CHAIN_ID_UNINITIALIZED',
|
|
18
|
+
ConsumingContractUninitialized = 'CONSUMING_CONTRACT_UNINITIALIZED',
|
|
18
19
|
SealOutputFailed = 'SEAL_OUTPUT_FAILED',
|
|
19
20
|
SealOutputReturnedNull = 'SEAL_OUTPUT_RETURNED_NULL',
|
|
20
21
|
InvalidUtype = 'INVALID_UTYPE',
|
|
@@ -42,6 +43,26 @@ export enum CofheErrorCode {
|
|
|
42
43
|
PublicWalletGetChainIdFailed = 'PUBLIC_WALLET_GET_CHAIN_ID_FAILED',
|
|
43
44
|
PublicWalletGetAddressesFailed = 'PUBLIC_WALLET_GET_ADDRESSES_FAILED',
|
|
44
45
|
RehydrateKeysStoreFailed = 'REHYDRATE_KEYS_STORE_FAILED',
|
|
46
|
+
|
|
47
|
+
// Threshold-network stable error codes (decrypt/sealoutput), see API-RESPONSES.md
|
|
48
|
+
BadRequest = 'BAD_REQUEST',
|
|
49
|
+
UnknownChain = 'UNKNOWN_CHAIN',
|
|
50
|
+
ACPMalformed = 'ACP_MALFORMED',
|
|
51
|
+
ACPDenied = 'ACP_DENIED',
|
|
52
|
+
ACPExpired = 'ACP_EXPIRED',
|
|
53
|
+
ACPInvalid = 'ACP_INVALID',
|
|
54
|
+
ACPRevoked = 'ACP_REVOKED',
|
|
55
|
+
NotPubliclyAllowed = 'NOT_PUBLICLY_ALLOWED',
|
|
56
|
+
CtNotFound = 'CT_NOT_FOUND',
|
|
57
|
+
UnsupportedSecurityZone = 'UNSUPPORTED_SECURITY_ZONE',
|
|
58
|
+
UnsupportedType = 'UNSUPPORTED_TYPE',
|
|
59
|
+
SigningFailed = 'SIGNING_FAILED',
|
|
60
|
+
CtSourceError = 'CT_SOURCE_ERROR',
|
|
61
|
+
ACPVerifierError = 'ACP_VERIFIER_ERROR',
|
|
62
|
+
CtSourceTimeout = 'CT_SOURCE_TIMEOUT',
|
|
63
|
+
ACPVerifierTimeout = 'ACP_VERIFIER_TIMEOUT',
|
|
64
|
+
ACPRequired = 'ACP_REQUIRED',
|
|
65
|
+
SealFailed = 'SEAL_FAILED',
|
|
45
66
|
}
|
|
46
67
|
|
|
47
68
|
export type CofheErrorParams = {
|
|
@@ -50,6 +71,8 @@ export type CofheErrorParams = {
|
|
|
50
71
|
cause?: Error;
|
|
51
72
|
hint?: string;
|
|
52
73
|
context?: Record<string, unknown>;
|
|
74
|
+
/** Raw backend `error` string, when this error originated from a threshold-network response. */
|
|
75
|
+
apiErrorCode?: string;
|
|
53
76
|
};
|
|
54
77
|
|
|
55
78
|
/**
|
|
@@ -68,8 +91,9 @@ export class CofheError extends Error {
|
|
|
68
91
|
public readonly cause?: Error;
|
|
69
92
|
public readonly hint?: string;
|
|
70
93
|
public readonly context?: Record<string, unknown>;
|
|
94
|
+
public readonly apiErrorCode?: string;
|
|
71
95
|
|
|
72
|
-
constructor({ code, message, cause, hint, context }: CofheErrorParams) {
|
|
96
|
+
constructor({ code, message, cause, hint, context, apiErrorCode }: CofheErrorParams) {
|
|
73
97
|
// If there's a cause, append its message to provide full context
|
|
74
98
|
const fullMessage = cause ? `${message} | Caused by: ${cause.message}` : message;
|
|
75
99
|
|
|
@@ -79,6 +103,7 @@ export class CofheError extends Error {
|
|
|
79
103
|
this.cause = cause;
|
|
80
104
|
this.hint = hint;
|
|
81
105
|
this.context = context;
|
|
106
|
+
this.apiErrorCode = apiErrorCode;
|
|
82
107
|
|
|
83
108
|
// Maintains proper stack trace for where our error was thrown (only available on V8)
|
|
84
109
|
if (Error.captureStackTrace) {
|
|
@@ -101,6 +126,7 @@ export class CofheError extends Error {
|
|
|
101
126
|
message: wrapperError?.message ?? 'An internal error occurred',
|
|
102
127
|
hint: wrapperError?.hint,
|
|
103
128
|
context: wrapperError?.context,
|
|
129
|
+
apiErrorCode: wrapperError?.apiErrorCode,
|
|
104
130
|
cause: cause,
|
|
105
131
|
});
|
|
106
132
|
}
|
|
@@ -115,6 +141,7 @@ export class CofheError extends Error {
|
|
|
115
141
|
message: this.message,
|
|
116
142
|
hint: this.hint,
|
|
117
143
|
context: this.context,
|
|
144
|
+
apiErrorCode: this.apiErrorCode,
|
|
118
145
|
cause: this.cause
|
|
119
146
|
? {
|
|
120
147
|
name: this.cause.name,
|
|
@@ -130,7 +157,8 @@ export class CofheError extends Error {
|
|
|
130
157
|
* Returns a human-readable string representation of the error
|
|
131
158
|
*/
|
|
132
159
|
toString(): string {
|
|
133
|
-
const
|
|
160
|
+
const codeSuffix = this.apiErrorCode ? ` (api: ${this.apiErrorCode})` : '';
|
|
161
|
+
const parts = [`${this.name} [${this.code}]${codeSuffix}: ${this.message}`];
|
|
134
162
|
|
|
135
163
|
if (this.hint) {
|
|
136
164
|
parts.push(`Hint: ${this.hint}`);
|
package/core/index.ts
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
// Client (base implementations)
|
|
2
2
|
export { createCofheClientBase, InitialConnectStore as CONNECT_STORE_DEFAULTS } from './client.js';
|
|
3
3
|
|
|
4
|
+
// Debug interceptors (neutral, opt-in network hooks for fault injection / logging)
|
|
5
|
+
export { setCofheDebugInterceptors, getCofheDebugInterceptors, cofheFetch } from './debug.js';
|
|
6
|
+
export type {
|
|
7
|
+
CofheDebugInterceptors,
|
|
8
|
+
CofheOnRequest,
|
|
9
|
+
CofheOnResponse,
|
|
10
|
+
CofheRequestContext,
|
|
11
|
+
CofheRequestOverride,
|
|
12
|
+
} from './debug.js';
|
|
13
|
+
|
|
4
14
|
// Configuration (base implementations)
|
|
5
|
-
export { createCofheConfigBase, getCofheConfigItem } from './config.js';
|
|
15
|
+
export { createCofheConfigBase, getCofheConfigItem, assertNoRenamedConfigKeys } from './config.js';
|
|
6
16
|
export type { CofheConfig, CofheInputConfig, CofheInternalConfig } from './config.js';
|
|
7
17
|
|
|
8
18
|
// Types
|
|
@@ -11,7 +21,7 @@ export type {
|
|
|
11
21
|
CofheClient as CofheClient,
|
|
12
22
|
CofheClientParams as CofheClientParams,
|
|
13
23
|
CofheClientConnectionState as CofheClientConnectionState,
|
|
14
|
-
|
|
24
|
+
CofheClientACPs as CofheClientACPs,
|
|
15
25
|
} from './clientTypes.js';
|
|
16
26
|
|
|
17
27
|
export type {
|
|
@@ -30,18 +40,8 @@ export type {
|
|
|
30
40
|
EncryptableAddress,
|
|
31
41
|
// Encrypted types
|
|
32
42
|
EncryptedNumber,
|
|
33
|
-
EncryptedItemInput,
|
|
34
|
-
EncryptedBoolInput,
|
|
35
|
-
EncryptedUint8Input,
|
|
36
|
-
EncryptedUint16Input,
|
|
37
|
-
EncryptedUint32Input,
|
|
38
|
-
EncryptedUint64Input,
|
|
39
|
-
EncryptedUint128Input,
|
|
40
|
-
EncryptedAddressInput,
|
|
41
|
-
EncryptedItemInputs,
|
|
42
|
-
EncryptableToEncryptedItemInputMap,
|
|
43
43
|
FheTypeValue,
|
|
44
|
-
//
|
|
44
|
+
// Batch-verified external hash + signature types
|
|
45
45
|
ExternalBoolHash,
|
|
46
46
|
ExternalUint8Hash,
|
|
47
47
|
ExternalUint16Hash,
|
|
@@ -71,7 +71,6 @@ export {
|
|
|
71
71
|
isEncryptableItem,
|
|
72
72
|
EncryptStep,
|
|
73
73
|
isLastEncryptionStep,
|
|
74
|
-
assertCorrectEncryptedItemInput,
|
|
75
74
|
} from './types.js';
|
|
76
75
|
|
|
77
76
|
// Error handling
|
|
@@ -88,6 +87,7 @@ export type { KeysStorage, KeysStore } from './keyStore.js';
|
|
|
88
87
|
|
|
89
88
|
// Builders (exported via client, but can be imported directly for typing)
|
|
90
89
|
export { EncryptInputsBuilder } from './encrypt/encryptInputsBuilder.js';
|
|
90
|
+
export type { EncryptInputsBuilderUnset } from './encrypt/encryptInputsBuilder.js';
|
|
91
91
|
export { DecryptForViewBuilder } from './decrypt/decryptForViewBuilder.js';
|
|
92
92
|
export { DecryptForTxBuilder } from './decrypt/decryptForTxBuilder.js';
|
|
93
93
|
export type { DecryptForTxResult } from './decrypt/decryptForTxBuilder.js';
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { acps } from '../acps.js';
|
|
3
|
+
|
|
4
|
+
type ScopeOpts = {
|
|
5
|
+
revokerData?: number;
|
|
6
|
+
revokerContract?: string;
|
|
7
|
+
scope?: number;
|
|
8
|
+
contracts?: string[];
|
|
9
|
+
handles?: bigint[];
|
|
10
|
+
};
|
|
11
|
+
const opts = (o: ScopeOpts): ScopeOpts => o;
|
|
12
|
+
|
|
13
|
+
const CHAIN = 31337;
|
|
14
|
+
const REVOKER = '0x00000000000000000000000000000000000000aa' as `0x${string}`;
|
|
15
|
+
const CONTRACT_A = '0x00000000000000000000000000000000000000bb' as `0x${string}`;
|
|
16
|
+
|
|
17
|
+
const acpConfig = {
|
|
18
|
+
defaultRevoker: { [CHAIN]: REVOKER },
|
|
19
|
+
defaultContractScopes: { [CHAIN]: [CONTRACT_A] },
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
describe('applyACPDefaults', () => {
|
|
23
|
+
it('injects default revoker (contract + creation timestamp) when no revoker options given', () => {
|
|
24
|
+
const before = Math.round(Date.now() / 1000);
|
|
25
|
+
const result = acps.applyACPDefaults(opts({}), acpConfig, CHAIN);
|
|
26
|
+
expect(result.revokerContract).toBe(REVOKER);
|
|
27
|
+
expect(result.revokerData).toBeGreaterThanOrEqual(before - 60); // 60s clock-skew backdating
|
|
28
|
+
expect(result.revokerData).toBeLessThanOrEqual(Math.round(Date.now() / 1000) - 59);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('does not override an explicit revoker pair', () => {
|
|
32
|
+
const result = acps.applyACPDefaults({ revokerData: 42, revokerContract: CONTRACT_A }, acpConfig, CHAIN);
|
|
33
|
+
expect(result.revokerData).toBe(42);
|
|
34
|
+
expect(result.revokerContract).toBe(CONTRACT_A);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('injects default contract scopes when no scope options given', () => {
|
|
38
|
+
const result = acps.applyACPDefaults(opts({}), acpConfig, CHAIN);
|
|
39
|
+
expect(result.contracts).toEqual([CONTRACT_A]);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('does not inject scopes when the caller provides any scope option (incl. explicit scope)', () => {
|
|
43
|
+
expect(acps.applyACPDefaults(opts({ scope: 0 }), acpConfig, CHAIN).contracts).toBeUndefined();
|
|
44
|
+
expect(acps.applyACPDefaults(opts({ handles: [1n] }), acpConfig, CHAIN).contracts).toBeUndefined();
|
|
45
|
+
expect(acps.applyACPDefaults(opts({ contracts: [] }), acpConfig, CHAIN).contracts).toEqual([]);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('no-op for chains without defaults and for missing config', () => {
|
|
49
|
+
expect(acps.applyACPDefaults(opts({}), acpConfig, 999)).toEqual({});
|
|
50
|
+
expect(acps.applyACPDefaults(opts({}), undefined, CHAIN)).toEqual({});
|
|
51
|
+
});
|
|
52
|
+
});
|