@veil-cash/sdk 0.6.3 → 0.6.5

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.cjs CHANGED
@@ -1,15 +1,15 @@
1
1
  'use strict';
2
2
 
3
3
  var ethers = require('ethers');
4
+ var buffer = require('buffer');
4
5
  var accounts = require('viem/accounts');
5
- var crypto = require('crypto');
6
+ var _ethSigUtil = require('eth-sig-util');
7
+ var _circomlib = require('circomlib');
6
8
  var viem = require('viem');
7
9
  var chains = require('viem/chains');
8
10
  var MerkleTree = require('fixed-merkle-tree-legacy');
9
11
  var snarkjs = require('snarkjs');
10
- var path = require('path');
11
- var fs = require('fs');
12
- var url = require('url');
12
+ var ffjavascript = require('ffjavascript');
13
13
 
14
14
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
15
15
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
@@ -32,18 +32,20 @@ function _interopNamespace(e) {
32
32
  return Object.freeze(n);
33
33
  }
34
34
 
35
- var crypto__namespace = /*#__PURE__*/_interopNamespace(crypto);
35
+ var _ethSigUtil__namespace = /*#__PURE__*/_interopNamespace(_ethSigUtil);
36
+ var _circomlib__namespace = /*#__PURE__*/_interopNamespace(_circomlib);
36
37
  var MerkleTree__default = /*#__PURE__*/_interopDefault(MerkleTree);
37
- var path__namespace = /*#__PURE__*/_interopNamespace(path);
38
- var fs__namespace = /*#__PURE__*/_interopNamespace(fs);
39
38
 
40
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
41
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
42
- }) : x)(function(x) {
43
- if (typeof require !== "undefined") return require.apply(this, arguments);
44
- throw Error('Dynamic require of "' + x + '" is not supported');
45
- });
46
- var circomlib = __require("circomlib");
39
+ // src/keypair.ts
40
+ function resolveInterop(mod) {
41
+ if (mod && typeof mod === "object" && "default" in mod) {
42
+ const defaultVal = mod.default;
43
+ if (defaultVal != null) return defaultVal;
44
+ }
45
+ return mod;
46
+ }
47
+ var ethSigUtil = resolveInterop(_ethSigUtil__namespace);
48
+ var circomlib = resolveInterop(_circomlib__namespace);
47
49
  var poseidon = circomlib.poseidon;
48
50
  var FIELD_SIZE = BigInt(
49
51
  "21888242871839275222246405745257275088548364400416034343698204186575808495617"
@@ -51,7 +53,11 @@ var FIELD_SIZE = BigInt(
51
53
  var poseidonHash = (items) => BigInt(poseidon(items).toString());
52
54
  var poseidonHash2 = (a, b) => poseidonHash([a, b]);
53
55
  var randomBN = (nbytes = 31) => {
54
- const bytes = crypto__namespace.randomBytes(nbytes);
56
+ const cryptoApi = globalThis.crypto;
57
+ if (!cryptoApi?.getRandomValues) {
58
+ throw new Error("Secure random number generation is unavailable in this runtime");
59
+ }
60
+ const bytes = cryptoApi.getRandomValues(new Uint8Array(nbytes));
55
61
  let hex = "0x";
56
62
  for (let i = 0; i < bytes.length; i++) {
57
63
  hex += bytes[i].toString(16).padStart(2, "0");
@@ -60,7 +66,7 @@ var randomBN = (nbytes = 31) => {
60
66
  };
61
67
  function toFixedHex(number, length = 32) {
62
68
  let hexValue;
63
- if (number instanceof Buffer) {
69
+ if (number instanceof buffer.Buffer) {
64
70
  hexValue = number.toString("hex");
65
71
  } else {
66
72
  let bigIntValue = BigInt(number);
@@ -75,11 +81,10 @@ function toFixedHex(number, length = 32) {
75
81
  var toBuffer = (value, length) => {
76
82
  const bigIntValue = BigInt(value);
77
83
  const hex = bigIntValue.toString(16).padStart(length * 2, "0");
78
- return Buffer.from(hex, "hex");
84
+ return buffer.Buffer.from(hex, "hex");
79
85
  };
80
86
  function getExtDataHash(extData) {
81
- const { ethers: ethers2 } = __require("ethers");
82
- const abi = ethers2.AbiCoder.defaultAbiCoder();
87
+ const abi = ethers.ethers.AbiCoder.defaultAbiCoder();
83
88
  const encodedData = abi.encode(
84
89
  ["tuple(address,int256,address,uint256,bytes,bytes)"],
85
90
  [[
@@ -91,7 +96,7 @@ function getExtDataHash(extData) {
91
96
  extData.encryptedOutput2
92
97
  ]]
93
98
  );
94
- const hash = ethers2.keccak256(encodedData);
99
+ const hash = ethers.ethers.keccak256(encodedData);
95
100
  return BigInt(hash) % FIELD_SIZE;
96
101
  }
97
102
  function shuffle(array) {
@@ -107,15 +112,14 @@ function shuffle(array) {
107
112
 
108
113
  // src/keypair.ts
109
114
  var VEIL_SIGNED_MESSAGE = "Sign this message to create your Veil Wallet private key. This will be used to decrypt your balances. Ensure you are signing this message on the Veil Cash website.";
110
- var ethSigUtil = __require("eth-sig-util");
111
115
  function packEncryptedMessage(encryptedMessage) {
112
- const nonceBuf = Buffer.from(encryptedMessage.nonce, "base64");
113
- const ephemPublicKeyBuf = Buffer.from(encryptedMessage.ephemPublicKey, "base64");
114
- const ciphertextBuf = Buffer.from(encryptedMessage.ciphertext, "base64");
115
- const messageBuff = Buffer.concat([
116
- Buffer.alloc(24 - nonceBuf.length),
116
+ const nonceBuf = buffer.Buffer.from(encryptedMessage.nonce, "base64");
117
+ const ephemPublicKeyBuf = buffer.Buffer.from(encryptedMessage.ephemPublicKey, "base64");
118
+ const ciphertextBuf = buffer.Buffer.from(encryptedMessage.ciphertext, "base64");
119
+ const messageBuff = buffer.Buffer.concat([
120
+ buffer.Buffer.alloc(24 - nonceBuf.length),
117
121
  nonceBuf,
118
- Buffer.alloc(32 - ephemPublicKeyBuf.length),
122
+ buffer.Buffer.alloc(32 - ephemPublicKeyBuf.length),
119
123
  ephemPublicKeyBuf,
120
124
  ciphertextBuf
121
125
  ]);
@@ -125,7 +129,7 @@ function unpackEncryptedMessage(encryptedMessage) {
125
129
  if (encryptedMessage.slice(0, 2) === "0x") {
126
130
  encryptedMessage = encryptedMessage.slice(2);
127
131
  }
128
- const messageBuff = Buffer.from(encryptedMessage, "hex");
132
+ const messageBuff = buffer.Buffer.from(encryptedMessage, "hex");
129
133
  const nonceBuf = messageBuff.slice(0, 24);
130
134
  const ephemPublicKeyBuf = messageBuff.slice(24, 56);
131
135
  const ciphertextBuf = messageBuff.slice(56);
@@ -158,7 +162,7 @@ var Keypair = class _Keypair {
158
162
  * @returns Deposit key as hex string (130 chars with 0x prefix)
159
163
  */
160
164
  toString() {
161
- return toFixedHex(this.pubkey) + Buffer.from(this.encryptionKey, "base64").toString("hex");
165
+ return toFixedHex(this.pubkey) + buffer.Buffer.from(this.encryptionKey, "base64").toString("hex");
162
166
  }
163
167
  /**
164
168
  * Alias for toString() - returns the deposit key
@@ -183,7 +187,7 @@ var Keypair = class _Keypair {
183
187
  return Object.assign(new _Keypair(), {
184
188
  privkey: null,
185
189
  pubkey: BigInt("0x" + str.slice(0, 64)),
186
- encryptionKey: Buffer.from(str.slice(64, 128), "hex").toString("base64")
190
+ encryptionKey: buffer.Buffer.from(str.slice(64, 128), "hex").toString("base64")
187
191
  });
188
192
  }
189
193
  /**
@@ -284,14 +288,12 @@ var Keypair = class _Keypair {
284
288
  if (!this.privkey) {
285
289
  throw new Error("Cannot decrypt without private key");
286
290
  }
287
- return Buffer.from(
291
+ return buffer.Buffer.from(
288
292
  ethSigUtil.decrypt(unpackEncryptedMessage(data), this.privkey.slice(2)),
289
293
  "base64"
290
294
  );
291
295
  }
292
296
  };
293
-
294
- // src/utxo.ts
295
297
  var Utxo = class _Utxo {
296
298
  amount;
297
299
  blinding;
@@ -342,7 +344,7 @@ var Utxo = class _Utxo {
342
344
  * @returns Encrypted data as 0x-prefixed hex string
343
345
  */
344
346
  encrypt() {
345
- const bytes = Buffer.concat([
347
+ const bytes = buffer.Buffer.concat([
346
348
  toBuffer(this.amount, 31),
347
349
  toBuffer(this.blinding, 31)
348
350
  ]);
@@ -1484,30 +1486,46 @@ function getMerklePath(tree, commitment) {
1484
1486
  pathIndices: index
1485
1487
  };
1486
1488
  }
1487
- var utils = null;
1488
- try {
1489
- const ffjavascript = __require("ffjavascript");
1490
- utils = ffjavascript.utils;
1491
- } catch {
1492
- console.warn("ffjavascript not found. Proof generation may not work.");
1489
+ var ffUtils = ffjavascript.utils;
1490
+ function isBrowserRuntime() {
1491
+ return !(typeof process !== "undefined" && !!process.versions?.node);
1492
+ }
1493
+ function stripTrailingSlash(value) {
1494
+ return value.endsWith("/") ? value.slice(0, -1) : value;
1493
1495
  }
1494
- function findKeysDirectory() {
1496
+ function normalizeCircuitBasePath(provingKeyPath, circuitName) {
1497
+ const resolvedPath = typeof provingKeyPath === "function" ? provingKeyPath(circuitName) : provingKeyPath;
1498
+ const withoutExtension = resolvedPath.replace(/\.(wasm|zkey)$/i, "");
1499
+ if (withoutExtension.endsWith(`/${circuitName}`) || withoutExtension.endsWith(`\\${circuitName}`)) {
1500
+ return withoutExtension;
1501
+ }
1502
+ return `${stripTrailingSlash(withoutExtension)}/${circuitName}`;
1503
+ }
1504
+ function importNodeModule(specifier) {
1505
+ const dynamicImport = new Function("specifier", "return import(specifier)");
1506
+ return dynamicImport(specifier);
1507
+ }
1508
+ async function findNodeKeysDirectory() {
1509
+ const [{ existsSync }, pathModule, { fileURLToPath }] = await Promise.all([
1510
+ importNodeModule("node:fs"),
1511
+ importNodeModule("node:path"),
1512
+ importNodeModule("node:url")
1513
+ ]);
1514
+ const path = pathModule;
1495
1515
  const possiblePaths = [
1496
1516
  // When running from package (installed via npm)
1497
- path__namespace.resolve(__dirname, "..", "keys"),
1498
- path__namespace.resolve(__dirname, "..", "..", "keys"),
1517
+ path.resolve(process.cwd(), "node_modules", "@veil-cash", "sdk", "keys"),
1499
1518
  // When running from source
1500
- path__namespace.resolve(process.cwd(), "keys")
1501
- // ESM module path
1519
+ path.resolve(process.cwd(), "keys")
1502
1520
  ];
1503
1521
  try {
1504
- const currentFilePath = url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
1505
- const currentDir = path__namespace.dirname(currentFilePath);
1506
- possiblePaths.unshift(path__namespace.resolve(currentDir, "..", "keys"));
1522
+ const currentFilePath = fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
1523
+ const currentDir = path.dirname(currentFilePath);
1524
+ possiblePaths.unshift(path.resolve(currentDir, "..", "keys"));
1507
1525
  } catch {
1508
1526
  }
1509
1527
  for (const p of possiblePaths) {
1510
- if (fs__namespace.existsSync(p) && fs__namespace.existsSync(path__namespace.join(p, "transaction2.wasm"))) {
1528
+ if (existsSync(p) && existsSync(path.join(p, "transaction2.wasm"))) {
1511
1529
  return p;
1512
1530
  }
1513
1531
  }
@@ -1515,26 +1533,48 @@ function findKeysDirectory() {
1515
1533
  "Circuit keys not found. Expected to find keys/ directory with transaction2.wasm and transaction2.zkey files."
1516
1534
  );
1517
1535
  }
1518
- async function prove(input, circuitName) {
1519
- if (!utils) {
1520
- throw new Error("ffjavascript is required for proof generation. Please install it: npm install ffjavascript");
1536
+ async function resolveProvingKeyPaths(circuitName, provingKeyPath) {
1537
+ if (provingKeyPath) {
1538
+ const circuitBasePath = normalizeCircuitBasePath(provingKeyPath, circuitName);
1539
+ return {
1540
+ wasmPath: `${circuitBasePath}.wasm`,
1541
+ zkeyPath: `${circuitBasePath}.zkey`
1542
+ };
1521
1543
  }
1522
- const keysDir = findKeysDirectory();
1523
- const wasmPath = path__namespace.join(keysDir, `${circuitName}.wasm`);
1524
- const zkeyPath = path__namespace.join(keysDir, `${circuitName}.zkey`);
1525
- if (!fs__namespace.existsSync(wasmPath)) {
1544
+ if (isBrowserRuntime()) {
1545
+ return {
1546
+ wasmPath: `/keys/${circuitName}.wasm`,
1547
+ zkeyPath: `/keys/${circuitName}.zkey`
1548
+ };
1549
+ }
1550
+ const keysDir = await findNodeKeysDirectory();
1551
+ return {
1552
+ wasmPath: `${keysDir}/${circuitName}.wasm`,
1553
+ zkeyPath: `${keysDir}/${circuitName}.zkey`
1554
+ };
1555
+ }
1556
+ async function assertNodeKeyFilesExist(wasmPath, zkeyPath) {
1557
+ if (isBrowserRuntime() || wasmPath.startsWith("http://") || wasmPath.startsWith("https://")) {
1558
+ return;
1559
+ }
1560
+ const { existsSync } = await importNodeModule("node:fs");
1561
+ if (!existsSync(wasmPath)) {
1526
1562
  throw new Error(`Circuit WASM file not found: ${wasmPath}`);
1527
1563
  }
1528
- if (!fs__namespace.existsSync(zkeyPath)) {
1564
+ if (!existsSync(zkeyPath)) {
1529
1565
  throw new Error(`Circuit zkey file not found: ${zkeyPath}`);
1530
1566
  }
1567
+ }
1568
+ async function prove(input, circuitName, options = {}) {
1569
+ const { wasmPath, zkeyPath } = await resolveProvingKeyPaths(circuitName, options.provingKeyPath);
1570
+ await assertNodeKeyFilesExist(wasmPath, zkeyPath);
1531
1571
  const result = await snarkjs.groth16.fullProve(
1532
- utils.stringifyBigInts(input),
1572
+ ffUtils.stringifyBigInts(input),
1533
1573
  wasmPath,
1534
1574
  zkeyPath,
1535
1575
  void 0,
1536
1576
  void 0,
1537
- { singleThread: true }
1577
+ { singleThread: options.singleThread ?? true }
1538
1578
  );
1539
1579
  const proof = result.proof;
1540
1580
  return "0x" + toFixedHex(proof.pi_a[0]).slice(2) + toFixedHex(proof.pi_a[1]).slice(2) + toFixedHex(proof.pi_b[0][1]).slice(2) + toFixedHex(proof.pi_b[0][0]).slice(2) + toFixedHex(proof.pi_b[1][1]).slice(2) + toFixedHex(proof.pi_b[1][0]).slice(2) + toFixedHex(proof.pi_c[0]).slice(2) + toFixedHex(proof.pi_c[1]).slice(2);
@@ -1562,7 +1602,8 @@ async function getProof({
1562
1602
  fee,
1563
1603
  recipient,
1564
1604
  relayer,
1565
- onProgress
1605
+ onProgress,
1606
+ provingKeyPath
1566
1607
  }) {
1567
1608
  inputs = shuffle([...inputs]);
1568
1609
  outputs = shuffle([...outputs]);
@@ -1622,7 +1663,7 @@ async function getProof({
1622
1663
  };
1623
1664
  onProgress?.("Generating ZK proof...", `${inputs.length} inputs`);
1624
1665
  const circuitName = selectCircuit(inputs.length);
1625
- const proof = await prove(proofInput, circuitName);
1666
+ const proof = await prove(proofInput, circuitName, { provingKeyPath });
1626
1667
  const args = {
1627
1668
  proof,
1628
1669
  root: toFixedHex(proofInput.root),
@@ -1644,7 +1685,8 @@ async function prepareTransaction({
1644
1685
  fee = 0,
1645
1686
  recipient = 0,
1646
1687
  relayer = 0,
1647
- onProgress
1688
+ onProgress,
1689
+ provingKeyPath
1648
1690
  }) {
1649
1691
  if (inputs.length > 16 || outputs.length > 2) {
1650
1692
  throw new Error("Incorrect inputs/outputs count. Maximum: 16 inputs, 2 outputs.");
@@ -1666,7 +1708,8 @@ async function prepareTransaction({
1666
1708
  fee: BigInt(fee),
1667
1709
  recipient: String(recipient),
1668
1710
  relayer: String(relayer),
1669
- onProgress
1711
+ onProgress,
1712
+ provingKeyPath
1670
1713
  });
1671
1714
  return result;
1672
1715
  }
@@ -1824,6 +1867,7 @@ async function buildWithdrawProof(options) {
1824
1867
  keypair,
1825
1868
  pool = "eth",
1826
1869
  rpcUrl,
1870
+ provingKeyPath,
1827
1871
  onProgress
1828
1872
  } = options;
1829
1873
  const poolConfig = POOL_CONFIG[pool];
@@ -1887,7 +1931,8 @@ async function buildWithdrawProof(options) {
1887
1931
  fee: 0,
1888
1932
  recipient,
1889
1933
  relayer: "0x0000000000000000000000000000000000000000",
1890
- onProgress
1934
+ onProgress,
1935
+ provingKeyPath
1891
1936
  });
1892
1937
  return {
1893
1938
  proofArgs: {
@@ -1984,6 +2029,7 @@ async function buildTransferProof(options) {
1984
2029
  senderKeypair,
1985
2030
  pool = "eth",
1986
2031
  rpcUrl,
2032
+ provingKeyPath,
1987
2033
  onProgress
1988
2034
  } = options;
1989
2035
  const poolConfig = POOL_CONFIG[pool];
@@ -2062,7 +2108,8 @@ async function buildTransferProof(options) {
2062
2108
  fee: 0,
2063
2109
  recipient: "0x0000000000000000000000000000000000000000",
2064
2110
  relayer: "0x0000000000000000000000000000000000000000",
2065
- onProgress
2111
+ onProgress,
2112
+ provingKeyPath
2066
2113
  });
2067
2114
  return {
2068
2115
  proofArgs: {
@@ -2104,7 +2151,7 @@ async function transfer(options) {
2104
2151
  };
2105
2152
  }
2106
2153
  async function mergeUtxos(options) {
2107
- const { amount, keypair, pool = "eth", rpcUrl, onProgress } = options;
2154
+ const { amount, keypair, pool = "eth", rpcUrl, provingKeyPath, onProgress } = options;
2108
2155
  const poolConfig = POOL_CONFIG[pool];
2109
2156
  const poolAddress = getPoolAddress(pool);
2110
2157
  onProgress?.("Fetching your UTXOs...");
@@ -2172,7 +2219,8 @@ async function mergeUtxos(options) {
2172
2219
  fee: 0,
2173
2220
  recipient: "0x0000000000000000000000000000000000000000",
2174
2221
  relayer: "0x0000000000000000000000000000000000000000",
2175
- onProgress
2222
+ onProgress,
2223
+ provingKeyPath
2176
2224
  });
2177
2225
  onProgress?.("Submitting to relay...");
2178
2226
  const relayResult = await submitRelay({
@@ -2584,6 +2632,7 @@ async function mergeSubaccount(options) {
2584
2632
  pool = "eth",
2585
2633
  rpcUrl,
2586
2634
  relayUrl,
2635
+ provingKeyPath,
2587
2636
  onProgress
2588
2637
  } = options;
2589
2638
  const normalizedSlot = normalizeSlot(slot);
@@ -2676,7 +2725,8 @@ async function mergeSubaccount(options) {
2676
2725
  fee: 0,
2677
2726
  recipient: "0x0000000000000000000000000000000000000000",
2678
2727
  relayer: "0x0000000000000000000000000000000000000000",
2679
- onProgress
2728
+ onProgress,
2729
+ provingKeyPath
2680
2730
  });
2681
2731
  onProgress?.("Submitting to relay...");
2682
2732
  const relayResult = await submitRelay({