@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/README.md CHANGED
@@ -288,6 +288,7 @@ Commands print human-readable success output by default. Errors are standardized
288
288
  The CLI is the main entrypoint for most users. If you are integrating Veil programmatically, use the dedicated SDK guide:
289
289
 
290
290
  - [SDK Quick Start and API Reference](./SDK.md)
291
+ - [Browser proof generation](./SDK.md#browser-proof-generation)
291
292
  - [AI agent and signer integration notes](./SDK.md#for-ai-agents)
292
293
 
293
294
  ## Deposit Flow
package/SDK.md CHANGED
@@ -182,6 +182,51 @@ const mergeResult = await mergeUtxos({
182
182
  });
183
183
  ```
184
184
 
185
+ ### Browser Proof Generation
186
+
187
+ `withdraw()`, `transfer()`, `mergeUtxos()`, `mergeSubaccount()`, `buildWithdrawProof()`,
188
+ `buildTransferProof()`, and `prepareTransaction()` can generate proofs in browser
189
+ runtimes.
190
+
191
+ In Node, the SDK uses the packaged `keys/` directory by default. In browsers,
192
+ the SDK defaults to same-origin hosted proving keys:
193
+
194
+ ```text
195
+ /keys/transaction2.wasm
196
+ /keys/transaction2.zkey
197
+ /keys/transaction16.wasm
198
+ /keys/transaction16.zkey
199
+ ```
200
+
201
+ For most web apps, copy the SDK `keys/` files into your app's public assets
202
+ directory. For example, in Next.js/Vite, serving them from `public/keys` makes
203
+ the default path work.
204
+
205
+ If you host keys elsewhere, pass `provingKeyPath`:
206
+
207
+ ```typescript
208
+ await withdraw({
209
+ amount: '0.05',
210
+ recipient: '0xRecipientAddress',
211
+ keypair,
212
+ provingKeyPath: 'https://cdn.example.com/veil-keys',
213
+ });
214
+
215
+ await transfer({
216
+ amount: '0.02',
217
+ recipientAddress: '0xRecipientAddress',
218
+ senderKeypair: keypair,
219
+ provingKeyPath: (circuitName) => `/static/zk/${circuitName}`,
220
+ });
221
+ ```
222
+
223
+ `provingKeyPath` may be a directory/base URL (`/keys`) or a resolver returning
224
+ the circuit base path without the `.wasm` / `.zkey` extension.
225
+
226
+ This removes Node `fs` key lookup from the browser proof path. Some bundlers
227
+ may still require standard Node-core polyfills for existing legacy dependencies
228
+ such as `circomlib`, `eth-sig-util`, and `fixed-merkle-tree`.
229
+
185
230
  ### Balance Queries
186
231
 
187
232
  Balance functions accept an optional `pool` parameter (`'eth'` | `'usdc'`), defaulting to `'eth'`.
@@ -8,10 +8,12 @@ var readline = require('readline');
8
8
  var fs = require('fs');
9
9
  var path = require('path');
10
10
  var ethers = require('ethers');
11
- var crypto = require('crypto');
11
+ var buffer = require('buffer');
12
+ var _ethSigUtil = require('eth-sig-util');
13
+ var _circomlib = require('circomlib');
12
14
  var MerkleTree = require('fixed-merkle-tree-legacy');
13
15
  var snarkjs = require('snarkjs');
14
- var url = require('url');
16
+ var ffjavascript = require('ffjavascript');
15
17
 
16
18
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
17
19
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
@@ -34,9 +36,8 @@ function _interopNamespace(e) {
34
36
  return Object.freeze(n);
35
37
  }
36
38
 
37
- var fs__namespace = /*#__PURE__*/_interopNamespace(fs);
38
- var path__namespace = /*#__PURE__*/_interopNamespace(path);
39
- var crypto__namespace = /*#__PURE__*/_interopNamespace(crypto);
39
+ var _ethSigUtil__namespace = /*#__PURE__*/_interopNamespace(_ethSigUtil);
40
+ var _circomlib__namespace = /*#__PURE__*/_interopNamespace(_circomlib);
40
41
  var MerkleTree__default = /*#__PURE__*/_interopDefault(MerkleTree);
41
42
 
42
43
  var __create = Object.create;
@@ -1234,8 +1235,8 @@ var require_command = __commonJS({
1234
1235
  "node_modules/commander/lib/command.js"(exports$1) {
1235
1236
  var EventEmitter = __require("events").EventEmitter;
1236
1237
  var childProcess = __require("child_process");
1237
- var path2 = __require("path");
1238
- var fs2 = __require("fs");
1238
+ var path = __require("path");
1239
+ var fs = __require("fs");
1239
1240
  var process2 = __require("process");
1240
1241
  var { Argument: Argument2, humanReadableArgName } = require_argument();
1241
1242
  var { CommanderError: CommanderError2 } = require_error();
@@ -2228,7 +2229,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
2228
2229
  * @param {string} subcommandName
2229
2230
  */
2230
2231
  _checkForMissingExecutable(executableFile, executableDir, subcommandName) {
2231
- if (fs2.existsSync(executableFile)) return;
2232
+ if (fs.existsSync(executableFile)) return;
2232
2233
  const executableDirMessage = executableDir ? `searched for local subcommand relative to directory '${executableDir}'` : "no directory for search for local subcommand, use .executableDir() to supply a custom directory";
2233
2234
  const executableMissing = `'${executableFile}' does not exist
2234
2235
  - if '${subcommandName}' is not meant to be an executable command, remove description parameter from '.command()' and use '.description()' instead
@@ -2246,11 +2247,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
2246
2247
  let launchWithNode = false;
2247
2248
  const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
2248
2249
  function findFile(baseDir, baseName) {
2249
- const localBin = path2.resolve(baseDir, baseName);
2250
- if (fs2.existsSync(localBin)) return localBin;
2251
- if (sourceExt.includes(path2.extname(baseName))) return void 0;
2250
+ const localBin = path.resolve(baseDir, baseName);
2251
+ if (fs.existsSync(localBin)) return localBin;
2252
+ if (sourceExt.includes(path.extname(baseName))) return void 0;
2252
2253
  const foundExt = sourceExt.find(
2253
- (ext) => fs2.existsSync(`${localBin}${ext}`)
2254
+ (ext) => fs.existsSync(`${localBin}${ext}`)
2254
2255
  );
2255
2256
  if (foundExt) return `${localBin}${foundExt}`;
2256
2257
  return void 0;
@@ -2262,21 +2263,21 @@ Expecting one of '${allowedValues.join("', '")}'`);
2262
2263
  if (this._scriptPath) {
2263
2264
  let resolvedScriptPath;
2264
2265
  try {
2265
- resolvedScriptPath = fs2.realpathSync(this._scriptPath);
2266
+ resolvedScriptPath = fs.realpathSync(this._scriptPath);
2266
2267
  } catch {
2267
2268
  resolvedScriptPath = this._scriptPath;
2268
2269
  }
2269
- executableDir = path2.resolve(
2270
- path2.dirname(resolvedScriptPath),
2270
+ executableDir = path.resolve(
2271
+ path.dirname(resolvedScriptPath),
2271
2272
  executableDir
2272
2273
  );
2273
2274
  }
2274
2275
  if (executableDir) {
2275
2276
  let localFile = findFile(executableDir, executableFile);
2276
2277
  if (!localFile && !subcommand._executableFile && this._scriptPath) {
2277
- const legacyName = path2.basename(
2278
+ const legacyName = path.basename(
2278
2279
  this._scriptPath,
2279
- path2.extname(this._scriptPath)
2280
+ path.extname(this._scriptPath)
2280
2281
  );
2281
2282
  if (legacyName !== this._name) {
2282
2283
  localFile = findFile(
@@ -2287,7 +2288,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
2287
2288
  }
2288
2289
  executableFile = localFile || executableFile;
2289
2290
  }
2290
- launchWithNode = sourceExt.includes(path2.extname(executableFile));
2291
+ launchWithNode = sourceExt.includes(path.extname(executableFile));
2291
2292
  let proc;
2292
2293
  if (process2.platform !== "win32") {
2293
2294
  if (launchWithNode) {
@@ -3202,7 +3203,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
3202
3203
  * @return {Command}
3203
3204
  */
3204
3205
  nameFromFilename(filename) {
3205
- this._name = path2.basename(filename, path2.extname(filename));
3206
+ this._name = path.basename(filename, path.extname(filename));
3206
3207
  return this;
3207
3208
  }
3208
3209
  /**
@@ -3216,9 +3217,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
3216
3217
  * @param {string} [path]
3217
3218
  * @return {(string|null|Command)}
3218
3219
  */
3219
- executableDir(path3) {
3220
- if (path3 === void 0) return this._executableDir;
3221
- this._executableDir = path3;
3220
+ executableDir(path2) {
3221
+ if (path2 === void 0) return this._executableDir;
3222
+ this._executableDir = path2;
3222
3223
  return this;
3223
3224
  }
3224
3225
  /**
@@ -3567,10 +3568,10 @@ var require_package = __commonJS({
3567
3568
  // node_modules/dotenv/lib/main.js
3568
3569
  var require_main = __commonJS({
3569
3570
  "node_modules/dotenv/lib/main.js"(exports$1, module) {
3570
- var fs2 = __require("fs");
3571
- var path2 = __require("path");
3571
+ var fs = __require("fs");
3572
+ var path = __require("path");
3572
3573
  var os = __require("os");
3573
- var crypto2 = __require("crypto");
3574
+ var crypto = __require("crypto");
3574
3575
  var packageJson = require_package();
3575
3576
  var version = packageJson.version;
3576
3577
  var TIPS = [
@@ -3709,7 +3710,7 @@ var require_main = __commonJS({
3709
3710
  if (options && options.path && options.path.length > 0) {
3710
3711
  if (Array.isArray(options.path)) {
3711
3712
  for (const filepath of options.path) {
3712
- if (fs2.existsSync(filepath)) {
3713
+ if (fs.existsSync(filepath)) {
3713
3714
  possibleVaultPath = filepath.endsWith(".vault") ? filepath : `${filepath}.vault`;
3714
3715
  }
3715
3716
  }
@@ -3717,15 +3718,15 @@ var require_main = __commonJS({
3717
3718
  possibleVaultPath = options.path.endsWith(".vault") ? options.path : `${options.path}.vault`;
3718
3719
  }
3719
3720
  } else {
3720
- possibleVaultPath = path2.resolve(process.cwd(), ".env.vault");
3721
+ possibleVaultPath = path.resolve(process.cwd(), ".env.vault");
3721
3722
  }
3722
- if (fs2.existsSync(possibleVaultPath)) {
3723
+ if (fs.existsSync(possibleVaultPath)) {
3723
3724
  return possibleVaultPath;
3724
3725
  }
3725
3726
  return null;
3726
3727
  }
3727
3728
  function _resolveHome(envPath) {
3728
- return envPath[0] === "~" ? path2.join(os.homedir(), envPath.slice(1)) : envPath;
3729
+ return envPath[0] === "~" ? path.join(os.homedir(), envPath.slice(1)) : envPath;
3729
3730
  }
3730
3731
  function _configVault(options) {
3731
3732
  const debug = parseBoolean(process.env.DOTENV_CONFIG_DEBUG || options && options.debug);
@@ -3742,7 +3743,7 @@ var require_main = __commonJS({
3742
3743
  return { parsed };
3743
3744
  }
3744
3745
  function configDotenv(options) {
3745
- const dotenvPath = path2.resolve(process.cwd(), ".env");
3746
+ const dotenvPath = path.resolve(process.cwd(), ".env");
3746
3747
  let encoding = "utf8";
3747
3748
  let processEnv = process.env;
3748
3749
  if (options && options.processEnv != null) {
@@ -3770,13 +3771,13 @@ var require_main = __commonJS({
3770
3771
  }
3771
3772
  let lastError;
3772
3773
  const parsedAll = {};
3773
- for (const path3 of optionPaths) {
3774
+ for (const path2 of optionPaths) {
3774
3775
  try {
3775
- const parsed = DotenvModule.parse(fs2.readFileSync(path3, { encoding }));
3776
+ const parsed = DotenvModule.parse(fs.readFileSync(path2, { encoding }));
3776
3777
  DotenvModule.populate(parsedAll, parsed, options);
3777
3778
  } catch (e) {
3778
3779
  if (debug) {
3779
- _debug(`Failed to load ${path3} ${e.message}`);
3780
+ _debug(`Failed to load ${path2} ${e.message}`);
3780
3781
  }
3781
3782
  lastError = e;
3782
3783
  }
@@ -3789,7 +3790,7 @@ var require_main = __commonJS({
3789
3790
  const shortPaths = [];
3790
3791
  for (const filePath of optionPaths) {
3791
3792
  try {
3792
- const relative = path2.relative(process.cwd(), filePath);
3793
+ const relative = path.relative(process.cwd(), filePath);
3793
3794
  shortPaths.push(relative);
3794
3795
  } catch (e) {
3795
3796
  if (debug) {
@@ -3824,7 +3825,7 @@ var require_main = __commonJS({
3824
3825
  const authTag = ciphertext.subarray(-16);
3825
3826
  ciphertext = ciphertext.subarray(12, -16);
3826
3827
  try {
3827
- const aesgcm = crypto2.createDecipheriv("aes-256-gcm", key, nonce);
3828
+ const aesgcm = crypto.createDecipheriv("aes-256-gcm", key, nonce);
3828
3829
  aesgcm.setAuthTag(authTag);
3829
3830
  return `${aesgcm.update(ciphertext)}${aesgcm.final()}`;
3830
3831
  } catch (error) {
@@ -5107,7 +5108,15 @@ function loadEnv() {
5107
5108
  } catch {
5108
5109
  }
5109
5110
  }
5110
- var circomlib = __require("circomlib");
5111
+ function resolveInterop(mod) {
5112
+ if (mod && typeof mod === "object" && "default" in mod) {
5113
+ const defaultVal = mod.default;
5114
+ if (defaultVal != null) return defaultVal;
5115
+ }
5116
+ return mod;
5117
+ }
5118
+ var ethSigUtil = resolveInterop(_ethSigUtil__namespace);
5119
+ var circomlib = resolveInterop(_circomlib__namespace);
5111
5120
  var poseidon = circomlib.poseidon;
5112
5121
  var FIELD_SIZE = BigInt(
5113
5122
  "21888242871839275222246405745257275088548364400416034343698204186575808495617"
@@ -5115,7 +5124,11 @@ var FIELD_SIZE = BigInt(
5115
5124
  var poseidonHash = (items) => BigInt(poseidon(items).toString());
5116
5125
  var poseidonHash2 = (a, b) => poseidonHash([a, b]);
5117
5126
  var randomBN = (nbytes = 31) => {
5118
- const bytes = crypto__namespace.randomBytes(nbytes);
5127
+ const cryptoApi = globalThis.crypto;
5128
+ if (!cryptoApi?.getRandomValues) {
5129
+ throw new Error("Secure random number generation is unavailable in this runtime");
5130
+ }
5131
+ const bytes = cryptoApi.getRandomValues(new Uint8Array(nbytes));
5119
5132
  let hex = "0x";
5120
5133
  for (let i = 0; i < bytes.length; i++) {
5121
5134
  hex += bytes[i].toString(16).padStart(2, "0");
@@ -5124,7 +5137,7 @@ var randomBN = (nbytes = 31) => {
5124
5137
  };
5125
5138
  function toFixedHex(number, length = 32) {
5126
5139
  let hexValue;
5127
- if (number instanceof Buffer) {
5140
+ if (number instanceof buffer.Buffer) {
5128
5141
  hexValue = number.toString("hex");
5129
5142
  } else {
5130
5143
  let bigIntValue = BigInt(number);
@@ -5139,11 +5152,10 @@ function toFixedHex(number, length = 32) {
5139
5152
  var toBuffer = (value, length) => {
5140
5153
  const bigIntValue = BigInt(value);
5141
5154
  const hex = bigIntValue.toString(16).padStart(length * 2, "0");
5142
- return Buffer.from(hex, "hex");
5155
+ return buffer.Buffer.from(hex, "hex");
5143
5156
  };
5144
5157
  function getExtDataHash(extData) {
5145
- const { ethers: ethers2 } = __require("ethers");
5146
- const abi = ethers2.AbiCoder.defaultAbiCoder();
5158
+ const abi = ethers.ethers.AbiCoder.defaultAbiCoder();
5147
5159
  const encodedData = abi.encode(
5148
5160
  ["tuple(address,int256,address,uint256,bytes,bytes)"],
5149
5161
  [[
@@ -5155,7 +5167,7 @@ function getExtDataHash(extData) {
5155
5167
  extData.encryptedOutput2
5156
5168
  ]]
5157
5169
  );
5158
- const hash = ethers2.keccak256(encodedData);
5170
+ const hash = ethers.ethers.keccak256(encodedData);
5159
5171
  return BigInt(hash) % FIELD_SIZE;
5160
5172
  }
5161
5173
  function shuffle(array) {
@@ -5171,15 +5183,14 @@ function shuffle(array) {
5171
5183
 
5172
5184
  // src/keypair.ts
5173
5185
  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.";
5174
- var ethSigUtil = __require("eth-sig-util");
5175
5186
  function packEncryptedMessage(encryptedMessage) {
5176
- const nonceBuf = Buffer.from(encryptedMessage.nonce, "base64");
5177
- const ephemPublicKeyBuf = Buffer.from(encryptedMessage.ephemPublicKey, "base64");
5178
- const ciphertextBuf = Buffer.from(encryptedMessage.ciphertext, "base64");
5179
- const messageBuff = Buffer.concat([
5180
- Buffer.alloc(24 - nonceBuf.length),
5187
+ const nonceBuf = buffer.Buffer.from(encryptedMessage.nonce, "base64");
5188
+ const ephemPublicKeyBuf = buffer.Buffer.from(encryptedMessage.ephemPublicKey, "base64");
5189
+ const ciphertextBuf = buffer.Buffer.from(encryptedMessage.ciphertext, "base64");
5190
+ const messageBuff = buffer.Buffer.concat([
5191
+ buffer.Buffer.alloc(24 - nonceBuf.length),
5181
5192
  nonceBuf,
5182
- Buffer.alloc(32 - ephemPublicKeyBuf.length),
5193
+ buffer.Buffer.alloc(32 - ephemPublicKeyBuf.length),
5183
5194
  ephemPublicKeyBuf,
5184
5195
  ciphertextBuf
5185
5196
  ]);
@@ -5189,7 +5200,7 @@ function unpackEncryptedMessage(encryptedMessage) {
5189
5200
  if (encryptedMessage.slice(0, 2) === "0x") {
5190
5201
  encryptedMessage = encryptedMessage.slice(2);
5191
5202
  }
5192
- const messageBuff = Buffer.from(encryptedMessage, "hex");
5203
+ const messageBuff = buffer.Buffer.from(encryptedMessage, "hex");
5193
5204
  const nonceBuf = messageBuff.slice(0, 24);
5194
5205
  const ephemPublicKeyBuf = messageBuff.slice(24, 56);
5195
5206
  const ciphertextBuf = messageBuff.slice(56);
@@ -5222,7 +5233,7 @@ var Keypair = class _Keypair {
5222
5233
  * @returns Deposit key as hex string (130 chars with 0x prefix)
5223
5234
  */
5224
5235
  toString() {
5225
- return toFixedHex(this.pubkey) + Buffer.from(this.encryptionKey, "base64").toString("hex");
5236
+ return toFixedHex(this.pubkey) + buffer.Buffer.from(this.encryptionKey, "base64").toString("hex");
5226
5237
  }
5227
5238
  /**
5228
5239
  * Alias for toString() - returns the deposit key
@@ -5247,7 +5258,7 @@ var Keypair = class _Keypair {
5247
5258
  return Object.assign(new _Keypair(), {
5248
5259
  privkey: null,
5249
5260
  pubkey: BigInt("0x" + str.slice(0, 64)),
5250
- encryptionKey: Buffer.from(str.slice(64, 128), "hex").toString("base64")
5261
+ encryptionKey: buffer.Buffer.from(str.slice(64, 128), "hex").toString("base64")
5251
5262
  });
5252
5263
  }
5253
5264
  /**
@@ -5348,7 +5359,7 @@ var Keypair = class _Keypair {
5348
5359
  if (!this.privkey) {
5349
5360
  throw new Error("Cannot decrypt without private key");
5350
5361
  }
5351
- return Buffer.from(
5362
+ return buffer.Buffer.from(
5352
5363
  ethSigUtil.decrypt(unpackEncryptedMessage(data), this.privkey.slice(2)),
5353
5364
  "base64"
5354
5365
  );
@@ -5423,10 +5434,10 @@ async function confirm(question) {
5423
5434
  input: process.stdin,
5424
5435
  output: process.stdout
5425
5436
  });
5426
- return new Promise((resolve2) => {
5437
+ return new Promise((resolve) => {
5427
5438
  rl.question(`${question} (y/n): `, (answer) => {
5428
5439
  rl.close();
5429
- resolve2(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
5440
+ resolve(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
5430
5441
  });
5431
5442
  });
5432
5443
  }
@@ -5792,8 +5803,6 @@ function createRegisterCommand() {
5792
5803
  });
5793
5804
  return register;
5794
5805
  }
5795
-
5796
- // src/utxo.ts
5797
5806
  var Utxo = class _Utxo {
5798
5807
  amount;
5799
5808
  blinding;
@@ -5844,7 +5853,7 @@ var Utxo = class _Utxo {
5844
5853
  * @returns Encrypted data as 0x-prefixed hex string
5845
5854
  */
5846
5855
  encrypt() {
5847
- const bytes = Buffer.concat([
5856
+ const bytes = buffer.Buffer.concat([
5848
5857
  toBuffer(this.amount, 31),
5849
5858
  toBuffer(this.blinding, 31)
5850
5859
  ]);
@@ -6533,30 +6542,46 @@ async function buildMerkleTree(commitments) {
6533
6542
  const tree = new MerkleTree__default.default(MERKLE_TREE_HEIGHT, leaves, { hashFunction });
6534
6543
  return tree;
6535
6544
  }
6536
- var utils = null;
6537
- try {
6538
- const ffjavascript = __require("ffjavascript");
6539
- utils = ffjavascript.utils;
6540
- } catch {
6541
- console.warn("ffjavascript not found. Proof generation may not work.");
6545
+ var ffUtils = ffjavascript.utils;
6546
+ function isBrowserRuntime() {
6547
+ return !(typeof process !== "undefined" && !!process.versions?.node);
6548
+ }
6549
+ function stripTrailingSlash(value) {
6550
+ return value.endsWith("/") ? value.slice(0, -1) : value;
6551
+ }
6552
+ function normalizeCircuitBasePath(provingKeyPath, circuitName) {
6553
+ const resolvedPath = typeof provingKeyPath === "function" ? provingKeyPath(circuitName) : provingKeyPath;
6554
+ const withoutExtension = resolvedPath.replace(/\.(wasm|zkey)$/i, "");
6555
+ if (withoutExtension.endsWith(`/${circuitName}`) || withoutExtension.endsWith(`\\${circuitName}`)) {
6556
+ return withoutExtension;
6557
+ }
6558
+ return `${stripTrailingSlash(withoutExtension)}/${circuitName}`;
6542
6559
  }
6543
- function findKeysDirectory() {
6560
+ function importNodeModule(specifier) {
6561
+ const dynamicImport = new Function("specifier", "return import(specifier)");
6562
+ return dynamicImport(specifier);
6563
+ }
6564
+ async function findNodeKeysDirectory() {
6565
+ const [{ existsSync: existsSync2 }, pathModule, { fileURLToPath }] = await Promise.all([
6566
+ importNodeModule("node:fs"),
6567
+ importNodeModule("node:path"),
6568
+ importNodeModule("node:url")
6569
+ ]);
6570
+ const path = pathModule;
6544
6571
  const possiblePaths = [
6545
6572
  // When running from package (installed via npm)
6546
- path__namespace.resolve(__dirname, "..", "keys"),
6547
- path__namespace.resolve(__dirname, "..", "..", "keys"),
6573
+ path.resolve(process.cwd(), "node_modules", "@veil-cash", "sdk", "keys"),
6548
6574
  // When running from source
6549
- path__namespace.resolve(process.cwd(), "keys")
6550
- // ESM module path
6575
+ path.resolve(process.cwd(), "keys")
6551
6576
  ];
6552
6577
  try {
6553
- 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)));
6554
- const currentDir = path__namespace.dirname(currentFilePath);
6555
- possiblePaths.unshift(path__namespace.resolve(currentDir, "..", "keys"));
6578
+ 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)));
6579
+ const currentDir = path.dirname(currentFilePath);
6580
+ possiblePaths.unshift(path.resolve(currentDir, "..", "keys"));
6556
6581
  } catch {
6557
6582
  }
6558
6583
  for (const p of possiblePaths) {
6559
- if (fs__namespace.existsSync(p) && fs__namespace.existsSync(path__namespace.join(p, "transaction2.wasm"))) {
6584
+ if (existsSync2(p) && existsSync2(path.join(p, "transaction2.wasm"))) {
6560
6585
  return p;
6561
6586
  }
6562
6587
  }
@@ -6564,26 +6589,48 @@ function findKeysDirectory() {
6564
6589
  "Circuit keys not found. Expected to find keys/ directory with transaction2.wasm and transaction2.zkey files."
6565
6590
  );
6566
6591
  }
6567
- async function prove(input, circuitName) {
6568
- if (!utils) {
6569
- throw new Error("ffjavascript is required for proof generation. Please install it: npm install ffjavascript");
6592
+ async function resolveProvingKeyPaths(circuitName, provingKeyPath) {
6593
+ if (provingKeyPath) {
6594
+ const circuitBasePath = normalizeCircuitBasePath(provingKeyPath, circuitName);
6595
+ return {
6596
+ wasmPath: `${circuitBasePath}.wasm`,
6597
+ zkeyPath: `${circuitBasePath}.zkey`
6598
+ };
6570
6599
  }
6571
- const keysDir = findKeysDirectory();
6572
- const wasmPath = path__namespace.join(keysDir, `${circuitName}.wasm`);
6573
- const zkeyPath = path__namespace.join(keysDir, `${circuitName}.zkey`);
6574
- if (!fs__namespace.existsSync(wasmPath)) {
6600
+ if (isBrowserRuntime()) {
6601
+ return {
6602
+ wasmPath: `/keys/${circuitName}.wasm`,
6603
+ zkeyPath: `/keys/${circuitName}.zkey`
6604
+ };
6605
+ }
6606
+ const keysDir = await findNodeKeysDirectory();
6607
+ return {
6608
+ wasmPath: `${keysDir}/${circuitName}.wasm`,
6609
+ zkeyPath: `${keysDir}/${circuitName}.zkey`
6610
+ };
6611
+ }
6612
+ async function assertNodeKeyFilesExist(wasmPath, zkeyPath) {
6613
+ if (isBrowserRuntime() || wasmPath.startsWith("http://") || wasmPath.startsWith("https://")) {
6614
+ return;
6615
+ }
6616
+ const { existsSync: existsSync2 } = await importNodeModule("node:fs");
6617
+ if (!existsSync2(wasmPath)) {
6575
6618
  throw new Error(`Circuit WASM file not found: ${wasmPath}`);
6576
6619
  }
6577
- if (!fs__namespace.existsSync(zkeyPath)) {
6620
+ if (!existsSync2(zkeyPath)) {
6578
6621
  throw new Error(`Circuit zkey file not found: ${zkeyPath}`);
6579
6622
  }
6623
+ }
6624
+ async function prove(input, circuitName, options = {}) {
6625
+ const { wasmPath, zkeyPath } = await resolveProvingKeyPaths(circuitName, options.provingKeyPath);
6626
+ await assertNodeKeyFilesExist(wasmPath, zkeyPath);
6580
6627
  const result = await snarkjs.groth16.fullProve(
6581
- utils.stringifyBigInts(input),
6628
+ ffUtils.stringifyBigInts(input),
6582
6629
  wasmPath,
6583
6630
  zkeyPath,
6584
6631
  void 0,
6585
6632
  void 0,
6586
- { singleThread: true }
6633
+ { singleThread: options.singleThread ?? true }
6587
6634
  );
6588
6635
  const proof = result.proof;
6589
6636
  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);
@@ -6607,7 +6654,8 @@ async function getProof({
6607
6654
  fee,
6608
6655
  recipient,
6609
6656
  relayer,
6610
- onProgress
6657
+ onProgress,
6658
+ provingKeyPath
6611
6659
  }) {
6612
6660
  inputs = shuffle([...inputs]);
6613
6661
  outputs = shuffle([...outputs]);
@@ -6667,7 +6715,7 @@ async function getProof({
6667
6715
  };
6668
6716
  onProgress?.("Generating ZK proof...", `${inputs.length} inputs`);
6669
6717
  const circuitName = selectCircuit(inputs.length);
6670
- const proof = await prove(proofInput, circuitName);
6718
+ const proof = await prove(proofInput, circuitName, { provingKeyPath });
6671
6719
  const args = {
6672
6720
  proof,
6673
6721
  root: toFixedHex(proofInput.root),
@@ -6689,7 +6737,8 @@ async function prepareTransaction({
6689
6737
  fee = 0,
6690
6738
  recipient = 0,
6691
6739
  relayer = 0,
6692
- onProgress
6740
+ onProgress,
6741
+ provingKeyPath
6693
6742
  }) {
6694
6743
  if (inputs.length > 16 || outputs.length > 2) {
6695
6744
  throw new Error("Incorrect inputs/outputs count. Maximum: 16 inputs, 2 outputs.");
@@ -6711,7 +6760,8 @@ async function prepareTransaction({
6711
6760
  fee: BigInt(fee),
6712
6761
  recipient: String(recipient),
6713
6762
  relayer: String(relayer),
6714
- onProgress
6763
+ onProgress,
6764
+ provingKeyPath
6715
6765
  });
6716
6766
  return result;
6717
6767
  }
@@ -6861,6 +6911,7 @@ async function buildWithdrawProof(options) {
6861
6911
  keypair,
6862
6912
  pool = "eth",
6863
6913
  rpcUrl,
6914
+ provingKeyPath,
6864
6915
  onProgress
6865
6916
  } = options;
6866
6917
  const poolConfig = POOL_CONFIG[pool];
@@ -6924,7 +6975,8 @@ async function buildWithdrawProof(options) {
6924
6975
  fee: 0,
6925
6976
  recipient,
6926
6977
  relayer: "0x0000000000000000000000000000000000000000",
6927
- onProgress
6978
+ onProgress,
6979
+ provingKeyPath
6928
6980
  });
6929
6981
  return {
6930
6982
  proofArgs: {
@@ -7085,6 +7137,7 @@ async function buildTransferProof(options) {
7085
7137
  senderKeypair,
7086
7138
  pool = "eth",
7087
7139
  rpcUrl,
7140
+ provingKeyPath,
7088
7141
  onProgress
7089
7142
  } = options;
7090
7143
  const poolConfig = POOL_CONFIG[pool];
@@ -7163,7 +7216,8 @@ async function buildTransferProof(options) {
7163
7216
  fee: 0,
7164
7217
  recipient: "0x0000000000000000000000000000000000000000",
7165
7218
  relayer: "0x0000000000000000000000000000000000000000",
7166
- onProgress
7219
+ onProgress,
7220
+ provingKeyPath
7167
7221
  });
7168
7222
  return {
7169
7223
  proofArgs: {
@@ -7205,7 +7259,7 @@ async function transfer(options) {
7205
7259
  };
7206
7260
  }
7207
7261
  async function mergeUtxos(options) {
7208
- const { amount, keypair, pool = "eth", rpcUrl, onProgress } = options;
7262
+ const { amount, keypair, pool = "eth", rpcUrl, provingKeyPath, onProgress } = options;
7209
7263
  const poolConfig = POOL_CONFIG[pool];
7210
7264
  const poolAddress = getPoolAddress(pool);
7211
7265
  onProgress?.("Fetching your UTXOs...");
@@ -7273,7 +7327,8 @@ async function mergeUtxos(options) {
7273
7327
  fee: 0,
7274
7328
  recipient: "0x0000000000000000000000000000000000000000",
7275
7329
  relayer: "0x0000000000000000000000000000000000000000",
7276
- onProgress
7330
+ onProgress,
7331
+ provingKeyPath
7277
7332
  });
7278
7333
  onProgress?.("Submitting to relay...");
7279
7334
  const relayResult = await submitRelay({
@@ -7964,6 +8019,7 @@ async function mergeSubaccount(options) {
7964
8019
  pool = "eth",
7965
8020
  rpcUrl,
7966
8021
  relayUrl,
8022
+ provingKeyPath,
7967
8023
  onProgress
7968
8024
  } = options;
7969
8025
  const normalizedSlot = normalizeSlot(slot);
@@ -8056,7 +8112,8 @@ async function mergeSubaccount(options) {
8056
8112
  fee: 0,
8057
8113
  recipient: "0x0000000000000000000000000000000000000000",
8058
8114
  relayer: "0x0000000000000000000000000000000000000000",
8059
- onProgress
8115
+ onProgress,
8116
+ provingKeyPath
8060
8117
  });
8061
8118
  onProgress?.("Submitting to relay...");
8062
8119
  const relayResult = await submitRelay({