@auditable/privacy-pool-zk-sdk 0.0.2-rc.8 → 0.1.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/dist/cli.js CHANGED
@@ -6,95 +6,1044 @@ var snarkjs = require('snarkjs');
6
6
 
7
7
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
8
8
  function _interopNamespaceDefault(e) {
9
- var n = Object.create(null);
10
- if (e) {
11
- Object.keys(e).forEach(function (k) {
12
- if (k !== 'default') {
13
- var d = Object.getOwnPropertyDescriptor(e, k);
14
- Object.defineProperty(n, k, d.get ? d : {
15
- enumerable: true,
16
- get: function () { return e[k]; }
17
- });
18
- }
19
- });
20
- }
21
- n.default = e;
22
- return Object.freeze(n);
9
+ var n = Object.create(null);
10
+ if (e) {
11
+ Object.keys(e).forEach(function (k) {
12
+ if (k !== 'default') {
13
+ var d = Object.getOwnPropertyDescriptor(e, k);
14
+ Object.defineProperty(n, k, d.get ? d : {
15
+ enumerable: true,
16
+ get: function () { return e[k]; }
17
+ });
18
+ }
19
+ });
20
+ }
21
+ n.default = e;
22
+ return Object.freeze(n);
23
23
  }
24
24
 
25
25
  var fs__namespace = /*#__PURE__*/_interopNamespaceDefault(fs);
26
26
  var snarkjs__namespace = /*#__PURE__*/_interopNamespaceDefault(snarkjs);
27
27
 
28
- let wasm;
28
+ function getDefaultExportFromCjs (x) {
29
+ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
30
+ }
29
31
 
30
- const heap = new Array(128).fill(undefined);
32
+ var dist = {};
31
33
 
32
- heap.push(undefined, null, true, false);
34
+ Object.defineProperty(dist, "__esModule", { value: true });
35
+ dist.bech32m = bech32 = dist.bech32 = void 0;
36
+ const ALPHABET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l';
37
+ const ALPHABET_MAP = {};
38
+ for (let z = 0; z < ALPHABET.length; z++) {
39
+ const x = ALPHABET.charAt(z);
40
+ ALPHABET_MAP[x] = z;
41
+ }
42
+ function polymodStep(pre) {
43
+ const b = pre >> 25;
44
+ return (((pre & 0x1ffffff) << 5) ^
45
+ (-((b >> 0) & 1) & 0x3b6a57b2) ^
46
+ (-((b >> 1) & 1) & 0x26508e6d) ^
47
+ (-((b >> 2) & 1) & 0x1ea119fa) ^
48
+ (-((b >> 3) & 1) & 0x3d4233dd) ^
49
+ (-((b >> 4) & 1) & 0x2a1462b3));
50
+ }
51
+ function prefixChk(prefix) {
52
+ let chk = 1;
53
+ for (let i = 0; i < prefix.length; ++i) {
54
+ const c = prefix.charCodeAt(i);
55
+ if (c < 33 || c > 126)
56
+ return 'Invalid prefix (' + prefix + ')';
57
+ chk = polymodStep(chk) ^ (c >> 5);
58
+ }
59
+ chk = polymodStep(chk);
60
+ for (let i = 0; i < prefix.length; ++i) {
61
+ const v = prefix.charCodeAt(i);
62
+ chk = polymodStep(chk) ^ (v & 0x1f);
63
+ }
64
+ return chk;
65
+ }
66
+ function convert(data, inBits, outBits, pad) {
67
+ let value = 0;
68
+ let bits = 0;
69
+ const maxV = (1 << outBits) - 1;
70
+ const result = [];
71
+ for (let i = 0; i < data.length; ++i) {
72
+ value = (value << inBits) | data[i];
73
+ bits += inBits;
74
+ while (bits >= outBits) {
75
+ bits -= outBits;
76
+ result.push((value >> bits) & maxV);
77
+ }
78
+ }
79
+ if (pad) {
80
+ if (bits > 0) {
81
+ result.push((value << (outBits - bits)) & maxV);
82
+ }
83
+ }
84
+ else {
85
+ if (bits >= inBits)
86
+ return 'Excess padding';
87
+ if ((value << (outBits - bits)) & maxV)
88
+ return 'Non-zero padding';
89
+ }
90
+ return result;
91
+ }
92
+ function toWords(bytes) {
93
+ return convert(bytes, 8, 5, true);
94
+ }
95
+ function fromWordsUnsafe(words) {
96
+ const res = convert(words, 5, 8, false);
97
+ if (Array.isArray(res))
98
+ return res;
99
+ }
100
+ function fromWords(words) {
101
+ const res = convert(words, 5, 8, false);
102
+ if (Array.isArray(res))
103
+ return res;
104
+ throw new Error(res);
105
+ }
106
+ function getLibraryFromEncoding(encoding) {
107
+ let ENCODING_CONST;
108
+ if (encoding === 'bech32') {
109
+ ENCODING_CONST = 1;
110
+ }
111
+ else {
112
+ ENCODING_CONST = 0x2bc830a3;
113
+ }
114
+ function encode(prefix, words, LIMIT) {
115
+ LIMIT = LIMIT || 90;
116
+ if (prefix.length + 7 + words.length > LIMIT)
117
+ throw new TypeError('Exceeds length limit');
118
+ prefix = prefix.toLowerCase();
119
+ // determine chk mod
120
+ let chk = prefixChk(prefix);
121
+ if (typeof chk === 'string')
122
+ throw new Error(chk);
123
+ let result = prefix + '1';
124
+ for (let i = 0; i < words.length; ++i) {
125
+ const x = words[i];
126
+ if (x >> 5 !== 0)
127
+ throw new Error('Non 5-bit word');
128
+ chk = polymodStep(chk) ^ x;
129
+ result += ALPHABET.charAt(x);
130
+ }
131
+ for (let i = 0; i < 6; ++i) {
132
+ chk = polymodStep(chk);
133
+ }
134
+ chk ^= ENCODING_CONST;
135
+ for (let i = 0; i < 6; ++i) {
136
+ const v = (chk >> ((5 - i) * 5)) & 0x1f;
137
+ result += ALPHABET.charAt(v);
138
+ }
139
+ return result;
140
+ }
141
+ function __decode(str, LIMIT) {
142
+ LIMIT = LIMIT || 90;
143
+ if (str.length < 8)
144
+ return str + ' too short';
145
+ if (str.length > LIMIT)
146
+ return 'Exceeds length limit';
147
+ // don't allow mixed case
148
+ const lowered = str.toLowerCase();
149
+ const uppered = str.toUpperCase();
150
+ if (str !== lowered && str !== uppered)
151
+ return 'Mixed-case string ' + str;
152
+ str = lowered;
153
+ const split = str.lastIndexOf('1');
154
+ if (split === -1)
155
+ return 'No separator character for ' + str;
156
+ if (split === 0)
157
+ return 'Missing prefix for ' + str;
158
+ const prefix = str.slice(0, split);
159
+ const wordChars = str.slice(split + 1);
160
+ if (wordChars.length < 6)
161
+ return 'Data too short';
162
+ let chk = prefixChk(prefix);
163
+ if (typeof chk === 'string')
164
+ return chk;
165
+ const words = [];
166
+ for (let i = 0; i < wordChars.length; ++i) {
167
+ const c = wordChars.charAt(i);
168
+ const v = ALPHABET_MAP[c];
169
+ if (v === undefined)
170
+ return 'Unknown character ' + c;
171
+ chk = polymodStep(chk) ^ v;
172
+ // not in the checksum?
173
+ if (i + 6 >= wordChars.length)
174
+ continue;
175
+ words.push(v);
176
+ }
177
+ if (chk !== ENCODING_CONST)
178
+ return 'Invalid checksum for ' + str;
179
+ return { prefix, words };
180
+ }
181
+ function decodeUnsafe(str, LIMIT) {
182
+ const res = __decode(str, LIMIT);
183
+ if (typeof res === 'object')
184
+ return res;
185
+ }
186
+ function decode(str, LIMIT) {
187
+ const res = __decode(str, LIMIT);
188
+ if (typeof res === 'object')
189
+ return res;
190
+ throw new Error(res);
191
+ }
192
+ return {
193
+ decodeUnsafe,
194
+ decode,
195
+ encode,
196
+ toWords,
197
+ fromWordsUnsafe,
198
+ fromWords,
199
+ };
200
+ }
201
+ var bech32 = dist.bech32 = getLibraryFromEncoding('bech32');
202
+ dist.bech32m = getLibraryFromEncoding('bech32m');
203
+
204
+ const STEALTH_ADDRESS_HRP = 'stpl1';
205
+ /** BIP-173 default 90 is too small for 64-byte payload (32+32 field coords) after 8→5 bit conversion. */
206
+ const BECH32_STEALTH_LIMIT = 1023;
207
+ function normalizeHex$2(hex) {
208
+ const s = hex.trim().replace(/^0x/i, '');
209
+ if (!/^[0-9a-fA-F]*$/.test(s)) {
210
+ throw new Error('stealth-address: hex must contain only 0-9, a-f');
211
+ }
212
+ return s.length % 2 === 0 ? s : `0${s}`;
213
+ }
214
+ function hexToBytes$2(hex) {
215
+ const norm = normalizeHex$2(hex);
216
+ const out = new Uint8Array(norm.length / 2);
217
+ for (let i = 0; i < out.length; i++) {
218
+ out[i] = parseInt(norm.slice(i * 2, i * 2 + 2), 16);
219
+ }
220
+ return out;
221
+ }
222
+ function bytesToHex$1(bytes) {
223
+ let s = '';
224
+ for (let i = 0; i < bytes.length; i++) {
225
+ s += bytes[i].toString(16).padStart(2, '0');
226
+ }
227
+ return s;
228
+ }
229
+ function concatBytes(a, b) {
230
+ const out = new Uint8Array(a.length + b.length);
231
+ out.set(a, 0);
232
+ out.set(b, a.length);
233
+ return out;
234
+ }
235
+ /**
236
+ * Encodes `x || y` as Bech32 (BIP-173) with human-readable part {@link STEALTH_ADDRESS_HRP} (`stpl1`).
237
+ * `x` and `y` must have the same byte length so decoding can split the payload in half.
238
+ */
239
+ function encodeStealthAddress(decoded) {
240
+ const xb = hexToBytes$2(decoded.x);
241
+ const yb = hexToBytes$2(decoded.y);
242
+ if (xb.length !== yb.length) {
243
+ throw new Error('stealth-address: x and y must encode the same number of bytes for a reversible address');
244
+ }
245
+ const payload = concatBytes(xb, yb);
246
+ const words = bech32.toWords(payload);
247
+ return bech32.encode(STEALTH_ADDRESS_HRP, words, BECH32_STEALTH_LIMIT);
248
+ }
249
+ /**
250
+ * Decodes a `stpl1` Bech32 stealth address into `x` and `y` (each half of the payload, as lowercase hex).
251
+ */
252
+ function decodeStealthAddress(address) {
253
+ const { prefix, words } = bech32.decode(address, BECH32_STEALTH_LIMIT);
254
+ if (prefix !== STEALTH_ADDRESS_HRP) {
255
+ throw new Error(`stealth-address: expected HRP ${STEALTH_ADDRESS_HRP}, got ${JSON.stringify(prefix)}`);
256
+ }
257
+ const bytes = new Uint8Array(bech32.fromWords(words));
258
+ if (bytes.length === 0 || bytes.length % 2 !== 0) {
259
+ throw new Error('stealth-address: payload length must be positive and even');
260
+ }
261
+ const mid = bytes.length / 2;
262
+ return {
263
+ x: bytesToHex$1(bytes.subarray(0, mid)),
264
+ y: bytesToHex$1(bytes.subarray(mid)),
265
+ };
266
+ }
33
267
 
34
- function getObject(idx) { return heap[idx]; }
268
+ /** Default nonce when deriving the wallet sign-in message. */
269
+ const DEFAULT_STEALTH_SIGN_NONCE = 'main address';
270
+ /**
271
+ * Plaintext for Stellar wallet message signing (stealth address derivation).
272
+ * Sign the exact bytes of this string (UTF-8) with the stellar account key.
273
+ */
274
+ function buildStealthAddressSignMessage(address, nonce = DEFAULT_STEALTH_SIGN_NONCE) {
275
+ return `Privacy layer app needs you to sign the message for stealth address derivation with address:\n${address}\n and nonce:\n${nonce}.\n\n This will not authorize any transaction.`;
276
+ }
35
277
 
36
- let heap_next = heap.length;
278
+ /** Bech32 HRP for {@link DecodedEphemeralKey} only (`x ‖ y`, 64 bytes). */
279
+ const DECODED_EPHEMERAL_HRP = 'epk1';
280
+ /** Bech32 HRP for {@link DecodedDepositorSharedSecretPreimage} (96 bytes). */
281
+ const DEPOSITOR_SHARED_SECRET_PREIMAGE_HRP = 'epk_dep_pre1';
282
+ const FIELD_BYTES = 32;
283
+ const EPK_POINT_PAYLOAD = FIELD_BYTES * 2;
284
+ const EPK_DEP_PRE_PAYLOAD = FIELD_BYTES * 3;
285
+ const BECH32_LONG_LIMIT = 1023;
286
+ function normalizeHex$1(hex) {
287
+ const s = hex.trim().replace(/^0x/i, '');
288
+ if (!/^[0-9a-fA-F]*$/.test(s)) {
289
+ throw new Error('ephemeral-key: hex must contain only 0-9, a-f');
290
+ }
291
+ return s.length % 2 === 0 ? s : `0${s}`;
292
+ }
293
+ function hexToBytes$1(hex) {
294
+ const norm = normalizeHex$1(hex);
295
+ const out = new Uint8Array(norm.length / 2);
296
+ for (let i = 0; i < out.length; i++) {
297
+ out[i] = parseInt(norm.slice(i * 2, i * 2 + 2), 16);
298
+ }
299
+ return out;
300
+ }
301
+ function bytesToHex(bytes) {
302
+ let s = '';
303
+ for (let i = 0; i < bytes.length; i++) {
304
+ s += bytes[i].toString(16).padStart(2, '0');
305
+ }
306
+ return s;
307
+ }
308
+ function concat2(a, b) {
309
+ const out = new Uint8Array(a.length + b.length);
310
+ out.set(a, 0);
311
+ out.set(b, a.length);
312
+ return out;
313
+ }
314
+ function concat3(a, b, c) {
315
+ const out = new Uint8Array(a.length + b.length + c.length);
316
+ out.set(a, 0);
317
+ out.set(b, a.length);
318
+ out.set(c, a.length + b.length);
319
+ return out;
320
+ }
321
+ function require32(label, bytes) {
322
+ if (bytes.length !== FIELD_BYTES) {
323
+ throw new Error(`ephemeral-key: ${label} must encode exactly ${FIELD_BYTES} bytes, got ${bytes.length}`);
324
+ }
325
+ }
326
+ /**
327
+ * 32-byte big-endian integer as hex (64 chars), **< 2^253**, so BabyJub ECDH matches
328
+ * `circuits/encryption.circom` `Num2Bits(253)` and `libs/cryptography` `scalar_mul_253`.
329
+ */
330
+ function generateRandomScalarHex32() {
331
+ const g = globalThis.crypto;
332
+ if (!g?.getRandomValues) {
333
+ throw new Error('ephemeral-key: crypto.getRandomValues is required');
334
+ }
335
+ const max = 1n << 253n;
336
+ for (let attempt = 0; attempt < 65536; attempt++) {
337
+ const b = new Uint8Array(32);
338
+ g.getRandomValues(b);
339
+ const hex = bytesToHex(b);
340
+ if (BigInt(`0x${hex}`) < max) {
341
+ return hex;
342
+ }
343
+ }
344
+ throw new Error('ephemeral-key: failed to sample scalar < 2^253');
345
+ }
346
+ /** Bech32 `epk1`: encodes `x ‖ y` (64 bytes). */
347
+ function encodeDecodedEphemeralKey(decoded) {
348
+ const xb = hexToBytes$1(decoded.x);
349
+ const yb = hexToBytes$1(decoded.y);
350
+ require32('x', xb);
351
+ require32('y', yb);
352
+ const payload = concat2(xb, yb);
353
+ const words = bech32.toWords(payload);
354
+ return bech32.encode(DECODED_EPHEMERAL_HRP, words, BECH32_LONG_LIMIT);
355
+ }
356
+ function decodeDecodedEphemeralKey(encoded) {
357
+ const { prefix, words } = bech32.decode(encoded, BECH32_LONG_LIMIT);
358
+ if (prefix !== DECODED_EPHEMERAL_HRP) {
359
+ throw new Error(`ephemeral-key: expected HRP ${DECODED_EPHEMERAL_HRP}, got ${JSON.stringify(prefix)}`);
360
+ }
361
+ const bytes = new Uint8Array(bech32.fromWords(words));
362
+ if (bytes.length !== EPK_POINT_PAYLOAD) {
363
+ throw new Error(`ephemeral-key: epk1 payload must be ${EPK_POINT_PAYLOAD} bytes, got ${bytes.length}`);
364
+ }
365
+ return {
366
+ x: bytesToHex(bytes.subarray(0, FIELD_BYTES)),
367
+ y: bytesToHex(bytes.subarray(FIELD_BYTES)),
368
+ };
369
+ }
370
+ /** Bech32 `epk_dep_pre1`: `randomNonceScalar ‖ recipient.x ‖ recipient.y`. */
371
+ function encodeDepositorSharedSecretPreimage(decoded) {
372
+ const sb = hexToBytes$1(decoded.randomNonceScalar);
373
+ const xb = hexToBytes$1(decoded.recipientStealthAddress.x);
374
+ const yb = hexToBytes$1(decoded.recipientStealthAddress.y);
375
+ require32('randomNonceScalar', sb);
376
+ require32('recipientStealthAddress.x', xb);
377
+ require32('recipientStealthAddress.y', yb);
378
+ const payload = concat3(sb, xb, yb);
379
+ const words = bech32.toWords(payload);
380
+ return bech32.encode(DEPOSITOR_SHARED_SECRET_PREIMAGE_HRP, words, BECH32_LONG_LIMIT);
381
+ }
382
+ function decodeDepositorSharedSecretPreimage(encoded) {
383
+ const { prefix, words } = bech32.decode(encoded, BECH32_LONG_LIMIT);
384
+ if (prefix !== DEPOSITOR_SHARED_SECRET_PREIMAGE_HRP) {
385
+ throw new Error(`ephemeral-key: expected HRP ${DEPOSITOR_SHARED_SECRET_PREIMAGE_HRP}, got ${JSON.stringify(prefix)}`);
386
+ }
387
+ const bytes = new Uint8Array(bech32.fromWords(words));
388
+ if (bytes.length !== EPK_DEP_PRE_PAYLOAD) {
389
+ throw new Error(`ephemeral-key: epk_dep_pre1 payload must be ${EPK_DEP_PRE_PAYLOAD} bytes, got ${bytes.length}`);
390
+ }
391
+ return {
392
+ randomNonceScalar: bytesToHex(bytes.subarray(0, FIELD_BYTES)),
393
+ recipientStealthAddress: {
394
+ x: bytesToHex(bytes.subarray(FIELD_BYTES, FIELD_BYTES * 2)),
395
+ y: bytesToHex(bytes.subarray(FIELD_BYTES * 2)),
396
+ },
397
+ };
398
+ }
37
399
 
38
- function addHeapObject(obj) {
39
- if (heap_next === heap.length) heap.push(heap.length + 1);
40
- const idx = heap_next;
41
- heap_next = heap[idx];
400
+ /** Matches `Transaction(20, 2, 2)` in `circuits/main.circom`. */
401
+ const TRANSACTION_TREE_DEPTH = 20;
402
+ /** BN254 scalar field modulus (ark `Fr`, circom signals). */
403
+ const BN254_SCALAR_MOD = 21888242871839275222246405745257275088548364400416034343698204186575808495617n;
404
+ /**
405
+ * BabyJub ECDH in `circuits/encryption.circom` uses `Num2Bits(253)`; scalars must be < 2^253
406
+ * (matches `libs/cryptography` `scalar_mul_253`).
407
+ */
408
+ const BN254_BABYJUB_SCALAR_MAX_EXCLUSIVE = 1n << 253n;
409
+ function normalizeHex(hex) {
410
+ const s = hex.trim().replace(/^0x/i, '');
411
+ if (!/^[0-9a-fA-F]*$/.test(s)) {
412
+ throw new Error('withdrawal-transaction-input: invalid hex');
413
+ }
414
+ return s.length % 2 === 0 ? s : `0${s}`;
415
+ }
416
+ /** 32-byte field coordinate (hex, no 0x) → decimal string mod BN254 scalar field. */
417
+ function coordHexToDecimal(hex) {
418
+ const h = normalizeHex(hex);
419
+ if (h.length > 64) {
420
+ throw new Error('withdrawal-transaction-input: coordinate hex too long');
421
+ }
422
+ const v = BigInt(`0x${h}`);
423
+ return (v % BN254_SCALAR_MOD).toString(10);
424
+ }
425
+ /**
426
+ * 32-byte big-endian scalar hex → decimal for circom `ephemeralKeyScalar` / ECDH `priv`.
427
+ * Integer must be < 2^253 (not reduced mod r — values ≥ 2^253 are rejected).
428
+ */
429
+ function scalarHexToFrDecimal(hex) {
430
+ const h = normalizeHex(hex);
431
+ if (h.length > 64) {
432
+ throw new Error('withdrawal-transaction-input: scalar hex too long');
433
+ }
434
+ const v = BigInt(`0x${h.padStart(64, '0').slice(-64)}`);
435
+ if (v >= BN254_BABYJUB_SCALAR_MAX_EXCLUSIVE) {
436
+ throw new Error('depositor ephemeral scalar must be < 2^253 (BabyJub Num2Bits); resample with random-scalar');
437
+ }
438
+ return v.toString(10);
439
+ }
440
+ /**
441
+ * Stellar G-address Ed25519 payload (32 bytes as 64 hex, optional 0x) → two circom public decimals
442
+ * (`withdrawAddressHi` / `withdrawAddressLo`). No mod-r; each half fits in 128 bits.
443
+ */
444
+ function ed25519PubkeyPayloadHexToWithdrawFrDecimals(hex) {
445
+ const h = normalizeHex(hex).padStart(64, '0').slice(-64);
446
+ const hi = BigInt(`0x${h.slice(0, 32)}`);
447
+ const lo = BigInt(`0x${h.slice(32, 64)}`);
448
+ return { hi: hi.toString(10), lo: lo.toString(10) };
449
+ }
450
+ /** Uniform random `Fr` as decimal (32 random bytes, mod r). For Poseidon-only inputs (e.g. nullifiers). */
451
+ function randomFrDecimal() {
452
+ const hex = generateRandomScalarHex32();
453
+ const v = BigInt(`0x${normalizeHex(hex)}`);
454
+ return (v % BN254_SCALAR_MOD).toString(10);
455
+ }
456
+ /** Random scalar < 2^253 for BabyJub ECDH / `Num2Bits(253)` (uses {@link generateRandomScalarHex32}). */
457
+ function randomFrDecimal253() {
458
+ const hex = generateRandomScalarHex32();
459
+ return BigInt(`0x${normalizeHex(hex)}`).toString(10);
460
+ }
461
+ function zerosTreeSiblings() {
462
+ return Array(TRANSACTION_TREE_DEPTH).fill('0');
463
+ }
464
+ function dummyWithdraw(wasm) {
465
+ const nullifier = randomFrDecimal();
466
+ const secretHex = generateRandomScalarHex32();
467
+ const secret = (BigInt(`0x${normalizeHex(secretHex)}`) % BN254_SCALAR_MOD).toString(10);
468
+ const pt = wasm.ecdhEphemeralPublicKeyFromScalarHex(secretHex);
469
+ return {
470
+ value: '0',
471
+ nullifier,
472
+ secret,
473
+ ephemeralKeys: [coordHexToDecimal(pt.x), coordHexToDecimal(pt.y)],
474
+ stateSiblings: zerosTreeSiblings(),
475
+ stateIndex: '0',
476
+ };
477
+ }
478
+ function dummyDeposit(wasm) {
479
+ const nullifier = randomFrDecimal();
480
+ const ephemeralKeyScalar = randomFrDecimal253();
481
+ const skHex = generateRandomScalarHex32();
482
+ const pt = wasm.ecdhEphemeralPublicKeyFromScalarHex(skHex);
483
+ return {
484
+ value: '0',
485
+ nullifier,
486
+ ephemeralKeyScalar,
487
+ recipientPublicKeys: [coordHexToDecimal(pt.x), coordHexToDecimal(pt.y)],
488
+ };
489
+ }
490
+ function resolveWithdraw(slot, wasm) {
491
+ return slot === 'dummy' ? dummyWithdraw(wasm) : slot;
492
+ }
493
+ function resolveDeposit(slot, wasm) {
494
+ return slot === 'dummy' ? dummyDeposit(wasm) : slot;
495
+ }
496
+ function buildTransactionWitnessInput(publicParams, withdrawSlots, depositSlots, wasm) {
497
+ const w0 = resolveWithdraw(withdrawSlots[0], wasm);
498
+ const w1 = resolveWithdraw(withdrawSlots[1], wasm);
499
+ const d0 = resolveDeposit(depositSlots[0], wasm);
500
+ const d1 = resolveDeposit(depositSlots[1], wasm);
501
+ return {
502
+ stateRoot: publicParams.stateRoot,
503
+ withdrawAddressHi: publicParams.withdrawAddressHi,
504
+ withdrawAddressLo: publicParams.withdrawAddressLo,
505
+ privKeyScalar: publicParams.privKeyScalar,
506
+ withdrawnValues: [w0.value, w1.value],
507
+ withdrawnNullifiers: [w0.nullifier, w1.nullifier],
508
+ withdrawnSecrets: [w0.secret, w1.secret],
509
+ ephemeralKeys: [w0.ephemeralKeys, w1.ephemeralKeys],
510
+ stateSiblings: [w0.stateSiblings, w1.stateSiblings],
511
+ stateIndex: [w0.stateIndex, w1.stateIndex],
512
+ depositedValues: [d0.value, d1.value],
513
+ depositedNullifiers: [d0.nullifier, d1.nullifier],
514
+ depositedEphemeralKeyScalars: [d0.ephemeralKeyScalar, d1.ephemeralKeyScalar],
515
+ depositedRecipientPublicKeys: [d0.recipientPublicKeys, d1.recipientPublicKeys],
516
+ };
517
+ }
518
+ /** `stpl1…` stealth address → `[x, y]` as decimal field strings for `depositedRecipientPublicKeys`. */
519
+ function recipientPublicKeysDecimalFromStealthAddress(stealthAddress) {
520
+ const { x, y } = decodeStealthAddress(stealthAddress);
521
+ return [coordHexToDecimal(x), coordHexToDecimal(y)];
522
+ }
523
+ /** First withdraw leg: Merkle witness + depositor ECDH point coordinates (hex). */
524
+ function withdrawObjectFromMerkleWitness(witness, depositorEphemeralHex) {
525
+ return {
526
+ value: witness.value,
527
+ nullifier: witness.nullifier,
528
+ secret: witness.secret,
529
+ ephemeralKeys: [
530
+ coordHexToDecimal(depositorEphemeralHex.x),
531
+ coordHexToDecimal(depositorEphemeralHex.y),
532
+ ],
533
+ stateSiblings: witness.stateSiblings,
534
+ stateIndex: witness.stateIndex,
535
+ };
536
+ }
42
537
 
43
- heap[idx] = obj;
44
- return idx;
538
+ function hexToBytes(hex) {
539
+ const out = new Uint8Array(hex.length / 2);
540
+ for (let i = 0; i < out.length; i++) {
541
+ out[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
542
+ }
543
+ return out;
544
+ }
545
+ function bytesToHexLower(bytes) {
546
+ let s = '';
547
+ for (let i = 0; i < bytes.length; i++) {
548
+ s += bytes[i].toString(16).padStart(2, '0');
549
+ }
550
+ return s;
551
+ }
552
+ /** Base64 → bytes via `atob` (browsers; Node 16+). No Node `Buffer`. */
553
+ function decodeBase64ToBytes(s) {
554
+ const t = s.replace(/\s/g, '');
555
+ if (typeof atob !== 'function') {
556
+ throw new Error('Base64 decoding requires atob (browser or Node 16+)');
557
+ }
558
+ try {
559
+ const binary = atob(t);
560
+ const out = new Uint8Array(binary.length);
561
+ for (let i = 0; i < binary.length; i++) {
562
+ out[i] = binary.charCodeAt(i);
563
+ }
564
+ return out;
565
+ }
566
+ catch {
567
+ throw new Error('Invalid base64 signature');
568
+ }
569
+ }
570
+ /**
571
+ * Ed25519 signature as **128 hex chars** (optional `0x`) or **base64** (typically 88 chars for 64 bytes, whitespace ignored).
572
+ */
573
+ function parseStellarEd25519SignatureRaw(input) {
574
+ const trimmed = input.trim();
575
+ const no0x = trimmed.replace(/^0x/i, '');
576
+ if (/^[0-9a-fA-F]+$/.test(no0x) && no0x.length === 128) {
577
+ return hexToBytes(no0x.toLowerCase());
578
+ }
579
+ const fromB64 = decodeBase64ToBytes(trimmed);
580
+ if (fromB64.length !== 64) {
581
+ throw new Error(`Decoded signature must be 64 bytes (Ed25519); got ${fromB64.length} from base64`);
582
+ }
583
+ return fromB64;
584
+ }
585
+ /** SHA-256 via Web Crypto only (`crypto.subtle`) — works in browsers and Node 19+ (global `crypto`). */
586
+ async function sha256(data) {
587
+ const subtle = globalThis.crypto?.subtle;
588
+ if (!subtle) {
589
+ throw new Error('SHA-256 requires crypto.subtle (HTTPS or localhost in browsers, or Node.js 19+).');
590
+ }
591
+ const copy = new Uint8Array(data.length);
592
+ copy.set(data);
593
+ return new Uint8Array(await subtle.digest('SHA-256', copy));
594
+ }
595
+ /**
596
+ * Stellar Ed25519 signature (hex or base64) → SHA-256(signature bytes) → scalar → WASM ECDH (no UTF-8 seed hash).
597
+ */
598
+ async function stealthAddressFromStellarSignature(ecdhFromScalarHex, encodeStealth, signature) {
599
+ const raw = parseStellarEd25519SignatureRaw(signature);
600
+ const scalar = await sha256(raw);
601
+ const scalarHex = bytesToHexLower(scalar);
602
+ const decoded = ecdhFromScalarHex(scalarHex);
603
+ return encodeStealth(decoded);
604
+ }
605
+ /**
606
+ * SHA-256(signature) as 32-byte BE integer, truncated to **253 bits** (same effective scalar as
607
+ * `libs/cryptography` `scalar_mul_253` / circom `Num2Bits(253)`), decimal for `privKeyScalar`.
608
+ */
609
+ async function privKeyScalarDecimalFromStellarSignature(signature) {
610
+ const raw = parseStellarEd25519SignatureRaw(signature);
611
+ const h = await sha256(raw);
612
+ let v = 0n;
613
+ for (let i = 0; i < h.length; i++) {
614
+ v = (v << 8n) + BigInt(h[i]);
615
+ }
616
+ const mask = BN254_BABYJUB_SCALAR_MAX_EXCLUSIVE - 1n;
617
+ return (v & mask).toString(10);
45
618
  }
46
619
 
47
- function handleError(f, args) {
620
+ /* @ts-self-types="./client_sdk_wasm.d.ts" */
621
+
622
+ /**
623
+ * Merkle root, path, and coin field strings for the first withdraw leg (JSON → JSON).
624
+ * @param {string} coin_json
625
+ * @param {string} state_json
626
+ * @returns {string}
627
+ */
628
+ function buildWithdrawMerkleWitness(coin_json, state_json) {
629
+ let deferred4_0;
630
+ let deferred4_1;
48
631
  try {
49
- return f.apply(this, args);
50
- } catch (e) {
51
- wasm.__wbindgen_export_0(addHeapObject(e));
632
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
633
+ const ptr0 = passStringToWasm0(coin_json, wasm.__wbindgen_export, wasm.__wbindgen_export2);
634
+ const len0 = WASM_VECTOR_LEN;
635
+ const ptr1 = passStringToWasm0(state_json, wasm.__wbindgen_export, wasm.__wbindgen_export2);
636
+ const len1 = WASM_VECTOR_LEN;
637
+ wasm.buildWithdrawMerkleWitness(retptr, ptr0, len0, ptr1, len1);
638
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
639
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
640
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
641
+ var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
642
+ var ptr3 = r0;
643
+ var len3 = r1;
644
+ if (r3) {
645
+ ptr3 = 0; len3 = 0;
646
+ throw takeObject(r2);
647
+ }
648
+ deferred4_0 = ptr3;
649
+ deferred4_1 = len3;
650
+ return getStringFromWasm0(ptr3, len3);
651
+ } finally {
652
+ wasm.__wbindgen_add_to_stack_pointer(16);
653
+ wasm.__wbindgen_export4(deferred4_0, deferred4_1, 1);
52
654
  }
53
655
  }
54
656
 
55
- let cachedUint8ArrayMemory0 = null;
657
+ /**
658
+ * Calculate nullifier hash from nullifier decimal string.
659
+ * Returns hex string (0x...)
660
+ * @param {string} nullifier_decimal
661
+ * @returns {string}
662
+ */
663
+ function calculateNullifierHash(nullifier_decimal) {
664
+ let deferred3_0;
665
+ let deferred3_1;
666
+ try {
667
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
668
+ const ptr0 = passStringToWasm0(nullifier_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
669
+ const len0 = WASM_VECTOR_LEN;
670
+ wasm.calculateNullifierHash(retptr, ptr0, len0);
671
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
672
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
673
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
674
+ var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
675
+ var ptr2 = r0;
676
+ var len2 = r1;
677
+ if (r3) {
678
+ ptr2 = 0; len2 = 0;
679
+ throw takeObject(r2);
680
+ }
681
+ deferred3_0 = ptr2;
682
+ deferred3_1 = len2;
683
+ return getStringFromWasm0(ptr2, len2);
684
+ } finally {
685
+ wasm.__wbindgen_add_to_stack_pointer(16);
686
+ wasm.__wbindgen_export4(deferred3_0, deferred3_1, 1);
687
+ }
688
+ }
56
689
 
57
- function getUint8ArrayMemory0() {
58
- if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
59
- cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
690
+ /**
691
+ * UTF-8 seed `SHA256` scalar → BabyJubJub `BASE8 * r` (circom `ECDHEphemeralKey`).
692
+ * `x` and `y` are lowercase hex (no `0x`). Bech32 / stealth string: TypeScript `encodeStealthAddress`.
693
+ * @param {string} seed
694
+ * @returns {any}
695
+ */
696
+ function ecdhEphemeralPublicKey(seed) {
697
+ try {
698
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
699
+ const ptr0 = passStringToWasm0(seed, wasm.__wbindgen_export, wasm.__wbindgen_export2);
700
+ const len0 = WASM_VECTOR_LEN;
701
+ wasm.ecdhEphemeralPublicKey(retptr, ptr0, len0);
702
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
703
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
704
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
705
+ if (r2) {
706
+ throw takeObject(r1);
707
+ }
708
+ return takeObject(r0);
709
+ } finally {
710
+ wasm.__wbindgen_add_to_stack_pointer(16);
60
711
  }
61
- return cachedUint8ArrayMemory0;
62
712
  }
63
713
 
64
- let cachedTextDecoder = (typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }) : { decode: () => { throw Error('TextDecoder not available') } } );
714
+ /**
715
+ * 32-byte scalar as 64 hex chars (optional `0x`) → `ecdh_ephemeral_public_key` (no UTF-8 seed hash).
716
+ * @param {string} scalar_hex
717
+ * @returns {any}
718
+ */
719
+ function ecdhEphemeralPublicKeyFromScalarHex(scalar_hex) {
720
+ try {
721
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
722
+ const ptr0 = passStringToWasm0(scalar_hex, wasm.__wbindgen_export, wasm.__wbindgen_export2);
723
+ const len0 = WASM_VECTOR_LEN;
724
+ wasm.ecdhEphemeralPublicKeyFromScalarHex(retptr, ptr0, len0);
725
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
726
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
727
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
728
+ if (r2) {
729
+ throw takeObject(r1);
730
+ }
731
+ return takeObject(r0);
732
+ } finally {
733
+ wasm.__wbindgen_add_to_stack_pointer(16);
734
+ }
735
+ }
65
736
 
66
- if (typeof TextDecoder !== 'undefined') { cachedTextDecoder.decode(); }
67
- const MAX_SAFARI_DECODE_BYTES = 2146435072;
68
- let numBytesDecoded = 0;
69
- function decodeText(ptr, len) {
70
- numBytesDecoded += len;
71
- if (numBytesDecoded >= MAX_SAFARI_DECODE_BYTES) {
72
- cachedTextDecoder = (typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }) : { decode: () => { throw Error('TextDecoder not available') } } );
73
- cachedTextDecoder.decode();
74
- numBytesDecoded = len;
737
+ /**
738
+ * Circuit `ECDH`: `priv * (pub_x, pub_y)` → shared key (`key[0], key[1]` hex).
739
+ * @param {string} priv_hex
740
+ * @param {string} pub_x_hex
741
+ * @param {string} pub_y_hex
742
+ * @returns {any}
743
+ */
744
+ function ecdhSharedKey(priv_hex, pub_x_hex, pub_y_hex) {
745
+ try {
746
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
747
+ const ptr0 = passStringToWasm0(priv_hex, wasm.__wbindgen_export, wasm.__wbindgen_export2);
748
+ const len0 = WASM_VECTOR_LEN;
749
+ const ptr1 = passStringToWasm0(pub_x_hex, wasm.__wbindgen_export, wasm.__wbindgen_export2);
750
+ const len1 = WASM_VECTOR_LEN;
751
+ const ptr2 = passStringToWasm0(pub_y_hex, wasm.__wbindgen_export, wasm.__wbindgen_export2);
752
+ const len2 = WASM_VECTOR_LEN;
753
+ wasm.ecdhSharedKey(retptr, ptr0, len0, ptr1, len1, ptr2, len2);
754
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
755
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
756
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
757
+ if (r2) {
758
+ throw takeObject(r1);
759
+ }
760
+ return takeObject(r0);
761
+ } finally {
762
+ wasm.__wbindgen_add_to_stack_pointer(16);
75
763
  }
76
- return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
77
764
  }
78
765
 
79
- function getStringFromWasm0(ptr, len) {
80
- ptr = ptr >>> 0;
81
- return decodeText(ptr, len);
766
+ /**
767
+ * Generate a new coin with random nullifier, secret, and shared-secret field elements.
768
+ * `amount` is stroops (u64); JS passes `bigint`.
769
+ * Returns JSON: { coin: { value, nullifier, secret, commitment }, commitment_hex }
770
+ * @param {bigint} amount
771
+ * @returns {any}
772
+ */
773
+ function generateCoin(amount) {
774
+ const ret = wasm.generateCoin(amount);
775
+ return takeObject(ret);
82
776
  }
83
777
 
84
- function dropObject(idx) {
85
- if (idx < 132) return;
86
- heap[idx] = heap_next;
87
- heap_next = idx;
778
+ /**
779
+ * `Poseidon₁(scalar)` secret + fixed ECDH shared coords (hex), matching an aligned deposit witness.
780
+ * @param {string} scalar_hex
781
+ * @param {string} shared_x_hex
782
+ * @param {string} shared_y_hex
783
+ * @param {bigint} amount
784
+ * @returns {any}
785
+ */
786
+ function generateCoinForDepositWithSharedHex(scalar_hex, shared_x_hex, shared_y_hex, amount) {
787
+ try {
788
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
789
+ const ptr0 = passStringToWasm0(scalar_hex, wasm.__wbindgen_export, wasm.__wbindgen_export2);
790
+ const len0 = WASM_VECTOR_LEN;
791
+ const ptr1 = passStringToWasm0(shared_x_hex, wasm.__wbindgen_export, wasm.__wbindgen_export2);
792
+ const len1 = WASM_VECTOR_LEN;
793
+ const ptr2 = passStringToWasm0(shared_y_hex, wasm.__wbindgen_export, wasm.__wbindgen_export2);
794
+ const len2 = WASM_VECTOR_LEN;
795
+ wasm.generateCoinForDepositWithSharedHex(retptr, ptr0, len0, ptr1, len1, ptr2, len2, amount);
796
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
797
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
798
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
799
+ if (r2) {
800
+ throw takeObject(r1);
801
+ }
802
+ return takeObject(r0);
803
+ } finally {
804
+ wasm.__wbindgen_add_to_stack_pointer(16);
805
+ }
88
806
  }
89
807
 
90
- function takeObject(idx) {
91
- const ret = getObject(idx);
92
- dropObject(idx);
93
- return ret;
808
+ /**
809
+ * `secret` in coin = `Poseidon255(1)(scalar)` per `deposit.circom`; scalar is 32-byte hex (64 chars, optional `0x`).
810
+ * @param {string} scalar_hex
811
+ * @param {bigint} amount
812
+ * @returns {any}
813
+ */
814
+ function generateCoinFromDepositEphemeralScalarHex(scalar_hex, amount) {
815
+ try {
816
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
817
+ const ptr0 = passStringToWasm0(scalar_hex, wasm.__wbindgen_export, wasm.__wbindgen_export2);
818
+ const len0 = WASM_VECTOR_LEN;
819
+ wasm.generateCoinFromDepositEphemeralScalarHex(retptr, ptr0, len0, amount);
820
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
821
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
822
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
823
+ if (r2) {
824
+ throw takeObject(r1);
825
+ }
826
+ return takeObject(r0);
827
+ } finally {
828
+ wasm.__wbindgen_add_to_stack_pointer(16);
829
+ }
94
830
  }
95
831
 
96
- function isLikeNone(x) {
97
- return x === undefined || x === null;
832
+ /**
833
+ * Same as `generateCoin`, but commitment uses the given ECDH shared key (64-char hex coords from `ecdhSharedKey`); shared coords are not stored in `coin` JSON.
834
+ * @param {string} shared_x_hex
835
+ * @param {string} shared_y_hex
836
+ * @param {bigint} amount
837
+ * @returns {any}
838
+ */
839
+ function generateCoinWithSharedSecretHex(shared_x_hex, shared_y_hex, amount) {
840
+ try {
841
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
842
+ const ptr0 = passStringToWasm0(shared_x_hex, wasm.__wbindgen_export, wasm.__wbindgen_export2);
843
+ const len0 = WASM_VECTOR_LEN;
844
+ const ptr1 = passStringToWasm0(shared_y_hex, wasm.__wbindgen_export, wasm.__wbindgen_export2);
845
+ const len1 = WASM_VECTOR_LEN;
846
+ wasm.generateCoinWithSharedSecretHex(retptr, ptr0, len0, ptr1, len1, amount);
847
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
848
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
849
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
850
+ if (r2) {
851
+ throw takeObject(r1);
852
+ }
853
+ return takeObject(r0);
854
+ } finally {
855
+ wasm.__wbindgen_add_to_stack_pointer(16);
856
+ }
857
+ }
858
+
859
+ /**
860
+ * Convert snarkjs proof JSON to hex bytes for Soroban contract.
861
+ * @param {string} proof_json
862
+ * @returns {string}
863
+ */
864
+ function proofToHex(proof_json) {
865
+ let deferred2_0;
866
+ let deferred2_1;
867
+ try {
868
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
869
+ const ptr0 = passStringToWasm0(proof_json, wasm.__wbindgen_export, wasm.__wbindgen_export2);
870
+ const len0 = WASM_VECTOR_LEN;
871
+ wasm.proofToHex(retptr, ptr0, len0);
872
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
873
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
874
+ deferred2_0 = r0;
875
+ deferred2_1 = r1;
876
+ return getStringFromWasm0(r0, r1);
877
+ } finally {
878
+ wasm.__wbindgen_add_to_stack_pointer(16);
879
+ wasm.__wbindgen_export4(deferred2_0, deferred2_1, 1);
880
+ }
881
+ }
882
+
883
+ /**
884
+ * Convert snarkjs public signals JSON to hex bytes for Soroban contract.
885
+ * @param {string} public_json
886
+ * @returns {string}
887
+ */
888
+ function publicToHex(public_json) {
889
+ let deferred2_0;
890
+ let deferred2_1;
891
+ try {
892
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
893
+ const ptr0 = passStringToWasm0(public_json, wasm.__wbindgen_export, wasm.__wbindgen_export2);
894
+ const len0 = WASM_VECTOR_LEN;
895
+ wasm.publicToHex(retptr, ptr0, len0);
896
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
897
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
898
+ deferred2_0 = r0;
899
+ deferred2_1 = r1;
900
+ return getStringFromWasm0(r0, r1);
901
+ } finally {
902
+ wasm.__wbindgen_add_to_stack_pointer(16);
903
+ wasm.__wbindgen_export4(deferred2_0, deferred2_1, 1);
904
+ }
905
+ }
906
+
907
+ function __wbg_get_imports() {
908
+ const import0 = {
909
+ __proto__: null,
910
+ __wbg_String_8564e559799eccda: function(arg0, arg1) {
911
+ const ret = String(getObject(arg1));
912
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_export, wasm.__wbindgen_export2);
913
+ const len1 = WASM_VECTOR_LEN;
914
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
915
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
916
+ },
917
+ __wbg___wbindgen_debug_string_5398f5bb970e0daa: function(arg0, arg1) {
918
+ const ret = debugString(getObject(arg1));
919
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_export, wasm.__wbindgen_export2);
920
+ const len1 = WASM_VECTOR_LEN;
921
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
922
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
923
+ },
924
+ __wbg___wbindgen_is_function_3c846841762788c1: function(arg0) {
925
+ const ret = typeof(getObject(arg0)) === 'function';
926
+ return ret;
927
+ },
928
+ __wbg___wbindgen_is_object_781bc9f159099513: function(arg0) {
929
+ const val = getObject(arg0);
930
+ const ret = typeof(val) === 'object' && val !== null;
931
+ return ret;
932
+ },
933
+ __wbg___wbindgen_is_string_7ef6b97b02428fae: function(arg0) {
934
+ const ret = typeof(getObject(arg0)) === 'string';
935
+ return ret;
936
+ },
937
+ __wbg___wbindgen_is_undefined_52709e72fb9f179c: function(arg0) {
938
+ const ret = getObject(arg0) === undefined;
939
+ return ret;
940
+ },
941
+ __wbg___wbindgen_throw_6ddd609b62940d55: function(arg0, arg1) {
942
+ throw new Error(getStringFromWasm0(arg0, arg1));
943
+ },
944
+ __wbg_call_2d781c1f4d5c0ef8: function() { return handleError(function (arg0, arg1, arg2) {
945
+ const ret = getObject(arg0).call(getObject(arg1), getObject(arg2));
946
+ return addHeapObject(ret);
947
+ }, arguments); },
948
+ __wbg_crypto_38df2bab126b63dc: function(arg0) {
949
+ const ret = getObject(arg0).crypto;
950
+ return addHeapObject(ret);
951
+ },
952
+ __wbg_getRandomValues_c44a50d8cfdaebeb: function() { return handleError(function (arg0, arg1) {
953
+ getObject(arg0).getRandomValues(getObject(arg1));
954
+ }, arguments); },
955
+ __wbg_length_ea16607d7b61445b: function(arg0) {
956
+ const ret = getObject(arg0).length;
957
+ return ret;
958
+ },
959
+ __wbg_msCrypto_bd5a034af96bcba6: function(arg0) {
960
+ const ret = getObject(arg0).msCrypto;
961
+ return addHeapObject(ret);
962
+ },
963
+ __wbg_new_ab79df5bd7c26067: function() {
964
+ const ret = new Object();
965
+ return addHeapObject(ret);
966
+ },
967
+ __wbg_new_with_length_825018a1616e9e55: function(arg0) {
968
+ const ret = new Uint8Array(arg0 >>> 0);
969
+ return addHeapObject(ret);
970
+ },
971
+ __wbg_node_84ea875411254db1: function(arg0) {
972
+ const ret = getObject(arg0).node;
973
+ return addHeapObject(ret);
974
+ },
975
+ __wbg_process_44c7a14e11e9f69e: function(arg0) {
976
+ const ret = getObject(arg0).process;
977
+ return addHeapObject(ret);
978
+ },
979
+ __wbg_prototypesetcall_d62e5099504357e6: function(arg0, arg1, arg2) {
980
+ Uint8Array.prototype.set.call(getArrayU8FromWasm0(arg0, arg1), getObject(arg2));
981
+ },
982
+ __wbg_randomFillSync_6c25eac9869eb53c: function() { return handleError(function (arg0, arg1) {
983
+ getObject(arg0).randomFillSync(takeObject(arg1));
984
+ }, arguments); },
985
+ __wbg_require_b4edbdcf3e2a1ef0: function() { return handleError(function () {
986
+ const ret = module.require;
987
+ return addHeapObject(ret);
988
+ }, arguments); },
989
+ __wbg_set_6be42768c690e380: function(arg0, arg1, arg2) {
990
+ getObject(arg0)[takeObject(arg1)] = takeObject(arg2);
991
+ },
992
+ __wbg_static_accessor_GLOBAL_8adb955bd33fac2f: function() {
993
+ const ret = typeof global === 'undefined' ? null : global;
994
+ return isLikeNone(ret) ? 0 : addHeapObject(ret);
995
+ },
996
+ __wbg_static_accessor_GLOBAL_THIS_ad356e0db91c7913: function() {
997
+ const ret = typeof globalThis === 'undefined' ? null : globalThis;
998
+ return isLikeNone(ret) ? 0 : addHeapObject(ret);
999
+ },
1000
+ __wbg_static_accessor_SELF_f207c857566db248: function() {
1001
+ const ret = typeof self === 'undefined' ? null : self;
1002
+ return isLikeNone(ret) ? 0 : addHeapObject(ret);
1003
+ },
1004
+ __wbg_static_accessor_WINDOW_bb9f1ba69d61b386: function() {
1005
+ const ret = typeof window === 'undefined' ? null : window;
1006
+ return isLikeNone(ret) ? 0 : addHeapObject(ret);
1007
+ },
1008
+ __wbg_subarray_a068d24e39478a8a: function(arg0, arg1, arg2) {
1009
+ const ret = getObject(arg0).subarray(arg1 >>> 0, arg2 >>> 0);
1010
+ return addHeapObject(ret);
1011
+ },
1012
+ __wbg_versions_276b2795b1c6a219: function(arg0) {
1013
+ const ret = getObject(arg0).versions;
1014
+ return addHeapObject(ret);
1015
+ },
1016
+ __wbindgen_cast_0000000000000001: function(arg0, arg1) {
1017
+ // Cast intrinsic for `Ref(Slice(U8)) -> NamedExternref("Uint8Array")`.
1018
+ const ret = getArrayU8FromWasm0(arg0, arg1);
1019
+ return addHeapObject(ret);
1020
+ },
1021
+ __wbindgen_cast_0000000000000002: function(arg0, arg1) {
1022
+ // Cast intrinsic for `Ref(String) -> Externref`.
1023
+ const ret = getStringFromWasm0(arg0, arg1);
1024
+ return addHeapObject(ret);
1025
+ },
1026
+ __wbindgen_object_clone_ref: function(arg0) {
1027
+ const ret = getObject(arg0);
1028
+ return addHeapObject(ret);
1029
+ },
1030
+ __wbindgen_object_drop_ref: function(arg0) {
1031
+ takeObject(arg0);
1032
+ },
1033
+ };
1034
+ return {
1035
+ __proto__: null,
1036
+ "./client_sdk_wasm_bg.js": import0,
1037
+ };
1038
+ }
1039
+
1040
+ function addHeapObject(obj) {
1041
+ if (heap_next === heap.length) heap.push(heap.length + 1);
1042
+ const idx = heap_next;
1043
+ heap_next = heap[idx];
1044
+
1045
+ heap[idx] = obj;
1046
+ return idx;
98
1047
  }
99
1048
 
100
1049
  function debugString(val) {
@@ -162,385 +1111,177 @@ function debugString(val) {
162
1111
  return className;
163
1112
  }
164
1113
 
165
- let WASM_VECTOR_LEN = 0;
166
-
167
- const cachedTextEncoder = (typeof TextEncoder !== 'undefined' ? new TextEncoder('utf-8') : { encode: () => { throw Error('TextEncoder not available') } } );
168
-
169
- const encodeString = (typeof cachedTextEncoder.encodeInto === 'function'
170
- ? function (arg, view) {
171
- return cachedTextEncoder.encodeInto(arg, view);
1114
+ function dropObject(idx) {
1115
+ if (idx < 1028) return;
1116
+ heap[idx] = heap_next;
1117
+ heap_next = idx;
172
1118
  }
173
- : function (arg, view) {
174
- const buf = cachedTextEncoder.encode(arg);
175
- view.set(buf);
176
- return {
177
- read: arg.length,
178
- written: buf.length
179
- };
180
- });
181
-
182
- function passStringToWasm0(arg, malloc, realloc) {
183
-
184
- if (realloc === undefined) {
185
- const buf = cachedTextEncoder.encode(arg);
186
- const ptr = malloc(buf.length, 1) >>> 0;
187
- getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);
188
- WASM_VECTOR_LEN = buf.length;
189
- return ptr;
190
- }
191
-
192
- let len = arg.length;
193
- let ptr = malloc(len, 1) >>> 0;
194
-
195
- const mem = getUint8ArrayMemory0();
196
-
197
- let offset = 0;
198
-
199
- for (; offset < len; offset++) {
200
- const code = arg.charCodeAt(offset);
201
- if (code > 0x7F) break;
202
- mem[ptr + offset] = code;
203
- }
204
-
205
- if (offset !== len) {
206
- if (offset !== 0) {
207
- arg = arg.slice(offset);
208
- }
209
- ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
210
- const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
211
- const ret = encodeString(arg, view);
212
-
213
- offset += ret.written;
214
- ptr = realloc(ptr, len, offset, 1) >>> 0;
215
- }
216
1119
 
217
- WASM_VECTOR_LEN = offset;
218
- return ptr;
1120
+ function getArrayU8FromWasm0(ptr, len) {
1121
+ ptr = ptr >>> 0;
1122
+ return getUint8ArrayMemory0().subarray(ptr / 1, ptr / 1 + len);
219
1123
  }
220
1124
 
221
1125
  let cachedDataViewMemory0 = null;
222
-
223
1126
  function getDataViewMemory0() {
224
1127
  if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer)) {
225
1128
  cachedDataViewMemory0 = new DataView(wasm.memory.buffer);
226
1129
  }
227
1130
  return cachedDataViewMemory0;
228
1131
  }
229
- /**
230
- * Convert snarkjs public signals JSON to hex bytes for Soroban contract.
231
- * @param {string} public_json
232
- * @returns {string}
233
- */
234
- function publicToHex(public_json) {
235
- let deferred2_0;
236
- let deferred2_1;
237
- try {
238
- const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
239
- const ptr0 = passStringToWasm0(public_json, wasm.__wbindgen_export_1, wasm.__wbindgen_export_2);
240
- const len0 = WASM_VECTOR_LEN;
241
- wasm.publicToHex(retptr, ptr0, len0);
242
- var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
243
- var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
244
- deferred2_0 = r0;
245
- deferred2_1 = r1;
246
- return getStringFromWasm0(r0, r1);
247
- } finally {
248
- wasm.__wbindgen_add_to_stack_pointer(16);
249
- wasm.__wbindgen_export_3(deferred2_0, deferred2_1, 1);
1132
+
1133
+ function getStringFromWasm0(ptr, len) {
1134
+ ptr = ptr >>> 0;
1135
+ return decodeText(ptr, len);
1136
+ }
1137
+
1138
+ let cachedUint8ArrayMemory0 = null;
1139
+ function getUint8ArrayMemory0() {
1140
+ if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
1141
+ cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
250
1142
  }
1143
+ return cachedUint8ArrayMemory0;
251
1144
  }
252
1145
 
253
- /**
254
- * Calculate nullifier hash from nullifier decimal string.
255
- * Returns hex string (0x...)
256
- * @param {string} nullifier_decimal
257
- * @returns {string}
258
- */
259
- function calculateNullifierHash(nullifier_decimal) {
260
- let deferred3_0;
261
- let deferred3_1;
1146
+ function getObject(idx) { return heap[idx]; }
1147
+
1148
+ function handleError(f, args) {
262
1149
  try {
263
- const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
264
- const ptr0 = passStringToWasm0(nullifier_decimal, wasm.__wbindgen_export_1, wasm.__wbindgen_export_2);
265
- const len0 = WASM_VECTOR_LEN;
266
- wasm.calculateNullifierHash(retptr, ptr0, len0);
267
- var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
268
- var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
269
- var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
270
- var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
271
- var ptr2 = r0;
272
- var len2 = r1;
273
- if (r3) {
274
- ptr2 = 0; len2 = 0;
275
- throw takeObject(r2);
276
- }
277
- deferred3_0 = ptr2;
278
- deferred3_1 = len2;
279
- return getStringFromWasm0(ptr2, len2);
280
- } finally {
281
- wasm.__wbindgen_add_to_stack_pointer(16);
282
- wasm.__wbindgen_export_3(deferred3_0, deferred3_1, 1);
1150
+ return f.apply(this, args);
1151
+ } catch (e) {
1152
+ wasm.__wbindgen_export3(addHeapObject(e));
283
1153
  }
284
1154
  }
285
1155
 
286
- /**
287
- * Generate withdrawal SNARK input from coin and state JSON strings.
288
- * Returns JSON string of SnarkInput.
289
- * @param {string} coin_json
290
- * @param {string} state_json
291
- * @returns {string}
292
- */
293
- function generateWithdrawalInput(coin_json, state_json) {
294
- let deferred4_0;
295
- let deferred4_1;
296
- try {
297
- const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
298
- const ptr0 = passStringToWasm0(coin_json, wasm.__wbindgen_export_1, wasm.__wbindgen_export_2);
299
- const len0 = WASM_VECTOR_LEN;
300
- const ptr1 = passStringToWasm0(state_json, wasm.__wbindgen_export_1, wasm.__wbindgen_export_2);
301
- const len1 = WASM_VECTOR_LEN;
302
- wasm.generateWithdrawalInput(retptr, ptr0, len0, ptr1, len1);
303
- var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
304
- var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
305
- var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
306
- var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
307
- var ptr3 = r0;
308
- var len3 = r1;
309
- if (r3) {
310
- ptr3 = 0; len3 = 0;
311
- throw takeObject(r2);
1156
+ let heap = new Array(1024).fill(undefined);
1157
+ heap.push(undefined, null, true, false);
1158
+
1159
+ let heap_next = heap.length;
1160
+
1161
+ function isLikeNone(x) {
1162
+ return x === undefined || x === null;
1163
+ }
1164
+
1165
+ function passStringToWasm0(arg, malloc, realloc) {
1166
+ if (realloc === undefined) {
1167
+ const buf = cachedTextEncoder.encode(arg);
1168
+ const ptr = malloc(buf.length, 1) >>> 0;
1169
+ getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);
1170
+ WASM_VECTOR_LEN = buf.length;
1171
+ return ptr;
1172
+ }
1173
+
1174
+ let len = arg.length;
1175
+ let ptr = malloc(len, 1) >>> 0;
1176
+
1177
+ const mem = getUint8ArrayMemory0();
1178
+
1179
+ let offset = 0;
1180
+
1181
+ for (; offset < len; offset++) {
1182
+ const code = arg.charCodeAt(offset);
1183
+ if (code > 0x7F) break;
1184
+ mem[ptr + offset] = code;
1185
+ }
1186
+ if (offset !== len) {
1187
+ if (offset !== 0) {
1188
+ arg = arg.slice(offset);
312
1189
  }
313
- deferred4_0 = ptr3;
314
- deferred4_1 = len3;
315
- return getStringFromWasm0(ptr3, len3);
316
- } finally {
317
- wasm.__wbindgen_add_to_stack_pointer(16);
318
- wasm.__wbindgen_export_3(deferred4_0, deferred4_1, 1);
1190
+ ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
1191
+ const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
1192
+ const ret = cachedTextEncoder.encodeInto(arg, view);
1193
+
1194
+ offset += ret.written;
1195
+ ptr = realloc(ptr, len, offset, 1) >>> 0;
319
1196
  }
1197
+
1198
+ WASM_VECTOR_LEN = offset;
1199
+ return ptr;
320
1200
  }
321
1201
 
322
- /**
323
- * Generate a new coin with random nullifier and secret.
324
- * Returns JSON: { coin: { value, nullifier, secret, commitment }, commitment_hex }
325
- * @returns {any}
326
- */
327
- function generateCoin() {
328
- const ret = wasm.generateCoin();
329
- return takeObject(ret);
1202
+ function takeObject(idx) {
1203
+ const ret = getObject(idx);
1204
+ dropObject(idx);
1205
+ return ret;
330
1206
  }
331
1207
 
332
- /**
333
- * Convert snarkjs proof JSON to hex bytes for Soroban contract.
334
- * @param {string} proof_json
335
- * @returns {string}
336
- */
337
- function proofToHex(proof_json) {
338
- let deferred2_0;
339
- let deferred2_1;
340
- try {
341
- const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
342
- const ptr0 = passStringToWasm0(proof_json, wasm.__wbindgen_export_1, wasm.__wbindgen_export_2);
343
- const len0 = WASM_VECTOR_LEN;
344
- wasm.proofToHex(retptr, ptr0, len0);
345
- var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
346
- var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
347
- deferred2_0 = r0;
348
- deferred2_1 = r1;
349
- return getStringFromWasm0(r0, r1);
350
- } finally {
351
- wasm.__wbindgen_add_to_stack_pointer(16);
352
- wasm.__wbindgen_export_3(deferred2_0, deferred2_1, 1);
1208
+ let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
1209
+ cachedTextDecoder.decode();
1210
+ const MAX_SAFARI_DECODE_BYTES = 2146435072;
1211
+ let numBytesDecoded = 0;
1212
+ function decodeText(ptr, len) {
1213
+ numBytesDecoded += len;
1214
+ if (numBytesDecoded >= MAX_SAFARI_DECODE_BYTES) {
1215
+ cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
1216
+ cachedTextDecoder.decode();
1217
+ numBytesDecoded = len;
353
1218
  }
1219
+ return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
1220
+ }
1221
+
1222
+ const cachedTextEncoder = new TextEncoder();
1223
+
1224
+ if (!('encodeInto' in cachedTextEncoder)) {
1225
+ cachedTextEncoder.encodeInto = function (arg, view) {
1226
+ const buf = cachedTextEncoder.encode(arg);
1227
+ view.set(buf);
1228
+ return {
1229
+ read: arg.length,
1230
+ written: buf.length
1231
+ };
1232
+ };
354
1233
  }
355
1234
 
356
- const EXPECTED_RESPONSE_TYPES = new Set(['basic', 'cors', 'default']);
1235
+ let WASM_VECTOR_LEN = 0;
1236
+
1237
+ let wasm;
1238
+ function __wbg_finalize_init(instance, module) {
1239
+ wasm = instance.exports;
1240
+ cachedDataViewMemory0 = null;
1241
+ cachedUint8ArrayMemory0 = null;
1242
+ return wasm;
1243
+ }
357
1244
 
358
1245
  async function __wbg_load(module, imports) {
359
1246
  if (typeof Response === 'function' && module instanceof Response) {
360
1247
  if (typeof WebAssembly.instantiateStreaming === 'function') {
361
1248
  try {
362
1249
  return await WebAssembly.instantiateStreaming(module, imports);
363
-
364
1250
  } catch (e) {
365
- const validResponse = module.ok && EXPECTED_RESPONSE_TYPES.has(module.type);
1251
+ const validResponse = module.ok && expectedResponseType(module.type);
366
1252
 
367
1253
  if (validResponse && module.headers.get('Content-Type') !== 'application/wasm') {
368
1254
  console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve Wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);
369
1255
 
370
- } else {
371
- throw e;
372
- }
1256
+ } else { throw e; }
373
1257
  }
374
1258
  }
375
1259
 
376
1260
  const bytes = await module.arrayBuffer();
377
1261
  return await WebAssembly.instantiate(bytes, imports);
378
-
379
1262
  } else {
380
1263
  const instance = await WebAssembly.instantiate(module, imports);
381
1264
 
382
1265
  if (instance instanceof WebAssembly.Instance) {
383
1266
  return { instance, module };
384
-
385
1267
  } else {
386
1268
  return instance;
387
1269
  }
388
1270
  }
389
- }
390
-
391
- function __wbg_get_imports() {
392
- const imports = {};
393
- imports.wbg = {};
394
- imports.wbg.__wbg_buffer_a1a27a0dfa70165d = function(arg0) {
395
- const ret = getObject(arg0).buffer;
396
- return addHeapObject(ret);
397
- };
398
- imports.wbg.__wbg_call_f2db6205e5c51dc8 = function() { return handleError(function (arg0, arg1, arg2) {
399
- const ret = getObject(arg0).call(getObject(arg1), getObject(arg2));
400
- return addHeapObject(ret);
401
- }, arguments) };
402
- imports.wbg.__wbg_call_fbe8be8bf6436ce5 = function() { return handleError(function (arg0, arg1) {
403
- const ret = getObject(arg0).call(getObject(arg1));
404
- return addHeapObject(ret);
405
- }, arguments) };
406
- imports.wbg.__wbg_crypto_574e78ad8b13b65f = function(arg0) {
407
- const ret = getObject(arg0).crypto;
408
- return addHeapObject(ret);
409
- };
410
- imports.wbg.__wbg_getRandomValues_b8f5dbd5f3995a9e = function() { return handleError(function (arg0, arg1) {
411
- getObject(arg0).getRandomValues(getObject(arg1));
412
- }, arguments) };
413
- imports.wbg.__wbg_msCrypto_a61aeb35a24c1329 = function(arg0) {
414
- const ret = getObject(arg0).msCrypto;
415
- return addHeapObject(ret);
416
- };
417
- imports.wbg.__wbg_new_07b483f72211fd66 = function() {
418
- const ret = new Object();
419
- return addHeapObject(ret);
420
- };
421
- imports.wbg.__wbg_new_e52b3efaaa774f96 = function(arg0) {
422
- const ret = new Uint8Array(getObject(arg0));
423
- return addHeapObject(ret);
424
- };
425
- imports.wbg.__wbg_newnoargs_ff528e72d35de39a = function(arg0, arg1) {
426
- const ret = new Function(getStringFromWasm0(arg0, arg1));
427
- return addHeapObject(ret);
428
- };
429
- imports.wbg.__wbg_newwithbyteoffsetandlength_3b01ecda099177e8 = function(arg0, arg1, arg2) {
430
- const ret = new Uint8Array(getObject(arg0), arg1 >>> 0, arg2 >>> 0);
431
- return addHeapObject(ret);
432
- };
433
- imports.wbg.__wbg_newwithlength_08f872dc1e3ada2e = function(arg0) {
434
- const ret = new Uint8Array(arg0 >>> 0);
435
- return addHeapObject(ret);
436
- };
437
- imports.wbg.__wbg_node_905d3e251edff8a2 = function(arg0) {
438
- const ret = getObject(arg0).node;
439
- return addHeapObject(ret);
440
- };
441
- imports.wbg.__wbg_process_dc0fbacc7c1c06f7 = function(arg0) {
442
- const ret = getObject(arg0).process;
443
- return addHeapObject(ret);
444
- };
445
- imports.wbg.__wbg_randomFillSync_ac0988aba3254290 = function() { return handleError(function (arg0, arg1) {
446
- getObject(arg0).randomFillSync(takeObject(arg1));
447
- }, arguments) };
448
- imports.wbg.__wbg_require_60cc747a6bc5215a = function() { return handleError(function () {
449
- const ret = module.require;
450
- return addHeapObject(ret);
451
- }, arguments) };
452
- imports.wbg.__wbg_set_3f1d0b984ed272ed = function(arg0, arg1, arg2) {
453
- getObject(arg0)[takeObject(arg1)] = takeObject(arg2);
454
- };
455
- imports.wbg.__wbg_set_fe4e79d1ed3b0e9b = function(arg0, arg1, arg2) {
456
- getObject(arg0).set(getObject(arg1), arg2 >>> 0);
457
- };
458
- imports.wbg.__wbg_static_accessor_GLOBAL_487c52c58d65314d = function() {
459
- const ret = typeof global === 'undefined' ? null : global;
460
- return isLikeNone(ret) ? 0 : addHeapObject(ret);
461
- };
462
- imports.wbg.__wbg_static_accessor_GLOBAL_THIS_ee9704f328b6b291 = function() {
463
- const ret = typeof globalThis === 'undefined' ? null : globalThis;
464
- return isLikeNone(ret) ? 0 : addHeapObject(ret);
465
- };
466
- imports.wbg.__wbg_static_accessor_SELF_78c9e3071b912620 = function() {
467
- const ret = typeof self === 'undefined' ? null : self;
468
- return isLikeNone(ret) ? 0 : addHeapObject(ret);
469
- };
470
- imports.wbg.__wbg_static_accessor_WINDOW_a093d21393777366 = function() {
471
- const ret = typeof window === 'undefined' ? null : window;
472
- return isLikeNone(ret) ? 0 : addHeapObject(ret);
473
- };
474
- imports.wbg.__wbg_subarray_dd4ade7d53bd8e26 = function(arg0, arg1, arg2) {
475
- const ret = getObject(arg0).subarray(arg1 >>> 0, arg2 >>> 0);
476
- return addHeapObject(ret);
477
- };
478
- imports.wbg.__wbg_versions_c01dfd4722a88165 = function(arg0) {
479
- const ret = getObject(arg0).versions;
480
- return addHeapObject(ret);
481
- };
482
- imports.wbg.__wbindgen_debug_string = function(arg0, arg1) {
483
- const ret = debugString(getObject(arg1));
484
- const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_export_1, wasm.__wbindgen_export_2);
485
- const len1 = WASM_VECTOR_LEN;
486
- getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
487
- getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
488
- };
489
- imports.wbg.__wbindgen_is_function = function(arg0) {
490
- const ret = typeof(getObject(arg0)) === 'function';
491
- return ret;
492
- };
493
- imports.wbg.__wbindgen_is_object = function(arg0) {
494
- const val = getObject(arg0);
495
- const ret = typeof(val) === 'object' && val !== null;
496
- return ret;
497
- };
498
- imports.wbg.__wbindgen_is_string = function(arg0) {
499
- const ret = typeof(getObject(arg0)) === 'string';
500
- return ret;
501
- };
502
- imports.wbg.__wbindgen_is_undefined = function(arg0) {
503
- const ret = getObject(arg0) === undefined;
504
- return ret;
505
- };
506
- imports.wbg.__wbindgen_memory = function() {
507
- const ret = wasm.memory;
508
- return addHeapObject(ret);
509
- };
510
- imports.wbg.__wbindgen_object_clone_ref = function(arg0) {
511
- const ret = getObject(arg0);
512
- return addHeapObject(ret);
513
- };
514
- imports.wbg.__wbindgen_object_drop_ref = function(arg0) {
515
- takeObject(arg0);
516
- };
517
- imports.wbg.__wbindgen_string_new = function(arg0, arg1) {
518
- const ret = getStringFromWasm0(arg0, arg1);
519
- return addHeapObject(ret);
520
- };
521
- imports.wbg.__wbindgen_throw = function(arg0, arg1) {
522
- throw new Error(getStringFromWasm0(arg0, arg1));
523
- };
524
-
525
- return imports;
526
- }
527
-
528
- function __wbg_finalize_init(instance, module) {
529
- wasm = instance.exports;
530
- __wbg_init.__wbindgen_wasm_module = module;
531
- cachedDataViewMemory0 = null;
532
- cachedUint8ArrayMemory0 = null;
533
-
534
1271
 
535
-
536
- return wasm;
1272
+ function expectedResponseType(type) {
1273
+ switch (type) {
1274
+ case 'basic': case 'cors': case 'default': return true;
1275
+ }
1276
+ return false;
1277
+ }
537
1278
  }
538
1279
 
539
1280
  function initSync(module) {
540
1281
  if (wasm !== undefined) return wasm;
541
1282
 
542
1283
 
543
- if (typeof module !== 'undefined') {
1284
+ if (module !== undefined) {
544
1285
  if (Object.getPrototypeOf(module) === Object.prototype) {
545
1286
  ({module} = module);
546
1287
  } else {
@@ -549,21 +1290,18 @@ function initSync(module) {
549
1290
  }
550
1291
 
551
1292
  const imports = __wbg_get_imports();
552
-
553
1293
  if (!(module instanceof WebAssembly.Module)) {
554
1294
  module = new WebAssembly.Module(module);
555
1295
  }
556
-
557
1296
  const instance = new WebAssembly.Instance(module, imports);
558
-
559
- return __wbg_finalize_init(instance, module);
1297
+ return __wbg_finalize_init(instance);
560
1298
  }
561
1299
 
562
1300
  async function __wbg_init(module_or_path) {
563
1301
  if (wasm !== undefined) return wasm;
564
1302
 
565
1303
 
566
- if (typeof module_or_path !== 'undefined') {
1304
+ if (module_or_path !== undefined) {
567
1305
  if (Object.getPrototypeOf(module_or_path) === Object.prototype) {
568
1306
  ({module_or_path} = module_or_path);
569
1307
  } else {
@@ -571,7 +1309,7 @@ async function __wbg_init(module_or_path) {
571
1309
  }
572
1310
  }
573
1311
 
574
- if (typeof module_or_path === 'undefined') {
1312
+ if (module_or_path === undefined) {
575
1313
  module_or_path = new URL('client_sdk_wasm_bg.wasm', (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.js', document.baseURI).href)));
576
1314
  }
577
1315
  const imports = __wbg_get_imports();
@@ -582,18 +1320,24 @@ async function __wbg_init(module_or_path) {
582
1320
 
583
1321
  const { instance, module } = await __wbg_load(await module_or_path, imports);
584
1322
 
585
- return __wbg_finalize_init(instance, module);
1323
+ return __wbg_finalize_init(instance);
586
1324
  }
587
1325
 
588
1326
  var wasmBindings = /*#__PURE__*/Object.freeze({
589
- __proto__: null,
590
- calculateNullifierHash: calculateNullifierHash,
591
- default: __wbg_init,
592
- generateCoin: generateCoin,
593
- generateWithdrawalInput: generateWithdrawalInput,
594
- initSync: initSync,
595
- proofToHex: proofToHex,
596
- publicToHex: publicToHex
1327
+ __proto__: null,
1328
+ buildWithdrawMerkleWitness: buildWithdrawMerkleWitness,
1329
+ calculateNullifierHash: calculateNullifierHash,
1330
+ default: __wbg_init,
1331
+ ecdhEphemeralPublicKey: ecdhEphemeralPublicKey,
1332
+ ecdhEphemeralPublicKeyFromScalarHex: ecdhEphemeralPublicKeyFromScalarHex,
1333
+ ecdhSharedKey: ecdhSharedKey,
1334
+ generateCoin: generateCoin,
1335
+ generateCoinForDepositWithSharedHex: generateCoinForDepositWithSharedHex,
1336
+ generateCoinFromDepositEphemeralScalarHex: generateCoinFromDepositEphemeralScalarHex,
1337
+ generateCoinWithSharedSecretHex: generateCoinWithSharedSecretHex,
1338
+ initSync: initSync,
1339
+ proofToHex: proofToHex,
1340
+ publicToHex: publicToHex
597
1341
  });
598
1342
 
599
1343
  const isNode$2 = typeof process !== 'undefined' && !!process.versions?.node;
@@ -603,7 +1347,7 @@ async function loadWasm(wasmBinary) {
603
1347
  return wasmModule;
604
1348
  if (isNode$2) {
605
1349
  if (wasmBinary) {
606
- initSync(wasmBinary);
1350
+ initSync({ module: wasmBinary });
607
1351
  }
608
1352
  else {
609
1353
  const path = await import('path');
@@ -612,13 +1356,13 @@ async function loadWasm(wasmBinary) {
612
1356
  const dir = path.dirname(fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.js', document.baseURI).href))));
613
1357
  const wasmPath = path.resolve(dir, '..', 'pkg', 'client_sdk_wasm_bg.wasm');
614
1358
  const buffer = fs.readFileSync(wasmPath);
615
- initSync(buffer);
1359
+ initSync({ module: buffer });
616
1360
  }
617
1361
  wasmModule = wasmBindings;
618
1362
  }
619
1363
  else {
620
1364
  if (wasmBinary) {
621
- initSync(wasmBinary);
1365
+ initSync({ module: wasmBinary });
622
1366
  }
623
1367
  else {
624
1368
  await __wbg_init();
@@ -628,10 +1372,6 @@ async function loadWasm(wasmBinary) {
628
1372
  return wasmModule;
629
1373
  }
630
1374
 
631
- function getDefaultExportFromCjs (x) {
632
- return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
633
- }
634
-
635
1375
  var witness_calculator = async function builder(code, options) {
636
1376
 
637
1377
  options = options || {};
@@ -666,6 +1406,8 @@ var witness_calculator = async function builder(code, options) {
666
1406
  err = "Not enough memory.\n";
667
1407
  } else if (code == 6) {
668
1408
  err = "Input signal array access exceeds the size.\n";
1409
+ } else if (code == 7) {
1410
+ err = "Out of bounds array access.\n";
669
1411
  } else {
670
1412
  err = "Unknown error.\n";
671
1413
  }
@@ -1090,6 +1832,29 @@ async function generateProof(wtns, zkey) {
1090
1832
  return { proof, publicSignals };
1091
1833
  }
1092
1834
 
1835
+ /**
1836
+ * Depositor: `randomNonceScalar * recipientStealthPoint` (same as circom `ECDH` with depositor scalar).
1837
+ */
1838
+ function sharedSecretFromDepositorPreimage(ecdhShared, preimage) {
1839
+ const out = ecdhShared(preimage.randomNonceScalar, preimage.recipientStealthAddress.x, preimage.recipientStealthAddress.y);
1840
+ return { x: out.x, y: out.y };
1841
+ }
1842
+ /**
1843
+ * Recipient: `recipientScalar * ephemeralKey` (same shared point as depositor path when keys match).
1844
+ */
1845
+ function sharedSecretFromRecipientPreimage(ecdhShared, preimage) {
1846
+ const out = ecdhShared(preimage.recipientScalar, preimage.ephemeralKey.x, preimage.ephemeralKey.y);
1847
+ return { x: out.x, y: out.y };
1848
+ }
1849
+
1850
+ /** Stroops amount as WASM `u64` (`bigint`). */
1851
+ function wasmU64Stroops(amount) {
1852
+ const b = typeof amount === 'bigint' ? amount : BigInt(amount);
1853
+ if (b < 0n || b > 0xffffffffffffffffn) {
1854
+ throw new RangeError('amount must be a non-negative u64 (stroops)');
1855
+ }
1856
+ return b;
1857
+ }
1093
1858
  class PrivacyPoolSDK {
1094
1859
  constructor(wasm, options) {
1095
1860
  this.wasm = wasm;
@@ -1114,20 +1879,70 @@ class PrivacyPoolSDK {
1114
1879
  return new PrivacyPoolSDK(wasm, opts);
1115
1880
  }
1116
1881
  /**
1117
- * Generate a new coin with random nullifier and secret.
1882
+ * Uniform 32-byte scalar as lowercase hex (Web Crypto). Same in browser and Node 19+.
1883
+ */
1884
+ static generateRandomScalarHex32() {
1885
+ return generateRandomScalarHex32();
1886
+ }
1887
+ /**
1888
+ * Text to sign with a Stellar wallet for stealth derivation (UTF-8). No WASM required.
1889
+ */
1890
+ static buildStealthAddressSignMessage(address, nonce = DEFAULT_STEALTH_SIGN_NONCE) {
1891
+ return buildStealthAddressSignMessage(address, nonce);
1892
+ }
1893
+ /**
1894
+ * Generate a new coin with random nullifier, secret, and random shared-secret field elements (dev / self-contained tests).
1895
+ * @param amount Stroops encoded as `bigint` or integer `number` (WASM `u64`).
1896
+ */
1897
+ generateCoin(amount) {
1898
+ return this.wasm.generateCoin(wasmU64Stroops(amount));
1899
+ }
1900
+ /**
1901
+ * Generate a coin with the same commitment shape as on-chain deposit: pass `ecdhSharedKey` output (hex x, y).
1902
+ * @param amount Stroops (`bigint` | `number`).
1903
+ */
1904
+ generateCoinWithSharedSecret(shared, amount) {
1905
+ return this.wasm.generateCoinWithSharedSecretHex(shared.x, shared.y, wasmU64Stroops(amount));
1906
+ }
1907
+ /**
1908
+ * Coin for a depositor `ephemeralKeyScalar` (32-byte hex): `coin.secret = Poseidon255(1)(scalar)` as in `deposit.circom`.
1909
+ * @param amount Stroops (`bigint` | `number`).
1118
1910
  */
1119
- generateCoin() {
1120
- return this.wasm.generateCoin();
1911
+ generateCoinFromDepositEphemeralScalarHex(scalarHex, amount) {
1912
+ return this.wasm.generateCoinFromDepositEphemeralScalarHex(scalarHex, wasmU64Stroops(amount));
1121
1913
  }
1122
1914
  /**
1123
- * Generate withdrawal SNARK input from coin data and state.
1915
+ * Aligned deposit coin: `secret = Poseidon₁(scalar)` and ECDH shared key from hex coords (e.g. `ecdhSharedKey(scalar, recipient_x, recipient_y)`).
1916
+ * @param amount Stroops (`bigint` | `number`).
1124
1917
  */
1125
- generateWithdrawalInput(coin, state) {
1918
+ generateCoinForDepositWithSharedHex(scalarHex, sharedXHex, sharedYHex, amount) {
1919
+ return this.wasm.generateCoinForDepositWithSharedHex(scalarHex, sharedXHex, sharedYHex, wasmU64Stroops(amount));
1920
+ }
1921
+ /**
1922
+ * Merkle root, path, and coin fields for the first withdraw leg (Rust LeanIMT + Poseidon).
1923
+ */
1924
+ buildWithdrawMerkleWitness(coin, state) {
1126
1925
  const coinJson = JSON.stringify(coin);
1127
1926
  const stateJson = JSON.stringify(state);
1128
- const resultJson = this.wasm.generateWithdrawalInput(coinJson, stateJson);
1927
+ const resultJson = this.wasm.buildWithdrawMerkleWitness(coinJson, stateJson);
1129
1928
  return JSON.parse(resultJson);
1130
1929
  }
1930
+ /**
1931
+ * Full `Transaction(20,2,2)` withdrawal proof: one real withdraw + dummies, using coin/state and depositor ECDH point (hex).
1932
+ */
1933
+ async proveWithdrawal(coin, state, params) {
1934
+ const witness = this.buildWithdrawMerkleWitness(coin, state);
1935
+ const w0 = withdrawObjectFromMerkleWitness(witness, {
1936
+ x: params.ephemeralXHex,
1937
+ y: params.ephemeralYHex,
1938
+ });
1939
+ return this.proveTransaction({
1940
+ stateRoot: witness.stateRoot,
1941
+ withdrawAddressHi: params.withdrawAddressHi,
1942
+ withdrawAddressLo: params.withdrawAddressLo,
1943
+ privKeyScalar: params.privKeyScalar,
1944
+ }, [w0, 'dummy'], ['dummy', 'dummy']);
1945
+ }
1131
1946
  /**
1132
1947
  * Convert a snarkjs proof JSON to hex bytes for Soroban.
1133
1948
  */
@@ -1141,16 +1956,33 @@ class PrivacyPoolSDK {
1141
1956
  return this.wasm.publicToHex(JSON.stringify(publicSignals));
1142
1957
  }
1143
1958
  /**
1144
- * Full withdrawal flow: generate input -> witness -> proof -> serialize.
1145
- * Returns proof_hex and public_hex ready for Soroban contract call.
1959
+ * BabyJubJub ephemeral point from a 32-byte scalar (hex). For custom {@link WithdrawObject} / tests.
1960
+ */
1961
+ ecdhEphemeralPublicKeyFromScalarHex(scalarHex) {
1962
+ return this.wasm.ecdhEphemeralPublicKeyFromScalarHex(scalarHex);
1963
+ }
1964
+ /** Circuit `ECDH`: scalar (32-byte hex) × recipient BabyJub point → shared key hex coords. */
1965
+ ecdhSharedKey(scalarHex, recipientPubXHex, recipientPubYHex) {
1966
+ return this.wasm.ecdhSharedKey(scalarHex, recipientPubXHex, recipientPubYHex);
1967
+ }
1968
+ /**
1969
+ * `Transaction(20,2,2)` proof from high-level legs: maps to witness input (incl. `"dummy"` ECDH via WASM), then Groth16 → Soroban hex.
1970
+ *
1971
+ * @param publicParams Public inputs: `stateRoot`, `withdrawAddressHi` / `withdrawAddressLo`, `privKeyScalar` (decimal field strings).
1972
+ * @param withdraws Exactly two withdraw slots (`WithdrawObject` or `"dummy"`).
1973
+ * @param deposits Exactly two deposit slots (`DepositObject` or `"dummy"`).
1146
1974
  */
1147
- async prepareWithdrawal(coin, state) {
1148
- const snarkInput = this.generateWithdrawalInput(coin, state);
1149
- const wtns = await generateWitness(snarkInput, this.options.circuitWasm);
1975
+ async proveTransaction(publicParams, withdraws, deposits) {
1976
+ const wasmEcdh = {
1977
+ ecdhEphemeralPublicKeyFromScalarHex: (h) => this.wasm.ecdhEphemeralPublicKeyFromScalarHex(h),
1978
+ };
1979
+ const witnessInput = buildTransactionWitnessInput(publicParams, withdraws, deposits, wasmEcdh);
1980
+ const wtns = await generateWitness(witnessInput, this.options.circuitWasm);
1150
1981
  const { proof, publicSignals } = await generateProof(wtns, this.options.zkey);
1151
- const proof_hex = this.proofToHex(proof);
1152
- const public_hex = this.publicToHex(publicSignals);
1153
- return { proof_hex, public_hex };
1982
+ return {
1983
+ proof_hex: this.proofToHex(proof),
1984
+ public_hex: this.publicToHex(publicSignals),
1985
+ };
1154
1986
  }
1155
1987
  /**
1156
1988
  * Calculate nullifier hash: Poseidon(nullifier)
@@ -1160,8 +1992,37 @@ class PrivacyPoolSDK {
1160
1992
  calculateNullifierHash(nullifier) {
1161
1993
  return this.wasm.calculateNullifierHash(nullifier);
1162
1994
  }
1995
+ /**
1996
+ * Ed25519 signature from signing {@link buildStealthAddressSignMessage}: **128 hex chars** (optional `0x`)
1997
+ * or **base64** (64 raw bytes after decode). `SHA-256(signature bytes)` → scalar → ECDH → `stpl1` Bech32.
1998
+ */
1999
+ async generateStealthAddressFromStellarSignature(signature) {
2000
+ return stealthAddressFromStellarSignature((h) => this.wasm.ecdhEphemeralPublicKeyFromScalarHex(h), encodeStealthAddress, signature);
2001
+ }
2002
+ encodeDecodedEphemeralKey(decoded) {
2003
+ return encodeDecodedEphemeralKey(decoded);
2004
+ }
2005
+ decodeDecodedEphemeralKey(encoded) {
2006
+ return decodeDecodedEphemeralKey(encoded);
2007
+ }
2008
+ encodeDepositorSharedSecretPreimage(decoded) {
2009
+ return encodeDepositorSharedSecretPreimage(decoded);
2010
+ }
2011
+ decodeDepositorSharedSecretPreimage(encoded) {
2012
+ return decodeDepositorSharedSecretPreimage(encoded);
2013
+ }
2014
+ sharedSecretFromDepositorPreimage(preimage) {
2015
+ return sharedSecretFromDepositorPreimage((a, b, c) => this.wasm.ecdhSharedKey(a, b, c), preimage);
2016
+ }
2017
+ sharedSecretFromRecipientPreimage(preimage) {
2018
+ return sharedSecretFromRecipientPreimage((a, b, c) => this.wasm.ecdhSharedKey(a, b, c), preimage);
2019
+ }
1163
2020
  }
1164
2021
 
2022
+ /** Pool Merkle tree depth (matches `coin::TREE_DEPTH` / `Transaction` circuit). */
2023
+ /** Default coin value in stroops (1 XLM); matches Rust `coin::COIN_VALUE`. */
2024
+ const COIN_VALUE_STROOPS = 1000000000;
2025
+
1165
2026
  async function main() {
1166
2027
  const args = process.argv.slice(2);
1167
2028
  if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {
@@ -1172,9 +2033,24 @@ async function main() {
1172
2033
  if (command === 'withdraw') {
1173
2034
  await handleWithdraw(args.slice(1));
1174
2035
  }
2036
+ else if (command === 'deposit-proof') {
2037
+ await handleDepositProof(args.slice(1));
2038
+ }
1175
2039
  else if (command === 'generate') {
1176
2040
  await handleGenerate(args.slice(1));
1177
2041
  }
2042
+ else if (command === 'random-scalar') {
2043
+ handleRandomScalar();
2044
+ }
2045
+ else if (command === 'stealth-sign-message') {
2046
+ handleStealthSignMessage(args.slice(1));
2047
+ }
2048
+ else if (command === 'stealth-from-signature') {
2049
+ await handleStealthFromSignature(args.slice(1));
2050
+ }
2051
+ else if (command === 'priv-scalar-from-signature') {
2052
+ await handlePrivScalarFromSignature(args.slice(1));
2053
+ }
1178
2054
  else {
1179
2055
  console.error(`Unknown command: ${command}`);
1180
2056
  printUsage();
@@ -1189,14 +2065,44 @@ function printUsage() {
1189
2065
  Commands:
1190
2066
  generate Generate a new coin
1191
2067
  --output, -o <file> Output coin to file (default: stdout)
2068
+ --amount <stroops> Coin value in stroops (u64); default: 1000000000 (1 XLM)
2069
+ --scalar <hex> 32-byte depositor ephemeral scalar (64 hex, optional 0x); coin.secret = Poseidon₁(scalar) (deposit.circom)
2070
+ --stealth <stpl1...> With --scalar: ECDH(scalar, recipient) shared secret + aligned commitment (requires WASM ecdhSharedKey)
2071
+
2072
+ random-scalar Print random 32-byte hex scalar with integer < 2^253 (BabyJub / circom)
2073
+
2074
+ stealth-sign-message Print message to sign (Stellar wallet / stellar CLI)
2075
+ --address <G...> Stellar account address (required)
2076
+ --nonce <string> Nonce label (default: "main address")
2077
+
2078
+ stealth-from-signature Derive stpl1 stealth address from Ed25519 signature
2079
+ --signature <value> 128 hex chars (optional 0x) or standard base64 (64 bytes)
2080
+ --signature-file <path> Read signature from file (whitespace trimmed)
2081
+
2082
+ priv-scalar-from-signature Print privKeyScalar (decimal Fr) from Stellar Ed25519 signature (SHA-256(sig) mod r)
1192
2083
 
1193
2084
  withdraw Generate a withdrawal proof
1194
2085
  --coin <file> Path to coin JSON file
1195
2086
  --state <file> Path to state JSON file
2087
+ --withdraw-pubkey-hex <hex> Stellar account Ed25519 payload (32 bytes = 64 hex); splits to public withdrawAddressHi/Lo
2088
+ --withdraw-address-hi <dec> Optional: override high u128 (decimal) if not using --withdraw-pubkey-hex
2089
+ --withdraw-address-lo <dec> Optional: override low u128 (decimal)
2090
+ --priv-key-scalar <dec> privKeyScalar (decimal Fr)
2091
+ --ephemeral-x <hex> Depositor ECDH point x (64 hex chars, optional 0x)
2092
+ --ephemeral-y <hex> Depositor ECDH point y (64 hex chars, optional 0x)
1196
2093
  --output-proof <file> Write proof hex to file
1197
2094
  --output-public <file> Write public signals hex to file
1198
2095
 
1199
- Output (withdraw):
2096
+ deposit-proof Groth16 proof for deposit-only transact (2 dummy withdraws, 1 deposit + dummy)
2097
+ --state-root <dec> Current Merkle root (decimal Fr), must match pool on submit
2098
+ --stealth <stpl1...> Recipient stealth address (decodes to recipient public key)
2099
+ --coin <file> With --ephemeral-scalar-hex: use coin nullifier/value (aligned with generate --scalar --stealth)
2100
+ --ephemeral-scalar-hex <hex> Same 32-byte hex as deposit / generate --scalar
2101
+ --value <dec> Deposit amount (stroops as decimal Fr); optional if --coin (must match coin)
2102
+ --output-proof <file> Write proof hex to file
2103
+ --output-public <file> Write public signals hex to file
2104
+
2105
+ Output (withdraw, deposit-proof):
1200
2106
  Prints proof_hex on first line and public_hex on second line to stdout.
1201
2107
  `);
1202
2108
  }
@@ -1218,13 +2124,101 @@ function parseArgs(args) {
1218
2124
  else if (arg === '-o' && i + 1 < args.length) {
1219
2125
  parsed['output'] = args[++i];
1220
2126
  }
2127
+ else if (arg === '-a' && i + 1 < args.length) {
2128
+ parsed['address'] = args[++i];
2129
+ }
2130
+ else if (arg === '-n' && i + 1 < args.length) {
2131
+ parsed['nonce'] = args[++i];
2132
+ }
2133
+ else if (arg === '-s' && i + 1 < args.length) {
2134
+ parsed['signature'] = args[++i];
2135
+ }
1221
2136
  }
1222
2137
  return parsed;
1223
2138
  }
2139
+ function handleStealthSignMessage(args) {
2140
+ const parsed = parseArgs(args);
2141
+ const address = parsed['address'];
2142
+ if (!address) {
2143
+ console.error('Error: --address <G...> is required');
2144
+ process.exit(1);
2145
+ }
2146
+ const nonce = parsed['nonce'] ?? DEFAULT_STEALTH_SIGN_NONCE;
2147
+ console.log(buildStealthAddressSignMessage(address, nonce));
2148
+ }
2149
+ async function handleStealthFromSignature(args) {
2150
+ const parsed = parseArgs(args);
2151
+ let sig = parsed['signature'];
2152
+ if (parsed['signature-file']) {
2153
+ sig = fs__namespace.readFileSync(parsed['signature-file'], 'utf-8');
2154
+ }
2155
+ if (!sig) {
2156
+ console.error('Error: --signature <hex> or --signature-file <path> is required');
2157
+ process.exit(1);
2158
+ }
2159
+ const sdk = await PrivacyPoolSDK.init();
2160
+ const stealth = await sdk.generateStealthAddressFromStellarSignature(sig);
2161
+ console.log(stealth);
2162
+ }
2163
+ async function handlePrivScalarFromSignature(args) {
2164
+ const parsed = parseArgs(args);
2165
+ let sig = parsed['signature'];
2166
+ if (parsed['signature-file']) {
2167
+ sig = fs__namespace.readFileSync(parsed['signature-file'], 'utf-8');
2168
+ }
2169
+ if (!sig) {
2170
+ console.error('Error: --signature <hex> or --signature-file <path> is required');
2171
+ process.exit(1);
2172
+ }
2173
+ const dec = await privKeyScalarDecimalFromStellarSignature(sig.trim());
2174
+ console.log(dec);
2175
+ }
2176
+ function handleRandomScalar() {
2177
+ console.log(PrivacyPoolSDK.generateRandomScalarHex32());
2178
+ }
2179
+ function parseStroopsU64(label, raw, defaultStroops) {
2180
+ if (raw === undefined) {
2181
+ return defaultStroops;
2182
+ }
2183
+ if (!/^\d+$/.test(raw)) {
2184
+ console.error(`Error: ${label} must be a non-negative decimal integer (stroops u64)`);
2185
+ process.exit(1);
2186
+ }
2187
+ try {
2188
+ const b = BigInt(raw);
2189
+ if (b < 0n || b > 0xffffffffffffffffn) {
2190
+ console.error(`Error: ${label} out of u64 range`);
2191
+ process.exit(1);
2192
+ }
2193
+ return b;
2194
+ }
2195
+ catch {
2196
+ console.error(`Error: invalid ${label}`);
2197
+ process.exit(1);
2198
+ }
2199
+ }
1224
2200
  async function handleGenerate(args) {
1225
2201
  const parsed = parseArgs(args);
1226
2202
  const sdk = await PrivacyPoolSDK.init();
1227
- const coin = sdk.generateCoin();
2203
+ const scalar = parsed['scalar'];
2204
+ const stealth = parsed['stealth'];
2205
+ const amount = parseStroopsU64('--amount', parsed['amount'], BigInt(COIN_VALUE_STROOPS));
2206
+ if (stealth && !scalar) {
2207
+ console.error('Error: --stealth requires --scalar');
2208
+ process.exit(1);
2209
+ }
2210
+ let coin;
2211
+ if (scalar && stealth) {
2212
+ const { x, y } = decodeStealthAddress(stealth);
2213
+ const shared = sdk.ecdhSharedKey(scalar, x, y);
2214
+ coin = sdk.generateCoinForDepositWithSharedHex(scalar, shared.x, shared.y, amount);
2215
+ }
2216
+ else if (scalar) {
2217
+ coin = sdk.generateCoinFromDepositEphemeralScalarHex(scalar, amount);
2218
+ }
2219
+ else {
2220
+ coin = sdk.generateCoin(amount);
2221
+ }
1228
2222
  const json = JSON.stringify(coin, null, 2);
1229
2223
  if (parsed['output']) {
1230
2224
  fs__namespace.writeFileSync(parsed['output'], json);
@@ -1245,11 +2239,37 @@ async function handleWithdraw(args) {
1245
2239
  console.error('Error: --state <file> is required');
1246
2240
  process.exit(1);
1247
2241
  }
2242
+ let withdrawHi = parsed['withdraw-address-hi'];
2243
+ let withdrawLo = parsed['withdraw-address-lo'];
2244
+ const pkHex = parsed['withdraw-pubkey-hex'];
2245
+ if (pkHex) {
2246
+ const parts = ed25519PubkeyPayloadHexToWithdrawFrDecimals(pkHex);
2247
+ withdrawHi = parts.hi;
2248
+ withdrawLo = parts.lo;
2249
+ }
2250
+ if (withdrawHi === undefined || withdrawLo === undefined) {
2251
+ console.error('Error: provide --withdraw-pubkey-hex <64 hex> or both --withdraw-address-hi and --withdraw-address-lo');
2252
+ process.exit(1);
2253
+ }
2254
+ if (!parsed['priv-key-scalar']) {
2255
+ console.error('Error: --priv-key-scalar <dec> is required');
2256
+ process.exit(1);
2257
+ }
2258
+ if (!parsed['ephemeral-x'] || !parsed['ephemeral-y']) {
2259
+ console.error('Error: --ephemeral-x <hex> and --ephemeral-y <hex> are required');
2260
+ process.exit(1);
2261
+ }
1248
2262
  const coinFile = JSON.parse(fs__namespace.readFileSync(parsed['coin'], 'utf-8'));
1249
2263
  const coin = coinFile.coin || coinFile;
1250
2264
  const state = JSON.parse(fs__namespace.readFileSync(parsed['state'], 'utf-8'));
1251
2265
  const sdk = await PrivacyPoolSDK.init();
1252
- const result = await sdk.prepareWithdrawal(coin, state);
2266
+ const result = await sdk.proveWithdrawal(coin, state, {
2267
+ withdrawAddressHi: withdrawHi,
2268
+ withdrawAddressLo: withdrawLo,
2269
+ privKeyScalar: parsed['priv-key-scalar'],
2270
+ ephemeralXHex: parsed['ephemeral-x'],
2271
+ ephemeralYHex: parsed['ephemeral-y'],
2272
+ });
1253
2273
  // Output proof and public hex to stdout (newline-separated)
1254
2274
  console.log(result.proof_hex);
1255
2275
  console.log(result.public_hex);
@@ -1263,6 +2283,69 @@ async function handleWithdraw(args) {
1263
2283
  console.error(`Public signals written to: ${parsed['output-public']}`);
1264
2284
  }
1265
2285
  }
2286
+ async function handleDepositProof(args) {
2287
+ const parsed = parseArgs(args);
2288
+ if (!parsed['state-root']) {
2289
+ console.error('Error: --state-root <dec> is required');
2290
+ process.exit(1);
2291
+ }
2292
+ if (!parsed['stealth']) {
2293
+ console.error('Error: --stealth <stpl1...> is required');
2294
+ process.exit(1);
2295
+ }
2296
+ const sdk = await PrivacyPoolSDK.init();
2297
+ const recipientPublicKeys = recipientPublicKeysDecimalFromStealthAddress(parsed['stealth']);
2298
+ const coinPath = parsed['coin'];
2299
+ const ephemeralScalarHex = parsed['ephemeral-scalar-hex'];
2300
+ let deposit;
2301
+ if (coinPath || ephemeralScalarHex) {
2302
+ if (!coinPath || !ephemeralScalarHex) {
2303
+ console.error('Error: aligned deposit proof requires both --coin <file> and --ephemeral-scalar-hex <hex>');
2304
+ process.exit(1);
2305
+ }
2306
+ const coinFile = JSON.parse(fs__namespace.readFileSync(coinPath, 'utf-8'));
2307
+ const c = coinFile.coin || coinFile;
2308
+ const value = parsed['value'] ?? c.value;
2309
+ if (parsed['value'] && parsed['value'] !== c.value) {
2310
+ console.error('Error: --value must match coin.value when using --coin');
2311
+ process.exit(1);
2312
+ }
2313
+ deposit = {
2314
+ value,
2315
+ nullifier: c.nullifier,
2316
+ ephemeralKeyScalar: scalarHexToFrDecimal(ephemeralScalarHex),
2317
+ recipientPublicKeys,
2318
+ };
2319
+ }
2320
+ else {
2321
+ if (!parsed['value']) {
2322
+ console.error('Error: --value <dec> is required (unless using --coin and --ephemeral-scalar-hex)');
2323
+ process.exit(1);
2324
+ }
2325
+ deposit = {
2326
+ value: parsed['value'],
2327
+ nullifier: randomFrDecimal(),
2328
+ ephemeralKeyScalar: randomFrDecimal253(),
2329
+ recipientPublicKeys,
2330
+ };
2331
+ }
2332
+ const result = await sdk.proveTransaction({
2333
+ stateRoot: parsed['state-root'],
2334
+ withdrawAddressHi: '0',
2335
+ withdrawAddressLo: '0',
2336
+ privKeyScalar: randomFrDecimal253(),
2337
+ }, ['dummy', 'dummy'], [deposit, 'dummy']);
2338
+ console.log(result.proof_hex);
2339
+ console.log(result.public_hex);
2340
+ if (parsed['output-proof']) {
2341
+ fs__namespace.writeFileSync(parsed['output-proof'], result.proof_hex);
2342
+ console.error(`Proof written to: ${parsed['output-proof']}`);
2343
+ }
2344
+ if (parsed['output-public']) {
2345
+ fs__namespace.writeFileSync(parsed['output-public'], result.public_hex);
2346
+ console.error(`Public signals written to: ${parsed['output-public']}`);
2347
+ }
2348
+ }
1266
2349
  main().catch((err) => {
1267
2350
  console.error('Error:', err.message || err);
1268
2351
  process.exit(1);