@veil-cash/sdk 0.6.3 → 0.6.4

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,57 +1,36 @@
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 }; }
16
16
 
17
- function _interopNamespace(e) {
18
- if (e && e.__esModule) return e;
19
- var n = Object.create(null);
20
- if (e) {
21
- Object.keys(e).forEach(function (k) {
22
- if (k !== 'default') {
23
- var d = Object.getOwnPropertyDescriptor(e, k);
24
- Object.defineProperty(n, k, d.get ? d : {
25
- enumerable: true,
26
- get: function () { return e[k]; }
27
- });
28
- }
29
- });
30
- }
31
- n.default = e;
32
- return Object.freeze(n);
33
- }
34
-
35
- var crypto__namespace = /*#__PURE__*/_interopNamespace(crypto);
17
+ var ethSigUtil__default = /*#__PURE__*/_interopDefault(ethSigUtil);
18
+ var circomlib__default = /*#__PURE__*/_interopDefault(circomlib);
36
19
  var MerkleTree__default = /*#__PURE__*/_interopDefault(MerkleTree);
37
- var path__namespace = /*#__PURE__*/_interopNamespace(path);
38
- var fs__namespace = /*#__PURE__*/_interopNamespace(fs);
39
20
 
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");
47
- var poseidon = circomlib.poseidon;
21
+ // src/keypair.ts
22
+ var poseidon = circomlib__default.default.poseidon;
48
23
  var FIELD_SIZE = BigInt(
49
24
  "21888242871839275222246405745257275088548364400416034343698204186575808495617"
50
25
  );
51
26
  var poseidonHash = (items) => BigInt(poseidon(items).toString());
52
27
  var poseidonHash2 = (a, b) => poseidonHash([a, b]);
53
28
  var randomBN = (nbytes = 31) => {
54
- const bytes = crypto__namespace.randomBytes(nbytes);
29
+ const cryptoApi = globalThis.crypto;
30
+ if (!cryptoApi?.getRandomValues) {
31
+ throw new Error("Secure random number generation is unavailable in this runtime");
32
+ }
33
+ const bytes = cryptoApi.getRandomValues(new Uint8Array(nbytes));
55
34
  let hex = "0x";
56
35
  for (let i = 0; i < bytes.length; i++) {
57
36
  hex += bytes[i].toString(16).padStart(2, "0");
@@ -60,7 +39,7 @@ var randomBN = (nbytes = 31) => {
60
39
  };
61
40
  function toFixedHex(number, length = 32) {
62
41
  let hexValue;
63
- if (number instanceof Buffer) {
42
+ if (number instanceof buffer.Buffer) {
64
43
  hexValue = number.toString("hex");
65
44
  } else {
66
45
  let bigIntValue = BigInt(number);
@@ -75,11 +54,10 @@ function toFixedHex(number, length = 32) {
75
54
  var toBuffer = (value, length) => {
76
55
  const bigIntValue = BigInt(value);
77
56
  const hex = bigIntValue.toString(16).padStart(length * 2, "0");
78
- return Buffer.from(hex, "hex");
57
+ return buffer.Buffer.from(hex, "hex");
79
58
  };
80
59
  function getExtDataHash(extData) {
81
- const { ethers: ethers2 } = __require("ethers");
82
- const abi = ethers2.AbiCoder.defaultAbiCoder();
60
+ const abi = ethers.ethers.AbiCoder.defaultAbiCoder();
83
61
  const encodedData = abi.encode(
84
62
  ["tuple(address,int256,address,uint256,bytes,bytes)"],
85
63
  [[
@@ -91,7 +69,7 @@ function getExtDataHash(extData) {
91
69
  extData.encryptedOutput2
92
70
  ]]
93
71
  );
94
- const hash = ethers2.keccak256(encodedData);
72
+ const hash = ethers.ethers.keccak256(encodedData);
95
73
  return BigInt(hash) % FIELD_SIZE;
96
74
  }
97
75
  function shuffle(array) {
@@ -107,15 +85,14 @@ function shuffle(array) {
107
85
 
108
86
  // src/keypair.ts
109
87
  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
88
  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),
89
+ const nonceBuf = buffer.Buffer.from(encryptedMessage.nonce, "base64");
90
+ const ephemPublicKeyBuf = buffer.Buffer.from(encryptedMessage.ephemPublicKey, "base64");
91
+ const ciphertextBuf = buffer.Buffer.from(encryptedMessage.ciphertext, "base64");
92
+ const messageBuff = buffer.Buffer.concat([
93
+ buffer.Buffer.alloc(24 - nonceBuf.length),
117
94
  nonceBuf,
118
- Buffer.alloc(32 - ephemPublicKeyBuf.length),
95
+ buffer.Buffer.alloc(32 - ephemPublicKeyBuf.length),
119
96
  ephemPublicKeyBuf,
120
97
  ciphertextBuf
121
98
  ]);
@@ -125,7 +102,7 @@ function unpackEncryptedMessage(encryptedMessage) {
125
102
  if (encryptedMessage.slice(0, 2) === "0x") {
126
103
  encryptedMessage = encryptedMessage.slice(2);
127
104
  }
128
- const messageBuff = Buffer.from(encryptedMessage, "hex");
105
+ const messageBuff = buffer.Buffer.from(encryptedMessage, "hex");
129
106
  const nonceBuf = messageBuff.slice(0, 24);
130
107
  const ephemPublicKeyBuf = messageBuff.slice(24, 56);
131
108
  const ciphertextBuf = messageBuff.slice(56);
@@ -150,7 +127,7 @@ var Keypair = class _Keypair {
150
127
  constructor(privkey = ethers.ethers.Wallet.createRandom().privateKey) {
151
128
  this.privkey = privkey;
152
129
  this.pubkey = poseidonHash([this.privkey]);
153
- this.encryptionKey = ethSigUtil.getEncryptionPublicKey(privkey.slice(2));
130
+ this.encryptionKey = ethSigUtil__default.default.getEncryptionPublicKey(privkey.slice(2));
154
131
  }
155
132
  /**
156
133
  * Get the deposit key for this keypair
@@ -158,7 +135,7 @@ var Keypair = class _Keypair {
158
135
  * @returns Deposit key as hex string (130 chars with 0x prefix)
159
136
  */
160
137
  toString() {
161
- return toFixedHex(this.pubkey) + Buffer.from(this.encryptionKey, "base64").toString("hex");
138
+ return toFixedHex(this.pubkey) + buffer.Buffer.from(this.encryptionKey, "base64").toString("hex");
162
139
  }
163
140
  /**
164
141
  * Alias for toString() - returns the deposit key
@@ -183,7 +160,7 @@ var Keypair = class _Keypair {
183
160
  return Object.assign(new _Keypair(), {
184
161
  privkey: null,
185
162
  pubkey: BigInt("0x" + str.slice(0, 64)),
186
- encryptionKey: Buffer.from(str.slice(64, 128), "hex").toString("base64")
163
+ encryptionKey: buffer.Buffer.from(str.slice(64, 128), "hex").toString("base64")
187
164
  });
188
165
  }
189
166
  /**
@@ -268,7 +245,7 @@ var Keypair = class _Keypair {
268
245
  */
269
246
  encrypt(bytes) {
270
247
  return packEncryptedMessage(
271
- ethSigUtil.encrypt(
248
+ ethSigUtil__default.default.encrypt(
272
249
  this.encryptionKey,
273
250
  { data: bytes.toString("base64") },
274
251
  "x25519-xsalsa20-poly1305"
@@ -284,14 +261,12 @@ var Keypair = class _Keypair {
284
261
  if (!this.privkey) {
285
262
  throw new Error("Cannot decrypt without private key");
286
263
  }
287
- return Buffer.from(
288
- ethSigUtil.decrypt(unpackEncryptedMessage(data), this.privkey.slice(2)),
264
+ return buffer.Buffer.from(
265
+ ethSigUtil__default.default.decrypt(unpackEncryptedMessage(data), this.privkey.slice(2)),
289
266
  "base64"
290
267
  );
291
268
  }
292
269
  };
293
-
294
- // src/utxo.ts
295
270
  var Utxo = class _Utxo {
296
271
  amount;
297
272
  blinding;
@@ -342,7 +317,7 @@ var Utxo = class _Utxo {
342
317
  * @returns Encrypted data as 0x-prefixed hex string
343
318
  */
344
319
  encrypt() {
345
- const bytes = Buffer.concat([
320
+ const bytes = buffer.Buffer.concat([
346
321
  toBuffer(this.amount, 31),
347
322
  toBuffer(this.blinding, 31)
348
323
  ]);
@@ -1484,30 +1459,46 @@ function getMerklePath(tree, commitment) {
1484
1459
  pathIndices: index
1485
1460
  };
1486
1461
  }
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.");
1462
+ var ffUtils = ffjavascript.utils;
1463
+ function isBrowserRuntime() {
1464
+ return !(typeof process !== "undefined" && !!process.versions?.node);
1465
+ }
1466
+ function stripTrailingSlash(value) {
1467
+ return value.endsWith("/") ? value.slice(0, -1) : value;
1468
+ }
1469
+ function normalizeCircuitBasePath(provingKeyPath, circuitName) {
1470
+ const resolvedPath = typeof provingKeyPath === "function" ? provingKeyPath(circuitName) : provingKeyPath;
1471
+ const withoutExtension = resolvedPath.replace(/\.(wasm|zkey)$/i, "");
1472
+ if (withoutExtension.endsWith(`/${circuitName}`) || withoutExtension.endsWith(`\\${circuitName}`)) {
1473
+ return withoutExtension;
1474
+ }
1475
+ return `${stripTrailingSlash(withoutExtension)}/${circuitName}`;
1493
1476
  }
1494
- function findKeysDirectory() {
1477
+ function importNodeModule(specifier) {
1478
+ const dynamicImport = new Function("specifier", "return import(specifier)");
1479
+ return dynamicImport(specifier);
1480
+ }
1481
+ async function findNodeKeysDirectory() {
1482
+ const [{ existsSync }, pathModule, { fileURLToPath }] = await Promise.all([
1483
+ importNodeModule("node:fs"),
1484
+ importNodeModule("node:path"),
1485
+ importNodeModule("node:url")
1486
+ ]);
1487
+ const path = pathModule;
1495
1488
  const possiblePaths = [
1496
1489
  // When running from package (installed via npm)
1497
- path__namespace.resolve(__dirname, "..", "keys"),
1498
- path__namespace.resolve(__dirname, "..", "..", "keys"),
1490
+ path.resolve(process.cwd(), "node_modules", "@veil-cash", "sdk", "keys"),
1499
1491
  // When running from source
1500
- path__namespace.resolve(process.cwd(), "keys")
1501
- // ESM module path
1492
+ path.resolve(process.cwd(), "keys")
1502
1493
  ];
1503
1494
  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"));
1495
+ 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)));
1496
+ const currentDir = path.dirname(currentFilePath);
1497
+ possiblePaths.unshift(path.resolve(currentDir, "..", "keys"));
1507
1498
  } catch {
1508
1499
  }
1509
1500
  for (const p of possiblePaths) {
1510
- if (fs__namespace.existsSync(p) && fs__namespace.existsSync(path__namespace.join(p, "transaction2.wasm"))) {
1501
+ if (existsSync(p) && existsSync(path.join(p, "transaction2.wasm"))) {
1511
1502
  return p;
1512
1503
  }
1513
1504
  }
@@ -1515,26 +1506,48 @@ function findKeysDirectory() {
1515
1506
  "Circuit keys not found. Expected to find keys/ directory with transaction2.wasm and transaction2.zkey files."
1516
1507
  );
1517
1508
  }
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");
1509
+ async function resolveProvingKeyPaths(circuitName, provingKeyPath) {
1510
+ if (provingKeyPath) {
1511
+ const circuitBasePath = normalizeCircuitBasePath(provingKeyPath, circuitName);
1512
+ return {
1513
+ wasmPath: `${circuitBasePath}.wasm`,
1514
+ zkeyPath: `${circuitBasePath}.zkey`
1515
+ };
1516
+ }
1517
+ if (isBrowserRuntime()) {
1518
+ return {
1519
+ wasmPath: `/keys/${circuitName}.wasm`,
1520
+ zkeyPath: `/keys/${circuitName}.zkey`
1521
+ };
1522
+ }
1523
+ const keysDir = await findNodeKeysDirectory();
1524
+ return {
1525
+ wasmPath: `${keysDir}/${circuitName}.wasm`,
1526
+ zkeyPath: `${keysDir}/${circuitName}.zkey`
1527
+ };
1528
+ }
1529
+ async function assertNodeKeyFilesExist(wasmPath, zkeyPath) {
1530
+ if (isBrowserRuntime() || wasmPath.startsWith("http://") || wasmPath.startsWith("https://")) {
1531
+ return;
1521
1532
  }
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)) {
1533
+ const { existsSync } = await importNodeModule("node:fs");
1534
+ if (!existsSync(wasmPath)) {
1526
1535
  throw new Error(`Circuit WASM file not found: ${wasmPath}`);
1527
1536
  }
1528
- if (!fs__namespace.existsSync(zkeyPath)) {
1537
+ if (!existsSync(zkeyPath)) {
1529
1538
  throw new Error(`Circuit zkey file not found: ${zkeyPath}`);
1530
1539
  }
1540
+ }
1541
+ async function prove(input, circuitName, options = {}) {
1542
+ const { wasmPath, zkeyPath } = await resolveProvingKeyPaths(circuitName, options.provingKeyPath);
1543
+ await assertNodeKeyFilesExist(wasmPath, zkeyPath);
1531
1544
  const result = await snarkjs.groth16.fullProve(
1532
- utils.stringifyBigInts(input),
1545
+ ffUtils.stringifyBigInts(input),
1533
1546
  wasmPath,
1534
1547
  zkeyPath,
1535
1548
  void 0,
1536
1549
  void 0,
1537
- { singleThread: true }
1550
+ { singleThread: options.singleThread ?? true }
1538
1551
  );
1539
1552
  const proof = result.proof;
1540
1553
  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 +1575,8 @@ async function getProof({
1562
1575
  fee,
1563
1576
  recipient,
1564
1577
  relayer,
1565
- onProgress
1578
+ onProgress,
1579
+ provingKeyPath
1566
1580
  }) {
1567
1581
  inputs = shuffle([...inputs]);
1568
1582
  outputs = shuffle([...outputs]);
@@ -1622,7 +1636,7 @@ async function getProof({
1622
1636
  };
1623
1637
  onProgress?.("Generating ZK proof...", `${inputs.length} inputs`);
1624
1638
  const circuitName = selectCircuit(inputs.length);
1625
- const proof = await prove(proofInput, circuitName);
1639
+ const proof = await prove(proofInput, circuitName, { provingKeyPath });
1626
1640
  const args = {
1627
1641
  proof,
1628
1642
  root: toFixedHex(proofInput.root),
@@ -1644,7 +1658,8 @@ async function prepareTransaction({
1644
1658
  fee = 0,
1645
1659
  recipient = 0,
1646
1660
  relayer = 0,
1647
- onProgress
1661
+ onProgress,
1662
+ provingKeyPath
1648
1663
  }) {
1649
1664
  if (inputs.length > 16 || outputs.length > 2) {
1650
1665
  throw new Error("Incorrect inputs/outputs count. Maximum: 16 inputs, 2 outputs.");
@@ -1666,7 +1681,8 @@ async function prepareTransaction({
1666
1681
  fee: BigInt(fee),
1667
1682
  recipient: String(recipient),
1668
1683
  relayer: String(relayer),
1669
- onProgress
1684
+ onProgress,
1685
+ provingKeyPath
1670
1686
  });
1671
1687
  return result;
1672
1688
  }
@@ -1824,6 +1840,7 @@ async function buildWithdrawProof(options) {
1824
1840
  keypair,
1825
1841
  pool = "eth",
1826
1842
  rpcUrl,
1843
+ provingKeyPath,
1827
1844
  onProgress
1828
1845
  } = options;
1829
1846
  const poolConfig = POOL_CONFIG[pool];
@@ -1887,7 +1904,8 @@ async function buildWithdrawProof(options) {
1887
1904
  fee: 0,
1888
1905
  recipient,
1889
1906
  relayer: "0x0000000000000000000000000000000000000000",
1890
- onProgress
1907
+ onProgress,
1908
+ provingKeyPath
1891
1909
  });
1892
1910
  return {
1893
1911
  proofArgs: {
@@ -1984,6 +2002,7 @@ async function buildTransferProof(options) {
1984
2002
  senderKeypair,
1985
2003
  pool = "eth",
1986
2004
  rpcUrl,
2005
+ provingKeyPath,
1987
2006
  onProgress
1988
2007
  } = options;
1989
2008
  const poolConfig = POOL_CONFIG[pool];
@@ -2062,7 +2081,8 @@ async function buildTransferProof(options) {
2062
2081
  fee: 0,
2063
2082
  recipient: "0x0000000000000000000000000000000000000000",
2064
2083
  relayer: "0x0000000000000000000000000000000000000000",
2065
- onProgress
2084
+ onProgress,
2085
+ provingKeyPath
2066
2086
  });
2067
2087
  return {
2068
2088
  proofArgs: {
@@ -2104,7 +2124,7 @@ async function transfer(options) {
2104
2124
  };
2105
2125
  }
2106
2126
  async function mergeUtxos(options) {
2107
- const { amount, keypair, pool = "eth", rpcUrl, onProgress } = options;
2127
+ const { amount, keypair, pool = "eth", rpcUrl, provingKeyPath, onProgress } = options;
2108
2128
  const poolConfig = POOL_CONFIG[pool];
2109
2129
  const poolAddress = getPoolAddress(pool);
2110
2130
  onProgress?.("Fetching your UTXOs...");
@@ -2172,7 +2192,8 @@ async function mergeUtxos(options) {
2172
2192
  fee: 0,
2173
2193
  recipient: "0x0000000000000000000000000000000000000000",
2174
2194
  relayer: "0x0000000000000000000000000000000000000000",
2175
- onProgress
2195
+ onProgress,
2196
+ provingKeyPath
2176
2197
  });
2177
2198
  onProgress?.("Submitting to relay...");
2178
2199
  const relayResult = await submitRelay({
@@ -2584,6 +2605,7 @@ async function mergeSubaccount(options) {
2584
2605
  pool = "eth",
2585
2606
  rpcUrl,
2586
2607
  relayUrl,
2608
+ provingKeyPath,
2587
2609
  onProgress
2588
2610
  } = options;
2589
2611
  const normalizedSlot = normalizeSlot(slot);
@@ -2676,7 +2698,8 @@ async function mergeSubaccount(options) {
2676
2698
  fee: 0,
2677
2699
  recipient: "0x0000000000000000000000000000000000000000",
2678
2700
  relayer: "0x0000000000000000000000000000000000000000",
2679
- onProgress
2701
+ onProgress,
2702
+ provingKeyPath
2680
2703
  });
2681
2704
  onProgress?.("Submitting to relay...");
2682
2705
  const relayResult = await submitRelay({