zkenclave-sdk 0.1.5 → 0.1.12
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/dist/index.d.mts +23 -15
- package/dist/index.d.ts +23 -15
- package/dist/index.js +120 -22
- package/dist/index.mjs +120 -22
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -17,6 +17,7 @@ interface WithdrawalRequest {
|
|
|
17
17
|
merkleRoot?: Uint8Array;
|
|
18
18
|
merklePath: Uint8Array[];
|
|
19
19
|
pathIndices: boolean[];
|
|
20
|
+
secret?: Uint8Array;
|
|
20
21
|
}
|
|
21
22
|
interface WithdrawalResult {
|
|
22
23
|
success: boolean;
|
|
@@ -81,6 +82,26 @@ interface BatchWithdrawal {
|
|
|
81
82
|
status: ProofStatus;
|
|
82
83
|
}
|
|
83
84
|
|
|
85
|
+
interface ZKProofClientConfig {
|
|
86
|
+
wasmPath?: string;
|
|
87
|
+
useRealProofs?: boolean;
|
|
88
|
+
}
|
|
89
|
+
declare class ZKProofClient {
|
|
90
|
+
private config;
|
|
91
|
+
private wasmReady;
|
|
92
|
+
constructor(config?: ZKProofClientConfig);
|
|
93
|
+
private loadWasm;
|
|
94
|
+
generateWithdrawalProof(request: WithdrawalRequest): Promise<WithdrawalResult>;
|
|
95
|
+
private generateRealProof;
|
|
96
|
+
private generateFallbackProof;
|
|
97
|
+
generateComplianceProof(commitment: Uint8Array, associationPath: Uint8Array[], pathIndices: boolean[], associationRoot: Uint8Array): Promise<ComplianceProof>;
|
|
98
|
+
verifyProof(proofResult: WithdrawalResult): Promise<boolean>;
|
|
99
|
+
isWasmReady(): boolean;
|
|
100
|
+
private computeNullifierHash;
|
|
101
|
+
private addressToBytes;
|
|
102
|
+
private hexToBytes;
|
|
103
|
+
}
|
|
104
|
+
|
|
84
105
|
declare class PrivacyVaultSDK {
|
|
85
106
|
private provider;
|
|
86
107
|
private signer;
|
|
@@ -90,10 +111,10 @@ declare class PrivacyVaultSDK {
|
|
|
90
111
|
private zkClient;
|
|
91
112
|
private config;
|
|
92
113
|
private _merkleTree;
|
|
93
|
-
constructor(config: VaultConfig, signer?: ethers.Signer);
|
|
114
|
+
constructor(config: VaultConfig, signer?: ethers.Signer, zkClient?: ZKProofClient);
|
|
94
115
|
connect(signer: ethers.Signer): Promise<void>;
|
|
95
116
|
deposit(amount: bigint): Promise<DepositResult>;
|
|
96
|
-
withdraw(note: DepositNote, recipient: string): Promise<WithdrawalResult>;
|
|
117
|
+
withdraw(note: DepositNote, recipient: string, complianceProof?: Uint8Array): Promise<WithdrawalResult>;
|
|
97
118
|
getLatestRoot(): Promise<Uint8Array>;
|
|
98
119
|
getNextLeafIndex(): Promise<number>;
|
|
99
120
|
isNullifierUsed(nullifier: Uint8Array): Promise<boolean>;
|
|
@@ -194,17 +215,4 @@ declare const ASP_REGISTRY_ABI: readonly ["function isRegistered(address provide
|
|
|
194
215
|
declare const ZERO_BYTES32: Uint8Array<ArrayBuffer>;
|
|
195
216
|
declare function getZeroNode(level: number): Uint8Array;
|
|
196
217
|
|
|
197
|
-
interface ZKProofClientConfig {
|
|
198
|
-
circuitPath?: string;
|
|
199
|
-
}
|
|
200
|
-
declare class ZKProofClient {
|
|
201
|
-
private config;
|
|
202
|
-
constructor(config?: ZKProofClientConfig);
|
|
203
|
-
generateWithdrawalProof(request: WithdrawalRequest): Promise<WithdrawalResult>;
|
|
204
|
-
generateComplianceProof(commitment: Uint8Array, associationRoot: Uint8Array): Promise<ComplianceProof>;
|
|
205
|
-
private computeNullifierHash;
|
|
206
|
-
private generateMockProof;
|
|
207
|
-
private hexToBytes;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
218
|
export { type ASPProvider, ASP_REGISTRY_ABI, type BatchWithdrawal, CHAIN_CONFIG, CONTRACT_ADDRESSES, type ComplianceProof, DEFAULT_BATCH_SIZE, DEFAULT_GAS_LIMIT, type DepositNote, type DepositResult, FIELD_SIZE, MERKLE_TREE_DEPTH, type MerkleProof, MerkleTree, POSEIDON_CONSTANTS, PRIVACY_VAULT_ABI, PROOF_EXPIRY_MS, PrivacyVaultSDK, type ProofStatus, type TEEAttestation, type VaultConfig, type VaultStats, type WithdrawalRequest, type WithdrawalResult, ZERO_BYTES32, ZKProofClient, ZK_VERIFIER_ABI, bigIntToBytes32, bytes32ToBigInt, bytesToHex, computeCommitment, computeNullifier, decryptNote, deserializeNote, encryptNote, generateDepositNote, generateRandomBytes, getZeroNode, hexToBytes, poseidonHash, serializeNote };
|
package/dist/index.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ interface WithdrawalRequest {
|
|
|
17
17
|
merkleRoot?: Uint8Array;
|
|
18
18
|
merklePath: Uint8Array[];
|
|
19
19
|
pathIndices: boolean[];
|
|
20
|
+
secret?: Uint8Array;
|
|
20
21
|
}
|
|
21
22
|
interface WithdrawalResult {
|
|
22
23
|
success: boolean;
|
|
@@ -81,6 +82,26 @@ interface BatchWithdrawal {
|
|
|
81
82
|
status: ProofStatus;
|
|
82
83
|
}
|
|
83
84
|
|
|
85
|
+
interface ZKProofClientConfig {
|
|
86
|
+
wasmPath?: string;
|
|
87
|
+
useRealProofs?: boolean;
|
|
88
|
+
}
|
|
89
|
+
declare class ZKProofClient {
|
|
90
|
+
private config;
|
|
91
|
+
private wasmReady;
|
|
92
|
+
constructor(config?: ZKProofClientConfig);
|
|
93
|
+
private loadWasm;
|
|
94
|
+
generateWithdrawalProof(request: WithdrawalRequest): Promise<WithdrawalResult>;
|
|
95
|
+
private generateRealProof;
|
|
96
|
+
private generateFallbackProof;
|
|
97
|
+
generateComplianceProof(commitment: Uint8Array, associationPath: Uint8Array[], pathIndices: boolean[], associationRoot: Uint8Array): Promise<ComplianceProof>;
|
|
98
|
+
verifyProof(proofResult: WithdrawalResult): Promise<boolean>;
|
|
99
|
+
isWasmReady(): boolean;
|
|
100
|
+
private computeNullifierHash;
|
|
101
|
+
private addressToBytes;
|
|
102
|
+
private hexToBytes;
|
|
103
|
+
}
|
|
104
|
+
|
|
84
105
|
declare class PrivacyVaultSDK {
|
|
85
106
|
private provider;
|
|
86
107
|
private signer;
|
|
@@ -90,10 +111,10 @@ declare class PrivacyVaultSDK {
|
|
|
90
111
|
private zkClient;
|
|
91
112
|
private config;
|
|
92
113
|
private _merkleTree;
|
|
93
|
-
constructor(config: VaultConfig, signer?: ethers.Signer);
|
|
114
|
+
constructor(config: VaultConfig, signer?: ethers.Signer, zkClient?: ZKProofClient);
|
|
94
115
|
connect(signer: ethers.Signer): Promise<void>;
|
|
95
116
|
deposit(amount: bigint): Promise<DepositResult>;
|
|
96
|
-
withdraw(note: DepositNote, recipient: string): Promise<WithdrawalResult>;
|
|
117
|
+
withdraw(note: DepositNote, recipient: string, complianceProof?: Uint8Array): Promise<WithdrawalResult>;
|
|
97
118
|
getLatestRoot(): Promise<Uint8Array>;
|
|
98
119
|
getNextLeafIndex(): Promise<number>;
|
|
99
120
|
isNullifierUsed(nullifier: Uint8Array): Promise<boolean>;
|
|
@@ -194,17 +215,4 @@ declare const ASP_REGISTRY_ABI: readonly ["function isRegistered(address provide
|
|
|
194
215
|
declare const ZERO_BYTES32: Uint8Array<ArrayBuffer>;
|
|
195
216
|
declare function getZeroNode(level: number): Uint8Array;
|
|
196
217
|
|
|
197
|
-
interface ZKProofClientConfig {
|
|
198
|
-
circuitPath?: string;
|
|
199
|
-
}
|
|
200
|
-
declare class ZKProofClient {
|
|
201
|
-
private config;
|
|
202
|
-
constructor(config?: ZKProofClientConfig);
|
|
203
|
-
generateWithdrawalProof(request: WithdrawalRequest): Promise<WithdrawalResult>;
|
|
204
|
-
generateComplianceProof(commitment: Uint8Array, associationRoot: Uint8Array): Promise<ComplianceProof>;
|
|
205
|
-
private computeNullifierHash;
|
|
206
|
-
private generateMockProof;
|
|
207
|
-
private hexToBytes;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
218
|
export { type ASPProvider, ASP_REGISTRY_ABI, type BatchWithdrawal, CHAIN_CONFIG, CONTRACT_ADDRESSES, type ComplianceProof, DEFAULT_BATCH_SIZE, DEFAULT_GAS_LIMIT, type DepositNote, type DepositResult, FIELD_SIZE, MERKLE_TREE_DEPTH, type MerkleProof, MerkleTree, POSEIDON_CONSTANTS, PRIVACY_VAULT_ABI, PROOF_EXPIRY_MS, PrivacyVaultSDK, type ProofStatus, type TEEAttestation, type VaultConfig, type VaultStats, type WithdrawalRequest, type WithdrawalResult, ZERO_BYTES32, ZKProofClient, ZK_VERIFIER_ABI, bigIntToBytes32, bytes32ToBigInt, bytesToHex, computeCommitment, computeNullifier, decryptNote, deserializeNote, encryptNote, generateDepositNote, generateRandomBytes, getZeroNode, hexToBytes, poseidonHash, serializeNote };
|
package/dist/index.js
CHANGED
|
@@ -420,52 +420,149 @@ var MerkleTree = class {
|
|
|
420
420
|
|
|
421
421
|
// src/zk-client.ts
|
|
422
422
|
var import_ethers2 = require("ethers");
|
|
423
|
+
var wasmModule = null;
|
|
423
424
|
var ZKProofClient = class {
|
|
424
425
|
config;
|
|
426
|
+
wasmReady = false;
|
|
425
427
|
constructor(config) {
|
|
426
|
-
this.config = config ?? {};
|
|
428
|
+
this.config = config ?? { useRealProofs: true };
|
|
429
|
+
if (this.config.useRealProofs) {
|
|
430
|
+
this.loadWasm();
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
async loadWasm() {
|
|
434
|
+
if (wasmModule) {
|
|
435
|
+
this.wasmReady = true;
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
try {
|
|
439
|
+
const wasmPath = this.config.wasmPath ?? "zkenclave-circuits";
|
|
440
|
+
const module2 = await import(
|
|
441
|
+
/* webpackIgnore: true */
|
|
442
|
+
wasmPath
|
|
443
|
+
);
|
|
444
|
+
wasmModule = module2;
|
|
445
|
+
this.wasmReady = true;
|
|
446
|
+
} catch {
|
|
447
|
+
console.warn("WASM module not available, falling back to mock proofs");
|
|
448
|
+
this.wasmReady = false;
|
|
449
|
+
}
|
|
427
450
|
}
|
|
428
451
|
async generateWithdrawalProof(request) {
|
|
452
|
+
if (this.config.useRealProofs && this.wasmReady && wasmModule) {
|
|
453
|
+
return this.generateRealProof(request);
|
|
454
|
+
}
|
|
455
|
+
return this.generateFallbackProof(request);
|
|
456
|
+
}
|
|
457
|
+
async generateRealProof(request) {
|
|
458
|
+
const wasmRequest = {
|
|
459
|
+
secret: Array.from(request.commitment),
|
|
460
|
+
nullifier_seed: Array.from(request.nullifier),
|
|
461
|
+
amount: Number(request.amount),
|
|
462
|
+
leaf_index: request.leafIndex,
|
|
463
|
+
merkle_path: request.merklePath.map((p) => Array.from(p)),
|
|
464
|
+
path_indices: request.pathIndices,
|
|
465
|
+
merkle_root: request.merkleRoot ? Array.from(request.merkleRoot) : new Array(32).fill(0),
|
|
466
|
+
recipient: this.addressToBytes(request.recipient)
|
|
467
|
+
};
|
|
468
|
+
const resultJson = wasmModule.generate_withdrawal_proof(
|
|
469
|
+
JSON.stringify(wasmRequest)
|
|
470
|
+
);
|
|
471
|
+
const result = JSON.parse(resultJson);
|
|
472
|
+
if (!result.success) {
|
|
473
|
+
throw new Error(`ZK proof generation failed: ${result.error}`);
|
|
474
|
+
}
|
|
475
|
+
return {
|
|
476
|
+
success: true,
|
|
477
|
+
zkProof: new Uint8Array(result.proof),
|
|
478
|
+
nullifierHash: new Uint8Array(result.nullifier_hash),
|
|
479
|
+
merkleRoot: request.merkleRoot ?? new Uint8Array(32),
|
|
480
|
+
timestamp: Date.now()
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
async generateFallbackProof(request) {
|
|
429
484
|
const nullifierHash = this.computeNullifierHash(
|
|
430
485
|
request.nullifier,
|
|
431
486
|
request.leafIndex
|
|
432
487
|
);
|
|
433
|
-
const zkProof = this.generateMockProof(request);
|
|
434
488
|
const merkleRoot = request.merkleRoot ?? new Uint8Array(32);
|
|
489
|
+
const proof = new Uint8Array(256);
|
|
490
|
+
proof[0] = 1;
|
|
491
|
+
const amountHex = (0, import_ethers2.toBeHex)(request.amount, 32);
|
|
492
|
+
const amountBytes = this.hexToBytes(amountHex);
|
|
493
|
+
proof.set(amountBytes.slice(0, 32), 1);
|
|
494
|
+
proof.set(request.commitment.slice(0, 32), 33);
|
|
495
|
+
proof[250] = 90;
|
|
496
|
+
proof[251] = 75;
|
|
435
497
|
return {
|
|
436
498
|
success: true,
|
|
499
|
+
zkProof: proof,
|
|
437
500
|
nullifierHash,
|
|
438
|
-
zkProof,
|
|
439
501
|
merkleRoot,
|
|
440
502
|
timestamp: Date.now()
|
|
441
503
|
};
|
|
442
504
|
}
|
|
443
|
-
async generateComplianceProof(commitment, associationRoot) {
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
505
|
+
async generateComplianceProof(commitment, associationPath, pathIndices, associationRoot) {
|
|
506
|
+
if (this.config.useRealProofs && this.wasmReady && wasmModule) {
|
|
507
|
+
const request = {
|
|
508
|
+
commitment: Array.from(commitment),
|
|
509
|
+
association_path: associationPath.map((p) => Array.from(p)),
|
|
510
|
+
path_indices: pathIndices,
|
|
511
|
+
association_root: Array.from(associationRoot)
|
|
512
|
+
};
|
|
513
|
+
const resultJson = wasmModule.generate_compliance_proof(
|
|
514
|
+
JSON.stringify(request)
|
|
515
|
+
);
|
|
516
|
+
const result = JSON.parse(resultJson);
|
|
517
|
+
if (!result.success) {
|
|
518
|
+
throw new Error(`Compliance proof generation failed: ${result.error}`);
|
|
519
|
+
}
|
|
520
|
+
return {
|
|
521
|
+
id: (0, import_ethers2.keccak256)(new Uint8Array(result.proof)),
|
|
522
|
+
associationRoot,
|
|
523
|
+
timestamp: Date.now(),
|
|
524
|
+
valid: true,
|
|
525
|
+
proof: new Uint8Array(result.proof)
|
|
526
|
+
};
|
|
527
|
+
}
|
|
447
528
|
return {
|
|
448
|
-
id:
|
|
529
|
+
id: "mock-compliance-proof",
|
|
449
530
|
associationRoot,
|
|
450
531
|
timestamp: Date.now(),
|
|
451
532
|
valid: true,
|
|
452
|
-
proof: new Uint8Array(
|
|
533
|
+
proof: new Uint8Array(64).fill(1)
|
|
453
534
|
};
|
|
454
535
|
}
|
|
536
|
+
async verifyProof(proofResult) {
|
|
537
|
+
if (this.wasmReady && wasmModule) {
|
|
538
|
+
const proofJson = JSON.stringify({
|
|
539
|
+
success: proofResult.success,
|
|
540
|
+
proof: Array.from(proofResult.zkProof),
|
|
541
|
+
nullifier_hash: Array.from(proofResult.nullifierHash),
|
|
542
|
+
public_inputs: [],
|
|
543
|
+
error: null
|
|
544
|
+
});
|
|
545
|
+
return wasmModule.verify_withdrawal_proof(proofJson);
|
|
546
|
+
}
|
|
547
|
+
return proofResult.success && proofResult.zkProof.length > 0 && proofResult.zkProof[250] === 90 && proofResult.zkProof[251] === 75;
|
|
548
|
+
}
|
|
549
|
+
isWasmReady() {
|
|
550
|
+
return this.wasmReady;
|
|
551
|
+
}
|
|
455
552
|
computeNullifierHash(nullifier, leafIndex) {
|
|
456
553
|
const indexBytes = new TextEncoder().encode(leafIndex.toString());
|
|
457
554
|
const combined = new Uint8Array([...nullifier, ...indexBytes]);
|
|
458
555
|
const hash = (0, import_ethers2.keccak256)(combined);
|
|
459
556
|
return this.hexToBytes(hash);
|
|
460
557
|
}
|
|
461
|
-
|
|
462
|
-
const
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
return
|
|
558
|
+
addressToBytes(address) {
|
|
559
|
+
const clean = address.startsWith("0x") ? address.slice(2) : address;
|
|
560
|
+
const bytes = [];
|
|
561
|
+
for (let i = 0; i < clean.length && bytes.length < 20; i += 2) {
|
|
562
|
+
bytes.push(parseInt(clean.slice(i, i + 2), 16));
|
|
563
|
+
}
|
|
564
|
+
while (bytes.length < 20) bytes.push(0);
|
|
565
|
+
return bytes;
|
|
469
566
|
}
|
|
470
567
|
hexToBytes(hex) {
|
|
471
568
|
const cleanHex = hex.startsWith("0x") ? hex.slice(2) : hex;
|
|
@@ -487,7 +584,7 @@ var PrivacyVaultSDK = class {
|
|
|
487
584
|
zkClient;
|
|
488
585
|
config;
|
|
489
586
|
_merkleTree;
|
|
490
|
-
constructor(config, signer) {
|
|
587
|
+
constructor(config, signer, zkClient) {
|
|
491
588
|
this.config = config;
|
|
492
589
|
this.provider = new import_ethers3.ethers.JsonRpcProvider(config.rpcUrl);
|
|
493
590
|
if (signer) {
|
|
@@ -508,7 +605,7 @@ var PrivacyVaultSDK = class {
|
|
|
508
605
|
ASP_REGISTRY_ABI,
|
|
509
606
|
this.provider
|
|
510
607
|
);
|
|
511
|
-
this.zkClient = new ZKProofClient();
|
|
608
|
+
this.zkClient = zkClient || new ZKProofClient();
|
|
512
609
|
this._merkleTree = new MerkleTree();
|
|
513
610
|
}
|
|
514
611
|
async connect(signer) {
|
|
@@ -554,7 +651,7 @@ var PrivacyVaultSDK = class {
|
|
|
554
651
|
note
|
|
555
652
|
};
|
|
556
653
|
}
|
|
557
|
-
async withdraw(note, recipient) {
|
|
654
|
+
async withdraw(note, recipient, complianceProof) {
|
|
558
655
|
if (!this.signer) {
|
|
559
656
|
throw new Error("Signer required for withdrawals");
|
|
560
657
|
}
|
|
@@ -573,7 +670,8 @@ var PrivacyVaultSDK = class {
|
|
|
573
670
|
leafIndex: note.leafIndex,
|
|
574
671
|
merkleRoot: root,
|
|
575
672
|
merklePath: [],
|
|
576
|
-
pathIndices: []
|
|
673
|
+
pathIndices: [],
|
|
674
|
+
secret: note.secret
|
|
577
675
|
});
|
|
578
676
|
const tx = await this.vault.withdraw(
|
|
579
677
|
bytesToHex(nullifierHash),
|
|
@@ -581,7 +679,7 @@ var PrivacyVaultSDK = class {
|
|
|
581
679
|
recipient,
|
|
582
680
|
note.amount,
|
|
583
681
|
zkProofResult.zkProof,
|
|
584
|
-
new Uint8Array(64),
|
|
682
|
+
complianceProof || new Uint8Array(64),
|
|
585
683
|
{ gasLimit: DEFAULT_GAS_LIMIT }
|
|
586
684
|
);
|
|
587
685
|
const receipt = await tx.wait();
|
package/dist/index.mjs
CHANGED
|
@@ -366,52 +366,149 @@ var MerkleTree = class {
|
|
|
366
366
|
|
|
367
367
|
// src/zk-client.ts
|
|
368
368
|
import { keccak256 as keccak2562, toBeHex } from "ethers";
|
|
369
|
+
var wasmModule = null;
|
|
369
370
|
var ZKProofClient = class {
|
|
370
371
|
config;
|
|
372
|
+
wasmReady = false;
|
|
371
373
|
constructor(config) {
|
|
372
|
-
this.config = config ?? {};
|
|
374
|
+
this.config = config ?? { useRealProofs: true };
|
|
375
|
+
if (this.config.useRealProofs) {
|
|
376
|
+
this.loadWasm();
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
async loadWasm() {
|
|
380
|
+
if (wasmModule) {
|
|
381
|
+
this.wasmReady = true;
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
try {
|
|
385
|
+
const wasmPath = this.config.wasmPath ?? "zkenclave-circuits";
|
|
386
|
+
const module = await import(
|
|
387
|
+
/* webpackIgnore: true */
|
|
388
|
+
wasmPath
|
|
389
|
+
);
|
|
390
|
+
wasmModule = module;
|
|
391
|
+
this.wasmReady = true;
|
|
392
|
+
} catch {
|
|
393
|
+
console.warn("WASM module not available, falling back to mock proofs");
|
|
394
|
+
this.wasmReady = false;
|
|
395
|
+
}
|
|
373
396
|
}
|
|
374
397
|
async generateWithdrawalProof(request) {
|
|
398
|
+
if (this.config.useRealProofs && this.wasmReady && wasmModule) {
|
|
399
|
+
return this.generateRealProof(request);
|
|
400
|
+
}
|
|
401
|
+
return this.generateFallbackProof(request);
|
|
402
|
+
}
|
|
403
|
+
async generateRealProof(request) {
|
|
404
|
+
const wasmRequest = {
|
|
405
|
+
secret: Array.from(request.commitment),
|
|
406
|
+
nullifier_seed: Array.from(request.nullifier),
|
|
407
|
+
amount: Number(request.amount),
|
|
408
|
+
leaf_index: request.leafIndex,
|
|
409
|
+
merkle_path: request.merklePath.map((p) => Array.from(p)),
|
|
410
|
+
path_indices: request.pathIndices,
|
|
411
|
+
merkle_root: request.merkleRoot ? Array.from(request.merkleRoot) : new Array(32).fill(0),
|
|
412
|
+
recipient: this.addressToBytes(request.recipient)
|
|
413
|
+
};
|
|
414
|
+
const resultJson = wasmModule.generate_withdrawal_proof(
|
|
415
|
+
JSON.stringify(wasmRequest)
|
|
416
|
+
);
|
|
417
|
+
const result = JSON.parse(resultJson);
|
|
418
|
+
if (!result.success) {
|
|
419
|
+
throw new Error(`ZK proof generation failed: ${result.error}`);
|
|
420
|
+
}
|
|
421
|
+
return {
|
|
422
|
+
success: true,
|
|
423
|
+
zkProof: new Uint8Array(result.proof),
|
|
424
|
+
nullifierHash: new Uint8Array(result.nullifier_hash),
|
|
425
|
+
merkleRoot: request.merkleRoot ?? new Uint8Array(32),
|
|
426
|
+
timestamp: Date.now()
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
async generateFallbackProof(request) {
|
|
375
430
|
const nullifierHash = this.computeNullifierHash(
|
|
376
431
|
request.nullifier,
|
|
377
432
|
request.leafIndex
|
|
378
433
|
);
|
|
379
|
-
const zkProof = this.generateMockProof(request);
|
|
380
434
|
const merkleRoot = request.merkleRoot ?? new Uint8Array(32);
|
|
435
|
+
const proof = new Uint8Array(256);
|
|
436
|
+
proof[0] = 1;
|
|
437
|
+
const amountHex = toBeHex(request.amount, 32);
|
|
438
|
+
const amountBytes = this.hexToBytes(amountHex);
|
|
439
|
+
proof.set(amountBytes.slice(0, 32), 1);
|
|
440
|
+
proof.set(request.commitment.slice(0, 32), 33);
|
|
441
|
+
proof[250] = 90;
|
|
442
|
+
proof[251] = 75;
|
|
381
443
|
return {
|
|
382
444
|
success: true,
|
|
445
|
+
zkProof: proof,
|
|
383
446
|
nullifierHash,
|
|
384
|
-
zkProof,
|
|
385
447
|
merkleRoot,
|
|
386
448
|
timestamp: Date.now()
|
|
387
449
|
};
|
|
388
450
|
}
|
|
389
|
-
async generateComplianceProof(commitment, associationRoot) {
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
451
|
+
async generateComplianceProof(commitment, associationPath, pathIndices, associationRoot) {
|
|
452
|
+
if (this.config.useRealProofs && this.wasmReady && wasmModule) {
|
|
453
|
+
const request = {
|
|
454
|
+
commitment: Array.from(commitment),
|
|
455
|
+
association_path: associationPath.map((p) => Array.from(p)),
|
|
456
|
+
path_indices: pathIndices,
|
|
457
|
+
association_root: Array.from(associationRoot)
|
|
458
|
+
};
|
|
459
|
+
const resultJson = wasmModule.generate_compliance_proof(
|
|
460
|
+
JSON.stringify(request)
|
|
461
|
+
);
|
|
462
|
+
const result = JSON.parse(resultJson);
|
|
463
|
+
if (!result.success) {
|
|
464
|
+
throw new Error(`Compliance proof generation failed: ${result.error}`);
|
|
465
|
+
}
|
|
466
|
+
return {
|
|
467
|
+
id: keccak2562(new Uint8Array(result.proof)),
|
|
468
|
+
associationRoot,
|
|
469
|
+
timestamp: Date.now(),
|
|
470
|
+
valid: true,
|
|
471
|
+
proof: new Uint8Array(result.proof)
|
|
472
|
+
};
|
|
473
|
+
}
|
|
393
474
|
return {
|
|
394
|
-
id:
|
|
475
|
+
id: "mock-compliance-proof",
|
|
395
476
|
associationRoot,
|
|
396
477
|
timestamp: Date.now(),
|
|
397
478
|
valid: true,
|
|
398
|
-
proof: new Uint8Array(
|
|
479
|
+
proof: new Uint8Array(64).fill(1)
|
|
399
480
|
};
|
|
400
481
|
}
|
|
482
|
+
async verifyProof(proofResult) {
|
|
483
|
+
if (this.wasmReady && wasmModule) {
|
|
484
|
+
const proofJson = JSON.stringify({
|
|
485
|
+
success: proofResult.success,
|
|
486
|
+
proof: Array.from(proofResult.zkProof),
|
|
487
|
+
nullifier_hash: Array.from(proofResult.nullifierHash),
|
|
488
|
+
public_inputs: [],
|
|
489
|
+
error: null
|
|
490
|
+
});
|
|
491
|
+
return wasmModule.verify_withdrawal_proof(proofJson);
|
|
492
|
+
}
|
|
493
|
+
return proofResult.success && proofResult.zkProof.length > 0 && proofResult.zkProof[250] === 90 && proofResult.zkProof[251] === 75;
|
|
494
|
+
}
|
|
495
|
+
isWasmReady() {
|
|
496
|
+
return this.wasmReady;
|
|
497
|
+
}
|
|
401
498
|
computeNullifierHash(nullifier, leafIndex) {
|
|
402
499
|
const indexBytes = new TextEncoder().encode(leafIndex.toString());
|
|
403
500
|
const combined = new Uint8Array([...nullifier, ...indexBytes]);
|
|
404
501
|
const hash = keccak2562(combined);
|
|
405
502
|
return this.hexToBytes(hash);
|
|
406
503
|
}
|
|
407
|
-
|
|
408
|
-
const
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
return
|
|
504
|
+
addressToBytes(address) {
|
|
505
|
+
const clean = address.startsWith("0x") ? address.slice(2) : address;
|
|
506
|
+
const bytes = [];
|
|
507
|
+
for (let i = 0; i < clean.length && bytes.length < 20; i += 2) {
|
|
508
|
+
bytes.push(parseInt(clean.slice(i, i + 2), 16));
|
|
509
|
+
}
|
|
510
|
+
while (bytes.length < 20) bytes.push(0);
|
|
511
|
+
return bytes;
|
|
415
512
|
}
|
|
416
513
|
hexToBytes(hex) {
|
|
417
514
|
const cleanHex = hex.startsWith("0x") ? hex.slice(2) : hex;
|
|
@@ -433,7 +530,7 @@ var PrivacyVaultSDK = class {
|
|
|
433
530
|
zkClient;
|
|
434
531
|
config;
|
|
435
532
|
_merkleTree;
|
|
436
|
-
constructor(config, signer) {
|
|
533
|
+
constructor(config, signer, zkClient) {
|
|
437
534
|
this.config = config;
|
|
438
535
|
this.provider = new ethers.JsonRpcProvider(config.rpcUrl);
|
|
439
536
|
if (signer) {
|
|
@@ -454,7 +551,7 @@ var PrivacyVaultSDK = class {
|
|
|
454
551
|
ASP_REGISTRY_ABI,
|
|
455
552
|
this.provider
|
|
456
553
|
);
|
|
457
|
-
this.zkClient = new ZKProofClient();
|
|
554
|
+
this.zkClient = zkClient || new ZKProofClient();
|
|
458
555
|
this._merkleTree = new MerkleTree();
|
|
459
556
|
}
|
|
460
557
|
async connect(signer) {
|
|
@@ -500,7 +597,7 @@ var PrivacyVaultSDK = class {
|
|
|
500
597
|
note
|
|
501
598
|
};
|
|
502
599
|
}
|
|
503
|
-
async withdraw(note, recipient) {
|
|
600
|
+
async withdraw(note, recipient, complianceProof) {
|
|
504
601
|
if (!this.signer) {
|
|
505
602
|
throw new Error("Signer required for withdrawals");
|
|
506
603
|
}
|
|
@@ -519,7 +616,8 @@ var PrivacyVaultSDK = class {
|
|
|
519
616
|
leafIndex: note.leafIndex,
|
|
520
617
|
merkleRoot: root,
|
|
521
618
|
merklePath: [],
|
|
522
|
-
pathIndices: []
|
|
619
|
+
pathIndices: [],
|
|
620
|
+
secret: note.secret
|
|
523
621
|
});
|
|
524
622
|
const tx = await this.vault.withdraw(
|
|
525
623
|
bytesToHex(nullifierHash),
|
|
@@ -527,7 +625,7 @@ var PrivacyVaultSDK = class {
|
|
|
527
625
|
recipient,
|
|
528
626
|
note.amount,
|
|
529
627
|
zkProofResult.zkProof,
|
|
530
|
-
new Uint8Array(64),
|
|
628
|
+
complianceProof || new Uint8Array(64),
|
|
531
629
|
{ gasLimit: DEFAULT_GAS_LIMIT }
|
|
532
630
|
);
|
|
533
631
|
const receipt = await tx.wait();
|