@auditable/privacy-pool-zk-sdk 0.7.0 → 0.8.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/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as snarkjs from 'snarkjs';
2
- import { StrKey, xdr, nativeToScVal, Address, Keypair, rpc, TransactionBuilder, Operation, authorizeEntry } from '@stellar/stellar-sdk';
2
+ import { StrKey, Address, Keypair, rpc, TransactionBuilder, Operation, xdr, nativeToScVal, authorizeEntry } from '@stellar/stellar-sdk';
3
3
  import { buildBabyjub, buildMimc7, buildPoseidon } from 'circomlibjs';
4
4
 
5
5
  /* @ts-self-types="./client_sdk_wasm.d.ts" */
@@ -40,35 +40,69 @@ function buildWithdrawMerkleWitness(coin_json, state_json) {
40
40
  }
41
41
 
42
42
  /**
43
- * Calculate nullifier hash from nullifier decimal string.
43
+ * Calculate owner-bound nullifier hash from nullifier and spend-scalar decimal strings.
44
44
  * Returns hex string (0x...)
45
45
  * @param {string} nullifier_decimal
46
+ * @param {string} priv_key_scalar_decimal
46
47
  * @returns {string}
47
48
  */
48
- function calculateNullifierHash(nullifier_decimal) {
49
- let deferred3_0;
50
- let deferred3_1;
49
+ function calculateNullifierHash(nullifier_decimal, priv_key_scalar_decimal) {
50
+ let deferred4_0;
51
+ let deferred4_1;
51
52
  try {
52
53
  const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
53
54
  const ptr0 = passStringToWasm0(nullifier_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
54
55
  const len0 = WASM_VECTOR_LEN;
55
- wasm.calculateNullifierHash(retptr, ptr0, len0);
56
+ const ptr1 = passStringToWasm0(priv_key_scalar_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
57
+ const len1 = WASM_VECTOR_LEN;
58
+ wasm.calculateNullifierHash(retptr, ptr0, len0, ptr1, len1);
56
59
  var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
57
60
  var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
58
61
  var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
59
62
  var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
60
- var ptr2 = r0;
61
- var len2 = r1;
63
+ var ptr3 = r0;
64
+ var len3 = r1;
62
65
  if (r3) {
63
- ptr2 = 0; len2 = 0;
66
+ ptr3 = 0; len3 = 0;
64
67
  throw takeObject(r2);
65
68
  }
66
- deferred3_0 = ptr2;
67
- deferred3_1 = len2;
68
- return getStringFromWasm0(ptr2, len2);
69
+ deferred4_0 = ptr3;
70
+ deferred4_1 = len3;
71
+ return getStringFromWasm0(ptr3, len3);
72
+ } finally {
73
+ wasm.__wbindgen_add_to_stack_pointer(16);
74
+ wasm.__wbindgen_export4(deferred4_0, deferred4_1, 1);
75
+ }
76
+ }
77
+
78
+ /**
79
+ * `R = Poseidon255(2)(hi, lo)`; `scalar` is the raw Poseidon hash when it is
80
+ * already in `(0, BabyJub subgroup order)`. Out-of-range hashes fail so the
81
+ * caller can rejection-sample a new nonce.
82
+ * @param {string} nonce_decimal
83
+ * @param {string} recipient_hi_decimal
84
+ * @param {string} recipient_lo_decimal
85
+ * @returns {any}
86
+ */
87
+ function derivedEscrowKey$1(nonce_decimal, recipient_hi_decimal, recipient_lo_decimal) {
88
+ try {
89
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
90
+ const ptr0 = passStringToWasm0(nonce_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
91
+ const len0 = WASM_VECTOR_LEN;
92
+ const ptr1 = passStringToWasm0(recipient_hi_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
93
+ const len1 = WASM_VECTOR_LEN;
94
+ const ptr2 = passStringToWasm0(recipient_lo_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
95
+ const len2 = WASM_VECTOR_LEN;
96
+ wasm.derivedEscrowKey(retptr, ptr0, len0, ptr1, len1, ptr2, len2);
97
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
98
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
99
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
100
+ if (r2) {
101
+ throw takeObject(r1);
102
+ }
103
+ return takeObject(r0);
69
104
  } finally {
70
105
  wasm.__wbindgen_add_to_stack_pointer(16);
71
- wasm.__wbindgen_export4(deferred3_0, deferred3_1, 1);
72
106
  }
73
107
  }
74
108
 
@@ -149,26 +183,28 @@ function ecdhSharedKey(priv_hex, pub_x_hex, pub_y_hex) {
149
183
  }
150
184
 
151
185
  /**
152
- * Generate a new coin with random nullifier, secret, and shared-secret field elements.
153
- * `amount` is stroops (u64); JS passes `bigint`.
186
+ * Generate a new coin with random nullifier, secret, and owner public-key field elements.
187
+ * `amount_decimal` is an arbitrary-precision decimal field element (never JS `number`).
154
188
  * `asset_hi_decimal` / `asset_lo_decimal` are decimal Fr strings for the Stellar asset contract id (two limbs).
155
189
  * Returns JSON: { coin: { value, nullifier, secret, commitment, asset_hi, asset_lo }, commitment_hex, precommitement_hex }
156
- * @param {bigint} amount
190
+ * @param {string} amount_decimal
157
191
  * @param {string} asset_hi_decimal
158
192
  * @param {string} asset_lo_decimal
159
193
  * @param {string} application_id_decimal
160
194
  * @returns {any}
161
195
  */
162
- function generateCoin(amount, asset_hi_decimal, asset_lo_decimal, application_id_decimal) {
196
+ function generateCoin(amount_decimal, asset_hi_decimal, asset_lo_decimal, application_id_decimal) {
163
197
  try {
164
198
  const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
165
- const ptr0 = passStringToWasm0(asset_hi_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
199
+ const ptr0 = passStringToWasm0(amount_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
166
200
  const len0 = WASM_VECTOR_LEN;
167
- const ptr1 = passStringToWasm0(asset_lo_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
201
+ const ptr1 = passStringToWasm0(asset_hi_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
168
202
  const len1 = WASM_VECTOR_LEN;
169
- const ptr2 = passStringToWasm0(application_id_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
203
+ const ptr2 = passStringToWasm0(asset_lo_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
170
204
  const len2 = WASM_VECTOR_LEN;
171
- wasm.generateCoin(retptr, amount, ptr0, len0, ptr1, len1, ptr2, len2);
205
+ const ptr3 = passStringToWasm0(application_id_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
206
+ const len3 = WASM_VECTOR_LEN;
207
+ wasm.generateCoin(retptr, ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3);
172
208
  var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
173
209
  var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
174
210
  var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
@@ -182,32 +218,34 @@ function generateCoin(amount, asset_hi_decimal, asset_lo_decimal, application_id
182
218
  }
183
219
 
184
220
  /**
185
- * `Poseidon₁(scalar)` secret + fixed ECDH shared coords (hex), matching an aligned deposit witness.
221
+ * `Poseidon₁(scalar)` secret + recipient owner public key (hex), matching an aligned deposit witness.
186
222
  * @param {string} scalar_hex
187
- * @param {string} shared_x_hex
188
- * @param {string} shared_y_hex
189
- * @param {bigint} amount
223
+ * @param {string} owner_x_hex
224
+ * @param {string} owner_y_hex
225
+ * @param {string} amount_decimal
190
226
  * @param {string} asset_hi_decimal
191
227
  * @param {string} asset_lo_decimal
192
228
  * @param {string} application_id_decimal
193
229
  * @returns {any}
194
230
  */
195
- function generateCoinForDepositWithSharedHex(scalar_hex, shared_x_hex, shared_y_hex, amount, asset_hi_decimal, asset_lo_decimal, application_id_decimal) {
231
+ function generateCoinForDepositWithOwnerPubHex(scalar_hex, owner_x_hex, owner_y_hex, amount_decimal, asset_hi_decimal, asset_lo_decimal, application_id_decimal) {
196
232
  try {
197
233
  const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
198
234
  const ptr0 = passStringToWasm0(scalar_hex, wasm.__wbindgen_export, wasm.__wbindgen_export2);
199
235
  const len0 = WASM_VECTOR_LEN;
200
- const ptr1 = passStringToWasm0(shared_x_hex, wasm.__wbindgen_export, wasm.__wbindgen_export2);
236
+ const ptr1 = passStringToWasm0(owner_x_hex, wasm.__wbindgen_export, wasm.__wbindgen_export2);
201
237
  const len1 = WASM_VECTOR_LEN;
202
- const ptr2 = passStringToWasm0(shared_y_hex, wasm.__wbindgen_export, wasm.__wbindgen_export2);
238
+ const ptr2 = passStringToWasm0(owner_y_hex, wasm.__wbindgen_export, wasm.__wbindgen_export2);
203
239
  const len2 = WASM_VECTOR_LEN;
204
- const ptr3 = passStringToWasm0(asset_hi_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
240
+ const ptr3 = passStringToWasm0(amount_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
205
241
  const len3 = WASM_VECTOR_LEN;
206
- const ptr4 = passStringToWasm0(asset_lo_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
242
+ const ptr4 = passStringToWasm0(asset_hi_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
207
243
  const len4 = WASM_VECTOR_LEN;
208
- const ptr5 = passStringToWasm0(application_id_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
244
+ const ptr5 = passStringToWasm0(asset_lo_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
209
245
  const len5 = WASM_VECTOR_LEN;
210
- wasm.generateCoinForDepositWithSharedHex(retptr, ptr0, len0, ptr1, len1, ptr2, len2, amount, ptr3, len3, ptr4, len4, ptr5, len5);
246
+ const ptr6 = passStringToWasm0(application_id_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
247
+ const len6 = WASM_VECTOR_LEN;
248
+ wasm.generateCoinForDepositWithOwnerPubHex(retptr, ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3, ptr4, len4, ptr5, len5, ptr6, len6);
211
249
  var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
212
250
  var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
213
251
  var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
@@ -223,24 +261,26 @@ function generateCoinForDepositWithSharedHex(scalar_hex, shared_x_hex, shared_y_
223
261
  /**
224
262
  * `secret` in coin = `Poseidon255(1)(scalar)` per `deposit.circom`; scalar is 32-byte hex (64 chars, optional `0x`).
225
263
  * @param {string} scalar_hex
226
- * @param {bigint} amount
264
+ * @param {string} amount_decimal
227
265
  * @param {string} asset_hi_decimal
228
266
  * @param {string} asset_lo_decimal
229
267
  * @param {string} application_id_decimal
230
268
  * @returns {any}
231
269
  */
232
- function generateCoinFromDepositEphemeralScalarHex(scalar_hex, amount, asset_hi_decimal, asset_lo_decimal, application_id_decimal) {
270
+ function generateCoinFromDepositEphemeralScalarHex(scalar_hex, amount_decimal, asset_hi_decimal, asset_lo_decimal, application_id_decimal) {
233
271
  try {
234
272
  const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
235
273
  const ptr0 = passStringToWasm0(scalar_hex, wasm.__wbindgen_export, wasm.__wbindgen_export2);
236
274
  const len0 = WASM_VECTOR_LEN;
237
- const ptr1 = passStringToWasm0(asset_hi_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
275
+ const ptr1 = passStringToWasm0(amount_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
238
276
  const len1 = WASM_VECTOR_LEN;
239
- const ptr2 = passStringToWasm0(asset_lo_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
277
+ const ptr2 = passStringToWasm0(asset_hi_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
240
278
  const len2 = WASM_VECTOR_LEN;
241
- const ptr3 = passStringToWasm0(application_id_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
279
+ const ptr3 = passStringToWasm0(asset_lo_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
242
280
  const len3 = WASM_VECTOR_LEN;
243
- wasm.generateCoinFromDepositEphemeralScalarHex(retptr, ptr0, len0, amount, ptr1, len1, ptr2, len2, ptr3, len3);
281
+ const ptr4 = passStringToWasm0(application_id_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
282
+ const len4 = WASM_VECTOR_LEN;
283
+ wasm.generateCoinFromDepositEphemeralScalarHex(retptr, ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3, ptr4, len4);
244
284
  var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
245
285
  var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
246
286
  var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
@@ -254,29 +294,31 @@ function generateCoinFromDepositEphemeralScalarHex(scalar_hex, amount, asset_hi_
254
294
  }
255
295
 
256
296
  /**
257
- * 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.
258
- * @param {string} shared_x_hex
259
- * @param {string} shared_y_hex
260
- * @param {bigint} amount
297
+ * Same as `generateCoin`, but commitment uses the given owner public key (64-char hex coords).
298
+ * @param {string} owner_x_hex
299
+ * @param {string} owner_y_hex
300
+ * @param {string} amount_decimal
261
301
  * @param {string} asset_hi_decimal
262
302
  * @param {string} asset_lo_decimal
263
303
  * @param {string} application_id_decimal
264
304
  * @returns {any}
265
305
  */
266
- function generateCoinWithSharedSecretHex(shared_x_hex, shared_y_hex, amount, asset_hi_decimal, asset_lo_decimal, application_id_decimal) {
306
+ function generateCoinWithOwnerPubHex(owner_x_hex, owner_y_hex, amount_decimal, asset_hi_decimal, asset_lo_decimal, application_id_decimal) {
267
307
  try {
268
308
  const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
269
- const ptr0 = passStringToWasm0(shared_x_hex, wasm.__wbindgen_export, wasm.__wbindgen_export2);
309
+ const ptr0 = passStringToWasm0(owner_x_hex, wasm.__wbindgen_export, wasm.__wbindgen_export2);
270
310
  const len0 = WASM_VECTOR_LEN;
271
- const ptr1 = passStringToWasm0(shared_y_hex, wasm.__wbindgen_export, wasm.__wbindgen_export2);
311
+ const ptr1 = passStringToWasm0(owner_y_hex, wasm.__wbindgen_export, wasm.__wbindgen_export2);
272
312
  const len1 = WASM_VECTOR_LEN;
273
- const ptr2 = passStringToWasm0(asset_hi_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
313
+ const ptr2 = passStringToWasm0(amount_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
274
314
  const len2 = WASM_VECTOR_LEN;
275
- const ptr3 = passStringToWasm0(asset_lo_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
315
+ const ptr3 = passStringToWasm0(asset_hi_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
276
316
  const len3 = WASM_VECTOR_LEN;
277
- const ptr4 = passStringToWasm0(application_id_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
317
+ const ptr4 = passStringToWasm0(asset_lo_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
278
318
  const len4 = WASM_VECTOR_LEN;
279
- wasm.generateCoinWithSharedSecretHex(retptr, ptr0, len0, ptr1, len1, amount, ptr2, len2, ptr3, len3, ptr4, len4);
319
+ const ptr5 = passStringToWasm0(application_id_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
320
+ const len5 = WASM_VECTOR_LEN;
321
+ wasm.generateCoinWithOwnerPubHex(retptr, ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3, ptr4, len4, ptr5, len5);
280
322
  var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
281
323
  var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
282
324
  var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
@@ -689,13 +731,14 @@ var wasmBindings = /*#__PURE__*/Object.freeze({
689
731
  buildWithdrawMerkleWitness: buildWithdrawMerkleWitness,
690
732
  calculateNullifierHash: calculateNullifierHash,
691
733
  default: __wbg_init,
734
+ derivedEscrowKey: derivedEscrowKey$1,
692
735
  ecdhEphemeralPublicKey: ecdhEphemeralPublicKey,
693
736
  ecdhEphemeralPublicKeyFromScalarHex: ecdhEphemeralPublicKeyFromScalarHex,
694
737
  ecdhSharedKey: ecdhSharedKey,
695
738
  generateCoin: generateCoin,
696
- generateCoinForDepositWithSharedHex: generateCoinForDepositWithSharedHex,
739
+ generateCoinForDepositWithOwnerPubHex: generateCoinForDepositWithOwnerPubHex,
697
740
  generateCoinFromDepositEphemeralScalarHex: generateCoinFromDepositEphemeralScalarHex,
698
- generateCoinWithSharedSecretHex: generateCoinWithSharedSecretHex,
741
+ generateCoinWithOwnerPubHex: generateCoinWithOwnerPubHex,
699
742
  initSync: initSync,
700
743
  proofToHex: proofToHex,
701
744
  publicToHex: publicToHex
@@ -1531,7 +1574,7 @@ function bytesToHex$1(bytes) {
1531
1574
  }
1532
1575
  return s;
1533
1576
  }
1534
- function concatBytes(a, b) {
1577
+ function concatBytes$1(a, b) {
1535
1578
  const out = new Uint8Array(a.length + b.length);
1536
1579
  out.set(a, 0);
1537
1580
  out.set(b, a.length);
@@ -1547,7 +1590,7 @@ function encodeStealthAddress(decoded) {
1547
1590
  if (xb.length !== yb.length) {
1548
1591
  throw new Error('stealth-address: x and y must encode the same number of bytes for a reversible address');
1549
1592
  }
1550
- const payload = concatBytes(xb, yb);
1593
+ const payload = concatBytes$1(xb, yb);
1551
1594
  const words = bech32.toWords(payload);
1552
1595
  return bech32.encode(STEALTH_ADDRESS_HRP, words, BECH32_STEALTH_LIMIT);
1553
1596
  }
@@ -1572,12 +1615,165 @@ function decodeStealthAddress(address) {
1572
1615
 
1573
1616
  /** Default nonce when deriving the wallet sign-in message. */
1574
1617
  const DEFAULT_STEALTH_SIGN_NONCE = 'main address';
1618
+ /** Domain tag mixed into the spend-scalar digest (H6). */
1619
+ const SPEND_SCALAR_DOMAIN_TAG = 'privacy-pool-spend-scalar-v1';
1620
+ /** Schema version bound into the spend-scalar message and digest. */
1621
+ const OWNER_BOUND_NOTE_SCHEMA_VERSION = 1;
1622
+ function resolveSpendScalarSchemaVersion(domain) {
1623
+ return domain.schemaVersion ?? OWNER_BOUND_NOTE_SCHEMA_VERSION;
1624
+ }
1575
1625
  /**
1576
- * Plaintext for Stellar wallet message signing (stealth address derivation).
1626
+ * Plaintext for Stellar wallet message signing (spend-key derivation).
1577
1627
  * Sign the exact bytes of this string (UTF-8) with the stellar account key.
1628
+ *
1629
+ * The derived scalar is the owner-bound spend key for notes in this environment.
1630
+ */
1631
+ function buildStealthAddressSignMessage(address, domain, nonce = DEFAULT_STEALTH_SIGN_NONCE) {
1632
+ const schemaVersion = resolveSpendScalarSchemaVersion(domain);
1633
+ return [
1634
+ 'Arcane privacy layer: derive your private-note spend key.',
1635
+ '',
1636
+ `Wallet: ${address}`,
1637
+ `Network: ${domain.networkPassphrase}`,
1638
+ `Pool: ${domain.poolContract}`,
1639
+ `Registry: ${domain.registryContract}`,
1640
+ `Schema: owner-bound-note-v${schemaVersion}`,
1641
+ `Nonce: ${nonce}`,
1642
+ '',
1643
+ 'This signature derives the key that authorizes spending your private notes in this environment.',
1644
+ ].join('\n');
1645
+ }
1646
+
1647
+ const DOM_PADDING = 1347436868n;
1648
+ const DOM_NULLIFIER = 1346917708n;
1649
+ const DOM_ESCROW = 1346720579n;
1650
+ const DOM_ENC = 1346719299n;
1651
+ const BABYJUB_SUBGROUP_ORDER = 2736030358979909402780800718157159386076813972158567259200215660948447373041n;
1652
+ /**
1653
+ * Map any integer into `(0, l)` so it satisfies circom `LessThan(252)` vs
1654
+ * `BABYJUB_SUBGROUP_ORDER` and `BabyPbk`. Values already in range are unchanged.
1655
+ */
1656
+ function canonicalBabyJubScalarFromInteger(value) {
1657
+ if (value > 0n && value < BABYJUB_SUBGROUP_ORDER) {
1658
+ return value;
1659
+ }
1660
+ return (value % (BABYJUB_SUBGROUP_ORDER - 1n)) + 1n;
1661
+ }
1662
+
1663
+ function hexToBytes(hex) {
1664
+ const out = new Uint8Array(hex.length / 2);
1665
+ for (let i = 0; i < out.length; i++) {
1666
+ out[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
1667
+ }
1668
+ return out;
1669
+ }
1670
+ /** Base64 → bytes via `atob` (browsers; Node 16+). No Node `Buffer`. */
1671
+ function decodeBase64ToBytes(s) {
1672
+ const t = s.replace(/\s/g, '');
1673
+ if (typeof atob !== 'function') {
1674
+ throw new Error('Base64 decoding requires atob (browser or Node 16+)');
1675
+ }
1676
+ try {
1677
+ const binary = atob(t);
1678
+ const out = new Uint8Array(binary.length);
1679
+ for (let i = 0; i < binary.length; i++) {
1680
+ out[i] = binary.charCodeAt(i);
1681
+ }
1682
+ return out;
1683
+ }
1684
+ catch {
1685
+ throw new Error('Invalid base64 signature');
1686
+ }
1687
+ }
1688
+ /**
1689
+ * Ed25519 signature as **128 hex chars** (optional `0x`) or **base64** (typically 88 chars for 64 bytes, whitespace ignored).
1690
+ */
1691
+ function parseStellarEd25519SignatureRaw(input) {
1692
+ const trimmed = input.trim();
1693
+ const no0x = trimmed.replace(/^0x/i, '');
1694
+ if (/^[0-9a-fA-F]+$/.test(no0x) && no0x.length === 128) {
1695
+ return hexToBytes(no0x.toLowerCase());
1696
+ }
1697
+ const fromB64 = decodeBase64ToBytes(trimmed);
1698
+ if (fromB64.length !== 64) {
1699
+ throw new Error(`Decoded signature must be 64 bytes (Ed25519); got ${fromB64.length} from base64`);
1700
+ }
1701
+ return fromB64;
1702
+ }
1703
+ /** SHA-256 via Web Crypto only (`crypto.subtle`) — works in browsers and Node 19+ (global `crypto`). */
1704
+ async function sha256$1(data) {
1705
+ const subtle = globalThis.crypto?.subtle;
1706
+ if (!subtle) {
1707
+ throw new Error('SHA-256 requires crypto.subtle (HTTPS or localhost in browsers, or Node.js 19+).');
1708
+ }
1709
+ const copy = new Uint8Array(data.length);
1710
+ copy.set(data);
1711
+ return new Uint8Array(await subtle.digest('SHA-256', copy));
1712
+ }
1713
+ function appendU32BE$1(parts, value) {
1714
+ const buf = new Uint8Array(4);
1715
+ new DataView(buf.buffer).setUint32(0, value >>> 0, false);
1716
+ parts.push(buf);
1717
+ }
1718
+ function appendUtf8Prefixed(parts, text) {
1719
+ const bytes = new TextEncoder().encode(text);
1720
+ appendU32BE$1(parts, bytes.length);
1721
+ parts.push(bytes);
1722
+ }
1723
+ function concatBytes(parts) {
1724
+ const total = parts.reduce((sum, part) => sum + part.length, 0);
1725
+ const out = new Uint8Array(total);
1726
+ let offset = 0;
1727
+ for (const part of parts) {
1728
+ out.set(part, offset);
1729
+ offset += part.length;
1730
+ }
1731
+ return out;
1732
+ }
1733
+ /**
1734
+ * Domain-separated spend-scalar digest: SHA-256(
1735
+ * SPEND_SCALAR_DOMAIN_TAG || network || pool || registry || schemaVersion || signature
1736
+ * ).
1737
+ */
1738
+ async function spendScalarDigestFromStellarSignature(signature, domain) {
1739
+ const raw = parseStellarEd25519SignatureRaw(signature);
1740
+ const parts = [new TextEncoder().encode(SPEND_SCALAR_DOMAIN_TAG)];
1741
+ appendUtf8Prefixed(parts, domain.networkPassphrase);
1742
+ appendUtf8Prefixed(parts, domain.poolContract);
1743
+ appendUtf8Prefixed(parts, domain.registryContract);
1744
+ appendU32BE$1(parts, resolveSpendScalarSchemaVersion(domain));
1745
+ parts.push(raw);
1746
+ return sha256$1(concatBytes(parts));
1747
+ }
1748
+ function digestToCanonicalScalar(digest) {
1749
+ let v = 0n;
1750
+ for (let i = 0; i < digest.length; i++) {
1751
+ v = (v << 8n) + BigInt(digest[i]);
1752
+ }
1753
+ return canonicalBabyJubScalarFromInteger(v);
1754
+ }
1755
+ function canonicalScalarHex(scalar) {
1756
+ return scalar.toString(16).padStart(64, '0');
1757
+ }
1758
+ async function spendScalarHexFromStellarSignature(signature, domain) {
1759
+ const digest = await spendScalarDigestFromStellarSignature(signature, domain);
1760
+ return canonicalScalarHex(digestToCanonicalScalar(digest));
1761
+ }
1762
+ /**
1763
+ * Stellar Ed25519 signature (hex or base64) → domain-separated SHA-256 → scalar → WASM ECDH.
1764
+ */
1765
+ async function stealthAddressFromStellarSignature(ecdhFromScalarHex, encodeStealth, signature, domain) {
1766
+ const digest = await spendScalarDigestFromStellarSignature(signature, domain);
1767
+ const decoded = ecdhFromScalarHex(canonicalScalarHex(digestToCanonicalScalar(digest)));
1768
+ return encodeStealth(decoded);
1769
+ }
1770
+ /**
1771
+ * Domain-separated SHA-256(signature, network, pool, registry, schema) reduced into
1772
+ * `(0, BabyJub subgroup order)` so `privKeyScalar` matches `BabyPbk` and circom `LessThan(l)`.
1578
1773
  */
1579
- function buildStealthAddressSignMessage(address, nonce = DEFAULT_STEALTH_SIGN_NONCE) {
1580
- 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.`;
1774
+ async function privKeyScalarDecimalFromStellarSignature(signature, domain) {
1775
+ const digest = await spendScalarDigestFromStellarSignature(signature, domain);
1776
+ return digestToCanonicalScalar(digest).toString(10);
1581
1777
  }
1582
1778
 
1583
1779
  const TRANSACTION_N_AUDIT_SLOTS = 4;
@@ -1644,15 +1840,30 @@ function withApplicationIdOnDeposit(deposit, applicationId) {
1644
1840
  function withApplicationIdOnWithdraw(withdraw, applicationId) {
1645
1841
  return { ...withdraw, applicationId };
1646
1842
  }
1843
+ /**
1844
+ * Prefer an explicit key, then `NOTE_AUDIT_PUBLIC_KEY_X`/`_Y` env (decimal Fr),
1845
+ * then the built-in demo key. Used by CLI/`demo.sh` for per-app audit pubkeys.
1846
+ */
1847
+ function resolveAuditPublicKeyFromEnv(auditPublicKey) {
1848
+ if (auditPublicKey) {
1849
+ return auditPublicKey;
1850
+ }
1851
+ const x = process.env.NOTE_AUDIT_PUBLIC_KEY_X?.trim();
1852
+ const y = process.env.NOTE_AUDIT_PUBLIC_KEY_Y?.trim();
1853
+ if (x && y) {
1854
+ return [x, y];
1855
+ }
1856
+ return DEMO_AUDIT_PUBLIC_KEY;
1857
+ }
1647
1858
  function resolveTransactionAuditParams(applicationId, auditPublicKey) {
1648
- return buildUniformAuditParams(applicationId, auditPublicKey ?? DEMO_AUDIT_PUBLIC_KEY);
1859
+ return buildUniformAuditParams(applicationId, resolveAuditPublicKeyFromEnv(auditPublicKey));
1649
1860
  }
1650
1861
 
1651
- /** Matches `Transaction(20, 2, 2, publicNInputs, publicNOutputs, 4, 9)` in `circuits/main.circom`. */
1862
+ /** Matches `Transaction(20, 2, 2, publicNInputs, publicNOutputs, 4, 12, 6)` in `circuits/main.circom`. */
1652
1863
  const TRANSACTION_TREE_DEPTH = 20;
1653
1864
  const TRANSACTION_N_INS = 2;
1654
1865
  const TRANSACTION_N_OUTS = 2;
1655
- const NOTE_AUDIT_LEN$1 = 9;
1866
+ const NOTE_AUDIT_LEN$1 = 12;
1656
1867
  const NOTE_OUTPUT_LEN$1 = 6;
1657
1868
  /** BN254 scalar field modulus (ark `Fr`, circom signals). */
1658
1869
  const BN254_SCALAR_MOD = 21888242871839275222246405745257275088548364400416034343698204186575808495617n;
@@ -1722,6 +1933,12 @@ function randomFrDecimal253() {
1722
1933
  const hex = generateRandomScalarHex32();
1723
1934
  return BigInt(`0x${normalizeHex$1(hex)}`).toString(10);
1724
1935
  }
1936
+ /** Spend-scalar hex in `(0, BabyJub subgroup order)` so dummy withdraws satisfy `LessThan(l)`. */
1937
+ function randomCanonicalBabyJubScalarHex() {
1938
+ const hex = generateRandomScalarHex32();
1939
+ const reduced = canonicalBabyJubScalarFromInteger(BigInt(`0x${normalizeHex$1(hex)}`));
1940
+ return reduced.toString(16).padStart(64, '0');
1941
+ }
1725
1942
  function zerosTreeSiblings() {
1726
1943
  return Array(TRANSACTION_TREE_DEPTH).fill('0');
1727
1944
  }
@@ -1729,14 +1946,20 @@ function dummyWithdraw(wasm) {
1729
1946
  const nullifier = randomFrDecimal();
1730
1947
  const secretHex = generateRandomScalarHex32();
1731
1948
  const secret = (BigInt(`0x${normalizeHex$1(secretHex)}`) % BN254_SCALAR_MOD).toString(10);
1732
- const pt = wasm.ecdhEphemeralPublicKeyFromScalarHex(secretHex);
1949
+ const scalarHex = randomCanonicalBabyJubScalarHex();
1950
+ const privKeyScalar = scalarHexToFrDecimal(scalarHex);
1951
+ const pt = wasm.ecdhEphemeralPublicKeyFromScalarHex(scalarHex);
1733
1952
  return {
1734
1953
  value: '0',
1735
1954
  nullifier,
1736
1955
  secret,
1737
1956
  asset: ['0', '0'],
1738
1957
  applicationId: '0',
1739
- ephemeralKeys: [coordHexToDecimal(pt.x), coordHexToDecimal(pt.y)],
1958
+ ownerPub: [coordHexToDecimal(pt.x), coordHexToDecimal(pt.y)],
1959
+ privKeyScalar,
1960
+ paddingRandom: randomFrDecimal(),
1961
+ escrowNonce: '0',
1962
+ recipientStellar: ['0', '0'],
1740
1963
  stateSiblings: zerosTreeSiblings(),
1741
1964
  stateIndex: '0',
1742
1965
  };
@@ -1753,6 +1976,8 @@ function dummyDeposit(wasm) {
1753
1976
  asset: ['0', '0'],
1754
1977
  applicationId: '0',
1755
1978
  recipientPublicKeys: [coordHexToDecimal(pt.x), coordHexToDecimal(pt.y)],
1979
+ escrowNonce: '0',
1980
+ recipientStellar: ['0', '0'],
1756
1981
  };
1757
1982
  }
1758
1983
  function resolveWithdraw(slot, wasm) {
@@ -1777,12 +2002,19 @@ function buildTransactionWitnessInput(publicParams, publicLegs, withdrawSlots, d
1777
2002
  stateRoot: publicParams.stateRoot,
1778
2003
  withdrawAddressHi: publicParams.withdrawAddressHi,
1779
2004
  withdrawAddressLo: publicParams.withdrawAddressLo,
1780
- privKeyScalar: publicParams.privKeyScalar,
2005
+ escrowRecipientHi: publicParams.escrowRecipientHi ?? '0',
2006
+ escrowRecipientLo: publicParams.escrowRecipientLo ?? '0',
2007
+ sweepOutputOwnerPubX: publicParams.sweepOutputOwnerPubX ?? '0',
2008
+ sweepOutputOwnerPubY: publicParams.sweepOutputOwnerPubY ?? '0',
2009
+ privKeyScalars: [w0.privKeyScalar, w1.privKeyScalar],
2010
+ ownerPubs: [w0.ownerPub, w1.ownerPub],
2011
+ paddingRandoms: [w0.paddingRandom, w1.paddingRandom],
1781
2012
  withdrawnValues: [w0.value, w1.value],
1782
2013
  withdrawnNullifiers: [w0.nullifier, w1.nullifier],
1783
2014
  withdrawnSecrets: [w0.secret, w1.secret],
1784
2015
  withdrawnAssets: [w0.asset, w1.asset],
1785
- ephemeralKeys: [w0.ephemeralKeys, w1.ephemeralKeys],
2016
+ withdrawnEscrowNonces: [w0.escrowNonce, w1.escrowNonce],
2017
+ inputRecipientStellar: [w0.recipientStellar, w1.recipientStellar],
1786
2018
  stateSiblings: [w0.stateSiblings, w1.stateSiblings],
1787
2019
  stateIndex: [w0.stateIndex, w1.stateIndex],
1788
2020
  depositedValues: [d0.value, d1.value],
@@ -1790,6 +2022,11 @@ function buildTransactionWitnessInput(publicParams, publicLegs, withdrawSlots, d
1790
2022
  depositedAssets: [d0.asset, d1.asset],
1791
2023
  depositedEphemeralKeyScalars: [d0.ephemeralKeyScalar, d1.ephemeralKeyScalar],
1792
2024
  depositedRecipientPublicKeys: [d0.recipientPublicKeys, d1.recipientPublicKeys],
2025
+ depositedEscrowNonces: [d0.escrowNonce ?? '0', d1.escrowNonce ?? '0'],
2026
+ outputRecipientStellar: [
2027
+ d0.recipientStellar ?? ['0', '0'],
2028
+ d1.recipientStellar ?? ['0', '0'],
2029
+ ],
1793
2030
  inputApplicationIds: appIds.inputApplicationIds,
1794
2031
  outputApplicationIds: appIds.outputApplicationIds,
1795
2032
  auditEphemeralScalars: audit.auditEphemeralScalars,
@@ -1805,112 +2042,56 @@ function recipientPublicKeysDecimalFromStealthAddress(stealthAddress) {
1805
2042
  const { x, y } = decodeStealthAddress(stealthAddress);
1806
2043
  return [coordHexToDecimal(x), coordHexToDecimal(y)];
1807
2044
  }
1808
- /** First withdraw leg: Merkle witness + depositor ECDH point coordinates (hex). */
1809
- function withdrawObjectFromMerkleWitness(witness, depositorEphemeralHex, applicationId) {
2045
+ /** First withdraw leg: Merkle witness + owner public key (hex) and matching scalar. */
2046
+ function withdrawObjectFromMerkleWitness(witness, ownerPubHex, applicationId, privKeyScalar) {
1810
2047
  return {
1811
2048
  value: witness.value,
1812
2049
  nullifier: witness.nullifier,
1813
2050
  secret: witness.secret,
1814
2051
  asset: witness.withdrawnAsset,
1815
2052
  applicationId,
1816
- ephemeralKeys: [
1817
- coordHexToDecimal(depositorEphemeralHex.x),
1818
- coordHexToDecimal(depositorEphemeralHex.y),
1819
- ],
2053
+ ownerPub: [coordHexToDecimal(ownerPubHex.x), coordHexToDecimal(ownerPubHex.y)],
2054
+ privKeyScalar,
2055
+ paddingRandom: randomFrDecimal(),
2056
+ escrowNonce: '0',
2057
+ recipientStellar: ['0', '0'],
1820
2058
  stateSiblings: witness.stateSiblings,
1821
2059
  stateIndex: witness.stateIndex,
1822
2060
  };
1823
2061
  }
1824
2062
 
1825
- function hexToBytes(hex) {
1826
- const out = new Uint8Array(hex.length / 2);
1827
- for (let i = 0; i < out.length; i++) {
1828
- out[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
1829
- }
1830
- return out;
1831
- }
1832
- function bytesToHexLower(bytes) {
1833
- let s = '';
1834
- for (let i = 0; i < bytes.length; i++) {
1835
- s += bytes[i].toString(16).padStart(2, '0');
2063
+ /** Stroops amount as a decimal field string. Reject JS `number` so 18-decimal values cannot silently narrow. */
2064
+ function coinValueDecimal(amount) {
2065
+ if (typeof amount === 'number') {
2066
+ throw new TypeError('coin value must be bigint or decimal string, not number');
1836
2067
  }
1837
- return s;
1838
- }
1839
- /** Base64 bytes via `atob` (browsers; Node 16+). No Node `Buffer`. */
1840
- function decodeBase64ToBytes(s) {
1841
- const t = s.replace(/\s/g, '');
1842
- if (typeof atob !== 'function') {
1843
- throw new Error('Base64 decoding requires atob (browser or Node 16+)');
1844
- }
1845
- try {
1846
- const binary = atob(t);
1847
- const out = new Uint8Array(binary.length);
1848
- for (let i = 0; i < binary.length; i++) {
1849
- out[i] = binary.charCodeAt(i);
2068
+ if (typeof amount === 'bigint') {
2069
+ if (amount < 0n) {
2070
+ throw new RangeError('amount must be a non-negative integer');
1850
2071
  }
1851
- return out;
1852
- }
1853
- catch {
1854
- throw new Error('Invalid base64 signature');
1855
- }
1856
- }
1857
- /**
1858
- * Ed25519 signature as **128 hex chars** (optional `0x`) or **base64** (typically 88 chars for 64 bytes, whitespace ignored).
1859
- */
1860
- function parseStellarEd25519SignatureRaw(input) {
1861
- const trimmed = input.trim();
1862
- const no0x = trimmed.replace(/^0x/i, '');
1863
- if (/^[0-9a-fA-F]+$/.test(no0x) && no0x.length === 128) {
1864
- return hexToBytes(no0x.toLowerCase());
2072
+ return amount.toString(10);
1865
2073
  }
1866
- const fromB64 = decodeBase64ToBytes(trimmed);
1867
- if (fromB64.length !== 64) {
1868
- throw new Error(`Decoded signature must be 64 bytes (Ed25519); got ${fromB64.length} from base64`);
1869
- }
1870
- return fromB64;
1871
- }
1872
- /** SHA-256 via Web Crypto only (`crypto.subtle`) — works in browsers and Node 19+ (global `crypto`). */
1873
- async function sha256$1(data) {
1874
- const subtle = globalThis.crypto?.subtle;
1875
- if (!subtle) {
1876
- throw new Error('SHA-256 requires crypto.subtle (HTTPS or localhost in browsers, or Node.js 19+).');
2074
+ if (typeof amount !== 'string') {
2075
+ throw new TypeError('coin value must be bigint or decimal string, not number');
1877
2076
  }
1878
- const copy = new Uint8Array(data.length);
1879
- copy.set(data);
1880
- return new Uint8Array(await subtle.digest('SHA-256', copy));
1881
- }
1882
- /**
1883
- * Stellar Ed25519 signature (hex or base64) → SHA-256(signature bytes) → scalar → WASM ECDH (no UTF-8 seed hash).
1884
- */
1885
- async function stealthAddressFromStellarSignature(ecdhFromScalarHex, encodeStealth, signature) {
1886
- const raw = parseStellarEd25519SignatureRaw(signature);
1887
- const scalar = await sha256$1(raw);
1888
- const scalarHex = bytesToHexLower(scalar);
1889
- const decoded = ecdhFromScalarHex(scalarHex);
1890
- return encodeStealth(decoded);
1891
- }
1892
- /**
1893
- * SHA-256(signature) as 32-byte BE integer, truncated to **253 bits** (same effective scalar as
1894
- * `libs/cryptography` `scalar_mul_253` / circom `Num2Bits(253)`), decimal for `privKeyScalar`.
1895
- */
1896
- async function privKeyScalarDecimalFromStellarSignature(signature) {
1897
- const raw = parseStellarEd25519SignatureRaw(signature);
1898
- const h = await sha256$1(raw);
1899
- let v = 0n;
1900
- for (let i = 0; i < h.length; i++) {
1901
- v = (v << 8n) + BigInt(h[i]);
2077
+ const trimmed = amount.trim();
2078
+ if (!/^[0-9]+$/.test(trimmed)) {
2079
+ throw new TypeError('coin value decimal string must be a non-negative integer');
1902
2080
  }
1903
- const mask = BN254_BABYJUB_SCALAR_MAX_EXCLUSIVE - 1n;
1904
- return (v & mask).toString(10);
2081
+ return trimmed;
1905
2082
  }
1906
-
1907
- /** Stroops amount as WASM `u64` (`bigint`). */
1908
- function wasmU64Stroops(amount) {
1909
- const b = typeof amount === 'bigint' ? amount : BigInt(amount);
1910
- if (b < 0n || b > 0xffffffffffffffffn) {
1911
- throw new RangeError('amount must be a non-negative u64 (stroops)');
2083
+ function generatedCoinFromWasm(value) {
2084
+ const raw = value;
2085
+ const precommitementHex = raw.precommitementHex ?? raw.precommitement_hex;
2086
+ if (!precommitementHex) {
2087
+ throw new Error('generated coin missing precommitement hex');
1912
2088
  }
1913
- return b;
2089
+ return {
2090
+ coin: raw.coin,
2091
+ commitment_hex: raw.commitment_hex,
2092
+ precommitement_hex: precommitementHex,
2093
+ precommitementHex,
2094
+ };
1914
2095
  }
1915
2096
  class PrivacyPoolSDK {
1916
2097
  constructor(wasm, options) {
@@ -1942,39 +2123,40 @@ class PrivacyPoolSDK {
1942
2123
  return generateRandomScalarHex32();
1943
2124
  }
1944
2125
  /**
1945
- * Text to sign with a Stellar wallet for stealth derivation (UTF-8). No WASM required.
2126
+ * Text to sign with a Stellar wallet for spend-key derivation (UTF-8). No WASM required.
2127
+ * The message binds network, pool, registry, and schema version (H6).
1946
2128
  */
1947
- static buildStealthAddressSignMessage(address, nonce = DEFAULT_STEALTH_SIGN_NONCE) {
1948
- return buildStealthAddressSignMessage(address, nonce);
2129
+ static buildStealthAddressSignMessage(address, domain, nonce = DEFAULT_STEALTH_SIGN_NONCE) {
2130
+ return buildStealthAddressSignMessage(address, domain, nonce);
1949
2131
  }
1950
2132
  /**
1951
- * Generate a new coin with random nullifier, secret, and random shared-secret field elements (dev / self-contained tests).
1952
- * @param amount Stroops encoded as `bigint` or integer `number` (WASM `u64`).
2133
+ * Generate a new coin with random nullifier, secret, and random owner-pub field elements (dev / self-contained tests).
2134
+ * @param amount Decimal field element as `bigint` or decimal `string` (never JS `number`).
1953
2135
  * @param assetHiDecimal / assetLoDecimal Decimal Fr strings for Stellar asset contract id (two limbs).
1954
2136
  */
1955
2137
  generateCoin(amount, assetHiDecimal, assetLoDecimal, applicationIdDecimal = '0') {
1956
- return this.wasm.generateCoin(wasmU64Stroops(amount), assetHiDecimal, assetLoDecimal, applicationIdDecimal);
2138
+ return generatedCoinFromWasm(this.wasm.generateCoin(coinValueDecimal(amount), assetHiDecimal, assetLoDecimal, applicationIdDecimal));
1957
2139
  }
1958
2140
  /**
1959
- * Generate a coin with the same commitment shape as on-chain deposit: pass `ecdhSharedKey` output (hex x, y).
1960
- * @param amount Stroops (`bigint` | `number`).
2141
+ * Generate a coin with the same commitment shape as on-chain deposit: pass owner public key (hex x, y).
2142
+ * @param amount Decimal field element (`bigint` | `string`).
1961
2143
  */
1962
- generateCoinWithSharedSecret(shared, amount, assetHiDecimal, assetLoDecimal, applicationIdDecimal = '0') {
1963
- return this.wasm.generateCoinWithSharedSecretHex(shared.x, shared.y, wasmU64Stroops(amount), assetHiDecimal, assetLoDecimal, applicationIdDecimal);
2144
+ generateCoinWithOwnerPub(ownerPub, amount, assetHiDecimal, assetLoDecimal, applicationIdDecimal = '0') {
2145
+ return generatedCoinFromWasm(this.wasm.generateCoinWithOwnerPubHex(ownerPub.x, ownerPub.y, coinValueDecimal(amount), assetHiDecimal, assetLoDecimal, applicationIdDecimal));
1964
2146
  }
1965
2147
  /**
1966
2148
  * Coin for a depositor `ephemeralKeyScalar` (32-byte hex): `coin.secret = Poseidon255(1)(scalar)` as in `deposit.circom`.
1967
- * @param amount Stroops (`bigint` | `number`).
2149
+ * @param amount Decimal field element (`bigint` | `string`).
1968
2150
  */
1969
2151
  generateCoinFromDepositEphemeralScalarHex(scalarHex, amount, assetHiDecimal, assetLoDecimal, applicationIdDecimal = '0') {
1970
- return this.wasm.generateCoinFromDepositEphemeralScalarHex(scalarHex, wasmU64Stroops(amount), assetHiDecimal, assetLoDecimal, applicationIdDecimal);
2152
+ return generatedCoinFromWasm(this.wasm.generateCoinFromDepositEphemeralScalarHex(scalarHex, coinValueDecimal(amount), assetHiDecimal, assetLoDecimal, applicationIdDecimal));
1971
2153
  }
1972
2154
  /**
1973
- * Aligned deposit coin: `secret = Poseidon₁(scalar)` and ECDH shared key from hex coords (e.g. `ecdhSharedKey(scalar, recipient_x, recipient_y)`).
1974
- * @param amount Stroops (`bigint` | `number`).
2155
+ * Aligned deposit coin: `secret = Poseidon₁(scalar)` and owner pub from recipient hex coords.
2156
+ * @param amount Decimal field element (`bigint` | `string`).
1975
2157
  */
1976
- generateCoinForDepositWithSharedHex(scalarHex, sharedXHex, sharedYHex, amount, assetHiDecimal, assetLoDecimal, applicationIdDecimal = '0') {
1977
- return this.wasm.generateCoinForDepositWithSharedHex(scalarHex, sharedXHex, sharedYHex, wasmU64Stroops(amount), assetHiDecimal, assetLoDecimal, applicationIdDecimal);
2158
+ generateCoinForDepositWithOwnerPubHex(scalarHex, ownerXHex, ownerYHex, amount, assetHiDecimal, assetLoDecimal, applicationIdDecimal = '0') {
2159
+ return generatedCoinFromWasm(this.wasm.generateCoinForDepositWithOwnerPubHex(scalarHex, ownerXHex, ownerYHex, coinValueDecimal(amount), assetHiDecimal, assetLoDecimal, applicationIdDecimal));
1978
2160
  }
1979
2161
  /**
1980
2162
  * Merkle root, path, and coin fields for the first withdraw leg (Rust LeanIMT + Poseidon).
@@ -1993,10 +2175,8 @@ class PrivacyPoolSDK {
1993
2175
  */
1994
2176
  async proveWithdrawal(coin, state, params) {
1995
2177
  const witness = this.buildWithdrawMerkleWitness(coin, state);
1996
- const w0 = withdrawObjectFromMerkleWitness(witness, {
1997
- x: params.ephemeralXHex,
1998
- y: params.ephemeralYHex,
1999
- }, params.applicationId ?? coin.application_id ?? '0');
2178
+ const ownerPubHex = this.ecdhEphemeralPublicKeyFromScalarHex(BigInt(params.privKeyScalar).toString(16).padStart(64, '0'));
2179
+ const w0 = withdrawObjectFromMerkleWitness(witness, ownerPubHex, params.applicationId ?? coin.application_id ?? '0', params.privKeyScalar);
2000
2180
  const fullV = BigInt(coin.value);
2001
2181
  let publicWithdrawals;
2002
2182
  let deposits;
@@ -2082,19 +2262,20 @@ class PrivacyPoolSDK {
2082
2262
  };
2083
2263
  }
2084
2264
  /**
2085
- * Calculate nullifier hash: Poseidon(nullifier)
2265
+ * Calculate owner-bound nullifier hash: Poseidon(DOM_NULLIFIER, nullifier, privKeyScalar)
2086
2266
  * @param nullifier Nullifier decimal string from coin data
2267
+ * @param privKeyScalar Spend scalar decimal string
2087
2268
  * @returns Hex string (0x...) of the hash bytes
2088
2269
  */
2089
- calculateNullifierHash(nullifier) {
2090
- return this.wasm.calculateNullifierHash(nullifier);
2270
+ calculateNullifierHash(nullifier, privKeyScalar) {
2271
+ return this.wasm.calculateNullifierHash(nullifier, privKeyScalar);
2091
2272
  }
2092
2273
  /**
2093
2274
  * Ed25519 signature from signing {@link buildStealthAddressSignMessage}: **128 hex chars** (optional `0x`)
2094
- * or **base64** (64 raw bytes after decode). `SHA-256(signature bytes)` → scalar → ECDH → `stpl1` Bech32.
2275
+ * or **base64** (64 raw bytes after decode). Domain-separated SHA-256 → scalar → ECDH → `stpl1` Bech32.
2095
2276
  */
2096
- async generateStealthAddressFromStellarSignature(signature) {
2097
- return stealthAddressFromStellarSignature((h) => this.wasm.ecdhEphemeralPublicKeyFromScalarHex(h), encodeStealthAddress, signature);
2277
+ async generateStealthAddressFromStellarSignature(signature, domain) {
2278
+ return stealthAddressFromStellarSignature((h) => this.wasm.ecdhEphemeralPublicKeyFromScalarHex(h), encodeStealthAddress, signature, domain);
2098
2279
  }
2099
2280
  encodeDecodedEphemeralKey(decoded) {
2100
2281
  return encodeDecodedEphemeralKey(decoded);
@@ -2121,6 +2302,20 @@ const POOL_MERKLE_TREE_DEPTH = 20;
2121
2302
  /** Default coin value in stroops (1 XLM); matches Rust `coin::COIN_VALUE`. */
2122
2303
  const COIN_VALUE_STROOPS = 1000000000;
2123
2304
 
2305
+ // Split a JS number into u32 halves without a BigInt allocation. Exact only for integers
2306
+ // `0 <= n < 2**53`; callers use it on byte / bit counters, which JS length math caps far below
2307
+ // that (an ArrayBuffer cannot exceed 2**53 - 1 bytes).
2308
+ const fromNumH = (n) => (n / 2 ** 32) | 0;
2309
+ const fromNumL = (n) => n >>> 0;
2310
+ // Drop-in replacement for `view.setBigUint64(byteOffset, BigInt(n), isLE)` without the per-call
2311
+ // BigInt allocation. Same `n < 2**53` precondition as `fromNumH`/`fromNumL`.
2312
+ function setU64FromNum(view, byteOffset, n, isLE) {
2313
+ const h = fromNumH(n);
2314
+ const l = fromNumL(n);
2315
+ view.setUint32(byteOffset, isLE ? l : h, isLE);
2316
+ view.setUint32(byteOffset + 4, isLE ? h : l, isLE);
2317
+ }
2318
+
2124
2319
  /**
2125
2320
  * Checks if something is Uint8Array. Be careful: nodejs Buffer will return true.
2126
2321
  * @param a - value to test
@@ -2142,6 +2337,9 @@ function isBytes(a) {
2142
2337
  'BYTES_PER_ELEMENT' in a &&
2143
2338
  a.BYTES_PER_ELEMENT === 1));
2144
2339
  }
2340
+ // Shared error-message prefix builder. Only called on throw paths, so assert
2341
+ // success paths never pay for the string concatenation.
2342
+ const atitle = (title) => (title ? `"${title}" ` : '');
2145
2343
  /**
2146
2344
  * Asserts something is Uint8Array.
2147
2345
  * @param value - value to validate
@@ -2157,20 +2355,32 @@ function isBytes(a) {
2157
2355
  * ```
2158
2356
  */
2159
2357
  function abytes(value, length, title = '') {
2358
+ // Success path first: this runs at the start of every update() / digestInto(), and the
2359
+ // common `abytes(data)` form must not pay for length handling it does not use.
2360
+ if (isBytes(value) && (length === undefined))
2361
+ return value;
2160
2362
  const bytes = isBytes(value);
2161
- const len = value?.length;
2162
- const needsLen = length !== undefined;
2163
- if (!bytes || (needsLen)) {
2164
- const prefix = title && `"${title}" `;
2165
- const ofLen = '';
2166
- const got = bytes ? `length=${len}` : `type=${typeof value}`;
2167
- const message = prefix + 'expected Uint8Array' + ofLen + ', got ' + got;
2168
- if (!bytes)
2169
- throw new TypeError(message);
2170
- throw new RangeError(message);
2171
- }
2172
- return value;
2173
- }
2363
+ const ofLen = '';
2364
+ const got = bytes ? `length=${value.length}` : `type=${typeof value}`;
2365
+ const message = atitle(title) + 'expected Uint8Array' + ofLen + ', got ' + got;
2366
+ if (!bytes)
2367
+ throw new TypeError(message);
2368
+ throw new RangeError(message);
2369
+ }
2370
+ const aobject = (value, label) => {
2371
+ if (value === null || typeof value !== 'object' || Array.isArray(value))
2372
+ throw new TypeError((label === 'object' ? '' : `"${label}" `) + 'expected object, got type=' + typeof value);
2373
+ };
2374
+ const aopts = (value, label) => {
2375
+ aobject(value, label);
2376
+ const proto = Object.getPrototypeOf(value);
2377
+ if (proto !== Object.prototype && proto !== null)
2378
+ throw new TypeError(`"${label}" expected plain object`);
2379
+ // Object.assign() treats an own "__proto__" source key as a write to the target's legacy
2380
+ // prototype setter. Reject it before merging so inherited option values cannot be injected.
2381
+ if (Object.hasOwn(value, '__proto__'))
2382
+ throw new TypeError(`"${label}.__proto__" is not allowed`);
2383
+ };
2174
2384
  /**
2175
2385
  * Asserts a hash instance has not been destroyed or finished.
2176
2386
  * @param instance - hash instance to validate
@@ -2186,10 +2396,12 @@ function abytes(value, length, title = '') {
2186
2396
  * ```
2187
2397
  */
2188
2398
  function aexists(instance, checkFinished = true) {
2399
+ // Runs on every update()/digestInto(); the flags are library-owned booleans, so only their
2400
+ // truthiness is checked - re-validating their type per call was pure hot-path overhead.
2189
2401
  if (instance.destroyed)
2190
- throw new Error('Hash instance has been destroyed');
2402
+ throw new Error('hash was destroyed');
2191
2403
  if (checkFinished && instance.finished)
2192
- throw new Error('Hash#digest() has already been called');
2404
+ throw new Error('digest() was already called');
2193
2405
  }
2194
2406
  /**
2195
2407
  * Asserts output is a sufficiently-sized byte array.
@@ -2208,10 +2420,12 @@ function aexists(instance, checkFinished = true) {
2208
2420
  * ```
2209
2421
  */
2210
2422
  function aoutput(out, instance) {
2211
- abytes(out, undefined, 'digestInto() output');
2423
+ abytes(out, undefined, 'output');
2424
+ // `outputLen` is a library-owned readonly number; the negated comparison keeps failing fast
2425
+ // when it is missing/NaN (comparisons with undefined/NaN are false) without an anumber() call.
2212
2426
  const min = instance.outputLen;
2213
- if (out.length < min) {
2214
- throw new RangeError('"digestInto() output" expected to be of length >=' + min);
2427
+ if (!(out.length >= min)) {
2428
+ throw new RangeError('"output" expected length >= ' + min);
2215
2429
  }
2216
2430
  }
2217
2431
  /**
@@ -2286,6 +2500,28 @@ function bytesToHex(bytes) {
2286
2500
  }
2287
2501
  return hex;
2288
2502
  }
2503
+ /**
2504
+ * Merges default options and passed options.
2505
+ * @param defaults - base option object
2506
+ * @param opts - user overrides
2507
+ * @param title - label included in thrown override errors
2508
+ * @returns Fresh merged option object with a null prototype.
2509
+ * @throws On wrong argument types. {@link TypeError}
2510
+ * @example
2511
+ * Merge user overrides onto default options.
2512
+ * ```ts
2513
+ * checkOpts({ dkLen: 32 }, { asyncTick: 10 });
2514
+ * ```
2515
+ */
2516
+ function checkOpts(defaults, opts, title = 'opts') {
2517
+ aopts(defaults, 'defaults');
2518
+ if (opts !== undefined)
2519
+ aopts(opts, title);
2520
+ // Callers read optional fields directly, so omitted values must not fall through to ambient
2521
+ // Object.prototype pollution (for example a forged `dkLen` changing SHAKE's default output).
2522
+ const merged = Object.assign(Object.create(null), defaults, opts);
2523
+ return merged;
2524
+ }
2289
2525
  /**
2290
2526
  * Creates a callable hash function from a stateful class constructor.
2291
2527
  * @param hashCons - hash constructor or factory
@@ -2294,6 +2530,7 @@ function bytesToHex(bytes) {
2294
2530
  * Wrapper construction eagerly calls `hashCons(undefined)` once to read
2295
2531
  * `outputLen` / `blockLen`, so constructor side effects happen at module
2296
2532
  * init time.
2533
+ * @throws On wrong argument types. {@link TypeError}
2297
2534
  * @example
2298
2535
  * Wrap a stateful hash constructor into a callable helper.
2299
2536
  * ```ts
@@ -2304,6 +2541,9 @@ function bytesToHex(bytes) {
2304
2541
  * ```
2305
2542
  */
2306
2543
  function createHasher(hashCons, info = {}) {
2544
+ if (typeof hashCons !== 'function')
2545
+ throw new TypeError('"hashCons" expected function, got type=' + typeof hashCons);
2546
+ info = checkOpts({}, info, 'info');
2307
2547
  const hashC = (msg, opts) => hashCons(opts)
2308
2548
  .update(msg)
2309
2549
  .digest();
@@ -2415,6 +2655,7 @@ class HashMD {
2415
2655
  abytes(data);
2416
2656
  const { view, buffer, blockLen } = this;
2417
2657
  const len = data.length;
2658
+ let processed = false;
2418
2659
  for (let pos = 0; pos < len;) {
2419
2660
  const take = Math.min(blockLen - this.pos, len - pos);
2420
2661
  // Fast path only when there is no buffered partial block: `take === blockLen` implies
@@ -2423,18 +2664,25 @@ class HashMD {
2423
2664
  const dataView = createView(data);
2424
2665
  for (; blockLen <= len - pos; pos += blockLen)
2425
2666
  this.process(dataView, pos);
2667
+ processed = true;
2426
2668
  continue;
2427
2669
  }
2428
- buffer.set(data.subarray(pos, pos + take), this.pos);
2670
+ // When the whole input is buffered in one go (common for short messages), passing `data`
2671
+ // directly avoids allocating a subarray view.
2672
+ buffer.set(pos === 0 && take === len ? data : data.subarray(pos, pos + take), this.pos);
2429
2673
  this.pos += take;
2430
2674
  pos += take;
2431
2675
  if (this.pos === blockLen) {
2432
2676
  this.process(view, 0);
2433
2677
  this.pos = 0;
2678
+ processed = true;
2434
2679
  }
2435
2680
  }
2436
2681
  this.length += data.length;
2437
- this.roundClean();
2682
+ // Shared schedule buffers only pick up input-derived words inside process(); if everything
2683
+ // was buffered without processing, there is nothing to zero.
2684
+ if (processed)
2685
+ this.roundClean();
2438
2686
  return this;
2439
2687
  }
2440
2688
  digestInto(out) {
@@ -2446,32 +2694,33 @@ class HashMD {
2446
2694
  // was previously not allocated here. But it won't change performance.
2447
2695
  const { buffer, view, blockLen, isLE } = this;
2448
2696
  let { pos } = this;
2449
- // append the bit '1' to the message
2697
+ // append the bit '1' to the message, then zero-pad the rest of the block
2450
2698
  buffer[pos++] = 0b10000000;
2451
- clean(this.buffer.subarray(pos));
2699
+ buffer.fill(0, pos);
2452
2700
  // we have less than padOffset left in buffer, so we cannot put length in
2453
2701
  // current block, need process it and pad again
2454
2702
  if (this.padOffset > blockLen - pos) {
2455
2703
  this.process(view, 0);
2456
- pos = 0;
2704
+ buffer.fill(0);
2457
2705
  }
2458
- // Pad until full block byte with zeros
2459
- for (let i = pos; i < blockLen; i++)
2460
- buffer[i] = 0;
2461
2706
  // `padOffset` reserves the whole length field. For SHA-384/512 the high 64 bits stay zero from
2462
2707
  // the padding fill above, and JS will overflow before user input can make that half non-zero.
2463
- // So we only need to write the low 64 bits here.
2464
- view.setBigUint64(blockLen - 8, BigInt(this.length * 8), isLE);
2708
+ // So we only need to write the low 64 bits here (`length * 8` only scales the exponent of an
2709
+ // integer below 2**53, so the split inside the helper stays exact).
2710
+ setU64FromNum(view, blockLen - 8, this.length * 8, isLE);
2465
2711
  this.process(view, 0);
2466
- const oview = createView(out);
2712
+ // The final block above is processed outside update(), so the shared message-schedule
2713
+ // buffers (e.g. SHA256_W) would otherwise retain input-derived words after digest().
2714
+ this.roundClean();
2715
+ // digest() passes our own `buffer` as `out`; reuse its cached view instead of allocating one.
2716
+ const oview = out === buffer ? view : createView(out);
2467
2717
  const len = this.outputLen;
2468
2718
  // NOTE: we do division by 4 later, which must be fused in single op with modulo by JIT
2469
- if (len % 4)
2470
- throw new Error('_sha2: outputLen must be aligned to 32bit');
2471
2719
  const outLen = len / 4;
2472
2720
  const state = this.get();
2473
- if (outLen > state.length)
2474
- throw new Error('_sha2: outputLen bigger than state');
2721
+ // Subclass-misconfiguration invariant: outputLen must be 32-bit aligned and fit the state.
2722
+ if (len % 4 || outLen > state.length)
2723
+ throw new Error('invalid outputLen');
2475
2724
  for (let i = 0; i < outLen; i++)
2476
2725
  oview.setUint32(4 * i, state[i], isLE);
2477
2726
  }
@@ -2484,18 +2733,16 @@ class HashMD {
2484
2733
  this.destroy();
2485
2734
  return res;
2486
2735
  }
2487
- _cloneInto(to) {
2488
- to ||= new this.constructor();
2489
- to.set(...this.get());
2490
- const { blockLen, buffer, length, finished, destroyed, pos } = this;
2736
+ _cloneIntoMeta(to) {
2737
+ const { buffer, length, finished, destroyed, pos } = this;
2491
2738
  to.destroyed = destroyed;
2492
2739
  to.finished = finished;
2493
2740
  to.length = length;
2494
2741
  to.pos = pos;
2495
2742
  // Only partial-block bytes need copying: when `length % blockLen === 0`, `pos === 0` and
2496
2743
  // later `update()` / `digestInto()` overwrite `to.buffer` from the start before reading it.
2497
- if (length % blockLen)
2498
- to.buffer.set(buffer);
2744
+ if (pos)
2745
+ to.buffer.set(buffer); // Avoid a hot modulo guard.
2499
2746
  return to;
2500
2747
  }
2501
2748
  clone() {
@@ -2539,8 +2786,28 @@ const SHA256_K = /* @__PURE__ */ Uint32Array.from([
2539
2786
  const SHA256_W = /* @__PURE__ */ new Uint32Array(64);
2540
2787
  /** Internal SHA-224 / SHA-256 compression engine from RFC 6234 §6.2. */
2541
2788
  class SHA2_32B extends HashMD {
2542
- constructor(outputLen) {
2789
+ // We cannot use array here since array allows indexing by variable
2790
+ // which means optimizer/compiler cannot use registers.
2791
+ // Numeric initializers matter: starting the fields as `undefined` changes
2792
+ // V8's field representation and makes sha256 3x slower (measured).
2793
+ A = 0;
2794
+ B = 0;
2795
+ C = 0;
2796
+ D = 0;
2797
+ E = 0;
2798
+ F = 0;
2799
+ G = 0;
2800
+ H = 0;
2801
+ constructor(outputLen, IV) {
2543
2802
  super(64, outputLen, 8, false);
2803
+ this.A = IV[0] | 0;
2804
+ this.B = IV[1] | 0;
2805
+ this.C = IV[2] | 0;
2806
+ this.D = IV[3] | 0;
2807
+ this.E = IV[4] | 0;
2808
+ this.F = IV[5] | 0;
2809
+ this.G = IV[6] | 0;
2810
+ this.H = IV[7] | 0;
2544
2811
  }
2545
2812
  get() {
2546
2813
  const { A, B, C, D, E, F, G, H } = this;
@@ -2557,6 +2824,10 @@ class SHA2_32B extends HashMD {
2557
2824
  this.G = G | 0;
2558
2825
  this.H = H | 0;
2559
2826
  }
2827
+ _cloneInto(to) {
2828
+ (to ||= new this.constructor()).set(...this.get());
2829
+ return this._cloneIntoMeta(to);
2830
+ }
2560
2831
  process(view, offset) {
2561
2832
  // Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array
2562
2833
  for (let i = 0; i < 16; i++, offset += 4)
@@ -2608,18 +2879,8 @@ class SHA2_32B extends HashMD {
2608
2879
  }
2609
2880
  /** Internal SHA-256 hash class grounded in RFC 6234 §6.2. */
2610
2881
  class _SHA256 extends SHA2_32B {
2611
- // We cannot use array here since array allows indexing by variable
2612
- // which means optimizer/compiler cannot use registers.
2613
- A = SHA256_IV[0] | 0;
2614
- B = SHA256_IV[1] | 0;
2615
- C = SHA256_IV[2] | 0;
2616
- D = SHA256_IV[3] | 0;
2617
- E = SHA256_IV[4] | 0;
2618
- F = SHA256_IV[5] | 0;
2619
- G = SHA256_IV[6] | 0;
2620
- H = SHA256_IV[7] | 0;
2621
2882
  constructor() {
2622
- super(32);
2883
+ super(32, SHA256_IV);
2623
2884
  }
2624
2885
  }
2625
2886
  /**
@@ -2630,6 +2891,7 @@ class _SHA256 extends SHA2_32B {
2630
2891
  * - Each sha256 hash is executing 2^18 bit operations.
2631
2892
  * - Good 2024 ASICs can do 200Th/sec with 3500 watts of power, corresponding to 2^36 hashes/joule.
2632
2893
  * @param msg - message bytes to hash
2894
+ * @param opts - Reserved hash options.
2633
2895
  * @returns Digest bytes.
2634
2896
  * @example
2635
2897
  * Hash a message with SHA2-256.
@@ -2640,121 +2902,16 @@ class _SHA256 extends SHA2_32B {
2640
2902
  const sha256 = /* @__PURE__ */ createHasher(() => new _SHA256(),
2641
2903
  /* @__PURE__ */ oidNist(0x01));
2642
2904
 
2643
- const ONBOARDING_ZERO_DOMAIN = 'privacy-pool-onboarding-zero-v1';
2644
- function sha256Hex$1(data) {
2645
- return bytesToHex(sha256(data));
2646
- }
2647
- function appendU8$1(parts, value) {
2648
- parts.push(Buffer.from([value & 0xff]));
2649
- }
2650
- function appendU32BE$1(parts, value) {
2651
- const buf = Buffer.alloc(4);
2652
- buf.writeUInt32BE(value >>> 0);
2653
- parts.push(buf);
2654
- }
2655
- function appendU128BE$1(parts, value) {
2656
- const buf = Buffer.alloc(16);
2657
- buf.writeBigUInt64BE(value >> 64n, 0);
2658
- buf.writeBigUInt64BE(value & ((1n << 64n) - 1n), 8);
2659
- parts.push(buf);
2660
- }
2661
- function appendAddressStrkey$1(parts, address) {
2662
- const bytes = Buffer.from(address.trim(), 'utf8');
2663
- appendU32BE$1(parts, bytes.length);
2664
- parts.push(bytes);
2665
- }
2666
- function appendBytes32$1(parts, value) {
2667
- if (value.length !== 32) {
2668
- throw new Error(`expected 32-byte field, got ${value.length}`);
2669
- }
2670
- parts.push(value);
2671
- }
2672
- function appendBytesBlob(parts, data) {
2673
- appendU32BE$1(parts, data.length);
2674
- parts.push(data);
2675
- }
2676
- function encodePlaintextNote(parts, note) {
2677
- appendU128BE$1(parts, note.value);
2678
- appendBytes32$1(parts, note.asset_hi);
2679
- appendBytes32$1(parts, note.asset_lo);
2680
- appendBytes32$1(parts, note.nullifier);
2681
- appendBytes32$1(parts, note.secret);
2682
- if (note.deposited_ephemeral_scalar !== undefined) {
2683
- appendU8$1(parts, 1);
2684
- appendBytes32$1(parts, note.deposited_ephemeral_scalar);
2685
- }
2686
- else {
2687
- appendU8$1(parts, 0);
2688
- }
2689
- }
2690
- function encodeOptionalRegistration(parts, registration) {
2691
- if (registration.tag === 'None') {
2692
- appendU8$1(parts, 0);
2693
- return;
2694
- }
2695
- appendU8$1(parts, 1);
2696
- const reg = registration.values[0];
2697
- appendAddressStrkey$1(parts, reg.owner);
2698
- appendBytes32$1(parts, reg.public_key_x);
2699
- appendBytes32$1(parts, reg.public_key_y);
2700
- }
2701
- /** Canonical `onboardingHash` matching `libs/kyt-passage/src/lib.rs::hash_onboarding`. */
2702
- function hashOnboardingCanonical(onboarding) {
2703
- if (onboarding === null || onboarding === undefined) {
2704
- return sha256Hex$1(Buffer.from(ONBOARDING_ZERO_DOMAIN, 'utf8'));
2705
- }
2706
- const parts = [];
2707
- appendAddressStrkey$1(parts, onboarding.owner);
2708
- appendBytes32$1(parts, onboarding.temp_public_key_x);
2709
- appendBytes32$1(parts, onboarding.temp_public_key_y);
2710
- appendBytesBlob(parts, onboarding.encrypted_private_key);
2711
- appendU32BE$1(parts, onboarding.notes.length);
2712
- for (const note of onboarding.notes) {
2713
- encodePlaintextNote(parts, note);
2714
- }
2715
- encodeOptionalRegistration(parts, onboarding.private_address_registration);
2716
- return sha256Hex$1(Buffer.concat(parts));
2717
- }
2718
- function onboardingContractValue(onboarding) {
2719
- return {
2720
- owner: onboarding.owner,
2721
- temp_public_key_x: onboarding.temp_public_key_x,
2722
- temp_public_key_y: onboarding.temp_public_key_y,
2723
- encrypted_private_key: onboarding.encrypted_private_key,
2724
- notes: {
2725
- notes: onboarding.notes.map((note) => ({
2726
- value: note.value,
2727
- asset_hi: note.asset_hi,
2728
- asset_lo: note.asset_lo,
2729
- nullifier: note.nullifier,
2730
- secret: note.secret,
2731
- deposited_ephemeral_scalar: note.deposited_ephemeral_scalar,
2732
- })),
2733
- },
2734
- private_address_registration: onboarding.private_address_registration,
2735
- };
2736
- }
2737
- function onboardingToScVal(onboarding) {
2738
- return nativeToScVal(onboardingContractValue(onboarding));
2739
- }
2740
- function onboardingOptionToScVal(onboarding) {
2741
- if (onboarding === null || onboarding === undefined) {
2742
- return xdr.ScVal.scvVoid();
2743
- }
2744
- return onboardingToScVal(onboarding);
2745
- }
2746
- function addressToScVal(address) {
2747
- return nativeToScVal(address, { type: 'address' });
2748
- }
2749
-
2750
2905
  const KYT_PASSAGE_AUTH_DOMAIN = 'privacy-pool-kyt-passage-v1';
2751
2906
  const PUBLIC_LEG_CONTEXT_DOMAIN = 'privacy-pool-public-leg-context-v1';
2752
- const PASSAGE_ID_DOMAIN = 'privacy-pool-passage-id-v1';
2753
- const NOTE_AUDIT_LEN = 9;
2754
- const TOTAL_PUBLIC_SIGNALS = 79;
2907
+ const PASSAGE_ID_DOMAIN = 'privacy-pool-passage-id-v2';
2908
+ const PASSAGE_ID_DOMAIN_V1 = 'privacy-pool-passage-id-v1';
2909
+ const NOTE_AUDIT_LEN = 12;
2910
+ const TOTAL_PUBLIC_SIGNALS = 93;
2911
+ const NOTE_AUDIT_PLAINTEXT_LEN = 12;
2755
2912
  const FIELD_BYTES = 32;
2756
2913
  const LENGTH_PREFIX_BYTES = 4;
2757
- const STATE_ROOT_SIGNAL_INDEX = 70;
2914
+ const STATE_ROOT_SIGNAL_INDEX = 82;
2758
2915
  function sha256Hex(data) {
2759
2916
  return bytesToHex(sha256(data));
2760
2917
  }
@@ -2763,7 +2920,18 @@ function publicSignalsBuffer(publicSignalsBytes) {
2763
2920
  ? Buffer.from(publicSignalsBytes.replace(/^0x/, ''), 'hex')
2764
2921
  : publicSignalsBytes;
2765
2922
  }
2766
- function parsePublicSignalsBytes(publicSignalsBytes) {
2923
+ function expectedSignalCountForNonce(zkConfigNonce = 0n) {
2924
+ if (zkConfigNonce !== 0n) {
2925
+ throw new Error(`unknown zk config nonce ${zkConfigNonce.toString()}`);
2926
+ }
2927
+ return TOTAL_PUBLIC_SIGNALS;
2928
+ }
2929
+ function stateRootIndexForNonce(zkConfigNonce = 0n) {
2930
+ expectedSignalCountForNonce(zkConfigNonce);
2931
+ return STATE_ROOT_SIGNAL_INDEX;
2932
+ }
2933
+ function parsePublicSignalsBytes(publicSignalsBytes, zkConfigNonce = 0n) {
2934
+ const expectedCount = expectedSignalCountForNonce(zkConfigNonce);
2767
2935
  const buf = publicSignalsBuffer(publicSignalsBytes);
2768
2936
  let offset = 0;
2769
2937
  let hasLengthPrefix = false;
@@ -2775,11 +2943,11 @@ function parsePublicSignalsBytes(publicSignalsBytes) {
2775
2943
  }
2776
2944
  }
2777
2945
  const signalBytes = buf.subarray(offset);
2778
- if (signalBytes.length !== TOTAL_PUBLIC_SIGNALS * FIELD_BYTES) {
2779
- throw new Error(`expected ${TOTAL_PUBLIC_SIGNALS} public signals`);
2946
+ if (signalBytes.length !== expectedCount * FIELD_BYTES) {
2947
+ throw new Error(`expected ${expectedCount} public signals`);
2780
2948
  }
2781
2949
  return {
2782
- fields: Array.from({ length: TOTAL_PUBLIC_SIGNALS }, (_, index) => Buffer.from(signalBytes.subarray(index * FIELD_BYTES, (index + 1) * FIELD_BYTES))),
2950
+ fields: Array.from({ length: expectedCount }, (_, index) => Buffer.from(signalBytes.subarray(index * FIELD_BYTES, (index + 1) * FIELD_BYTES))),
2783
2951
  hasLengthPrefix,
2784
2952
  };
2785
2953
  }
@@ -2874,9 +3042,9 @@ function encodeLegSlot(parts, kind, slot, isPresent, assetHi, assetLo, amount, a
2874
3042
  parts.push(zeroAddressBuffer());
2875
3043
  }
2876
3044
  }
2877
- function hashPublicSignalBytes(publicSignalsBytes) {
2878
- const parsed = parsePublicSignalsBytes(publicSignalsBytes);
2879
- parsed.fields[STATE_ROOT_SIGNAL_INDEX] = Buffer.alloc(FIELD_BYTES);
3045
+ function hashPublicSignalBytes(publicSignalsBytes, zkConfigNonce = 0n) {
3046
+ const parsed = parsePublicSignalsBytes(publicSignalsBytes, zkConfigNonce);
3047
+ parsed.fields[stateRootIndexForNonce(zkConfigNonce)] = Buffer.alloc(FIELD_BYTES);
2880
3048
  return sha256Hex(encodePublicSignalsBytes(parsed.fields, parsed.hasLengthPrefix));
2881
3049
  }
2882
3050
  function hashPublicLegContext(layout, input) {
@@ -2898,16 +3066,22 @@ function hashPublicLegContext(layout, input) {
2898
3066
  }
2899
3067
  return sha256Hex(Buffer.concat(parts));
2900
3068
  }
2901
- function hashOnboarding(onboarding) {
2902
- return hashOnboardingCanonical(onboarding);
2903
- }
2904
- function derivePassageId(owner, nonce, publicSignalHash, publicLegContextHash, onboardingHash) {
3069
+ function derivePassageId(owner, nonce, publicSignalHash, publicLegContextHash) {
2905
3070
  const parts = [];
2906
3071
  appendBytes(parts, Buffer.from(PASSAGE_ID_DOMAIN, 'utf8'));
2907
3072
  appendAddressStrkey(parts, owner);
2908
3073
  appendU64BE(parts, nonce);
2909
3074
  appendBytes32(parts, publicSignalHash);
2910
3075
  appendBytes32(parts, publicLegContextHash);
3076
+ return sha256Hex(Buffer.concat(parts));
3077
+ }
3078
+ function derivePassageIdV1(owner, nonce, publicSignalHash, publicLegContextHash, onboardingHash) {
3079
+ const parts = [];
3080
+ appendBytes(parts, Buffer.from(PASSAGE_ID_DOMAIN_V1, 'utf8'));
3081
+ appendAddressStrkey(parts, owner);
3082
+ appendU64BE(parts, nonce);
3083
+ appendBytes32(parts, publicSignalHash);
3084
+ appendBytes32(parts, publicLegContextHash);
2911
3085
  appendBytes32(parts, onboardingHash);
2912
3086
  return sha256Hex(Buffer.concat(parts));
2913
3087
  }
@@ -2929,15 +3103,13 @@ function buildKytPassageAuthorization(input) {
2929
3103
  }
2930
3104
  function derivePassageFromTransactContext(input) {
2931
3105
  const layout = input.layout ?? { publicNInputs: 1, publicNOutputs: 1 };
2932
- const nonce = input.nonce ?? 0n;
2933
- const publicSignalHash = hashPublicSignalBytes(input.publicSignalsBytes);
3106
+ const nonce = BigInt(input.nonce ?? 0);
3107
+ const publicSignalHash = hashPublicSignalBytes(input.publicSignalsBytes, nonce);
2934
3108
  const publicLegContextHash = hashPublicLegContext(layout, input.publicLegContext);
2935
- const onboardingHash = hashOnboarding(input.onboarding ?? null);
2936
- const passageId = derivePassageId(input.owner, nonce, publicSignalHash, publicLegContextHash, onboardingHash);
3109
+ const passageId = derivePassageId(input.owner, nonce, publicSignalHash, publicLegContextHash);
2937
3110
  return {
2938
3111
  publicSignalHash,
2939
3112
  publicLegContextHash,
2940
- onboardingHash,
2941
3113
  passageId,
2942
3114
  };
2943
3115
  }
@@ -2968,14 +3140,16 @@ var kytPassage = /*#__PURE__*/Object.freeze({
2968
3140
  __proto__: null,
2969
3141
  KYT_PASSAGE_AUTH_DOMAIN: KYT_PASSAGE_AUTH_DOMAIN,
2970
3142
  NOTE_AUDIT_LEN: NOTE_AUDIT_LEN,
3143
+ NOTE_AUDIT_PLAINTEXT_LEN: NOTE_AUDIT_PLAINTEXT_LEN,
2971
3144
  PASSAGE_ID_DOMAIN: PASSAGE_ID_DOMAIN,
3145
+ PASSAGE_ID_DOMAIN_V1: PASSAGE_ID_DOMAIN_V1,
2972
3146
  PUBLIC_LEG_CONTEXT_DOMAIN: PUBLIC_LEG_CONTEXT_DOMAIN,
2973
3147
  TOTAL_PUBLIC_SIGNALS: TOTAL_PUBLIC_SIGNALS,
2974
3148
  addressToCanonicalXdr: addressToCanonicalXdr,
2975
3149
  buildKytPassageAuthorization: buildKytPassageAuthorization,
2976
3150
  derivePassageFromTransactContext: derivePassageFromTransactContext,
2977
3151
  derivePassageId: derivePassageId,
2978
- hashOnboarding: hashOnboarding,
3152
+ derivePassageIdV1: derivePassageIdV1,
2979
3153
  hashPublicLegContext: hashPublicLegContext,
2980
3154
  hashPublicSignalBytes: hashPublicSignalBytes,
2981
3155
  inspectKytPassage: inspectKytPassage,
@@ -2983,6 +3157,9 @@ var kytPassage = /*#__PURE__*/Object.freeze({
2983
3157
  zeroAddressSentinelBuffer: zeroAddressSentinelBuffer
2984
3158
  });
2985
3159
 
3160
+ function addressToScVal(address) {
3161
+ return nativeToScVal(address, { type: 'address' });
3162
+ }
2986
3163
  function passageIdHexToScVal(passageIdHex) {
2987
3164
  const bytes = Buffer.from(passageIdHex.replace(/^0x/, ''), 'hex');
2988
3165
  return xdr.ScVal.scvBytes(bytes);
@@ -3019,7 +3196,6 @@ function poolTransactOperation(params) {
3019
3196
  nativeToScVal(params.nonce, { type: 'u64' }),
3020
3197
  xdr.ScVal.scvBytes(params.proofBytes),
3021
3198
  xdr.ScVal.scvBytes(params.publicSignalsBytes),
3022
- onboardingOptionToScVal(params.onboarding),
3023
3199
  kytAuthorizationOptionToScVal(params.kytAuthorization),
3024
3200
  ],
3025
3201
  });
@@ -3033,7 +3209,6 @@ function helperSubmitWithPassageOperation(helperContractId, params, passageId, e
3033
3209
  nativeToScVal(params.nonce, { type: 'u64' }),
3034
3210
  xdr.ScVal.scvBytes(params.proofBytes),
3035
3211
  xdr.ScVal.scvBytes(params.publicSignalsBytes),
3036
- onboardingOptionToScVal(params.onboarding),
3037
3212
  passageIdHexToScVal(passageId),
3038
3213
  xdr.ScVal.scvU32(expiresAtLedger),
3039
3214
  signatureToScVal(signatureBase64ToBytes(signature)),
@@ -3166,7 +3341,6 @@ async function registerKytPassage(params) {
3166
3341
  nonce: params.nonce,
3167
3342
  publicSignalsBytes: params.publicSignalsBytes,
3168
3343
  publicLegContext: params.publicLegContext,
3169
- onboarding: params.onboarding,
3170
3344
  });
3171
3345
  await submitTransaction({
3172
3346
  source: params.source,
@@ -3216,7 +3390,6 @@ async function submitWithKytPassage(params) {
3216
3390
  nonce: params.nonce,
3217
3391
  publicSignalsBytes: params.publicSignalsBytes,
3218
3392
  publicLegContext: params.publicLegContext,
3219
- onboarding: params.onboarding,
3220
3393
  });
3221
3394
  if (approved.passageId.replace(/^0x/, '') !== derivation.passageId) {
3222
3395
  throw new Error('KYT approval passageId does not match local transaction context');
@@ -3231,7 +3404,6 @@ async function submitWithKytPassage(params) {
3231
3404
  nonce: params.nonce,
3232
3405
  proofBytes: params.proofBytes,
3233
3406
  publicSignalsBytes: params.publicSignalsBytes,
3234
- onboarding: params.onboarding,
3235
3407
  kytSubmitHelperId: params.kytSubmitHelperId,
3236
3408
  passageId: derivation.passageId,
3237
3409
  expiresAtLedger: approved.expiresAtLedger,
@@ -3255,6 +3427,44 @@ function localSignKytPassageAuthorization(secretSeed, authorization) {
3255
3427
  return sig.toString('base64');
3256
3428
  }
3257
3429
 
3430
+ const SCALAR_HEX_LENGTH = 64;
3431
+ const OUT_OF_RANGE_MESSAGE = 'derived escrow hash is outside BabyJub subgroup; retry nonce';
3432
+ function hexFromCanonicalScalar(value) {
3433
+ return value.toString(16).padStart(SCALAR_HEX_LENGTH, '0');
3434
+ }
3435
+ function assertCanonicalBabyJubScalar(scalar) {
3436
+ if (!(scalar > 0n && scalar < BABYJUB_SUBGROUP_ORDER)) {
3437
+ throw new Error(OUT_OF_RANGE_MESSAGE);
3438
+ }
3439
+ }
3440
+ async function derivedEscrowKey(nonce, recipientHi, recipientLo) {
3441
+ const wasm = await loadWasm();
3442
+ const out = wasm.derivedEscrowKey(nonce.toString(), recipientHi.toString(), recipientLo.toString());
3443
+ const scalar = BigInt(`0x${out.scalarHex}`);
3444
+ assertCanonicalBabyJubScalar(scalar);
3445
+ return {
3446
+ scalarHex: hexFromCanonicalScalar(scalar),
3447
+ pointXHex: out.pointXHex,
3448
+ pointYHex: out.pointYHex,
3449
+ };
3450
+ }
3451
+ async function sampleDerivedEscrowKey(recipientHi, recipientLo, startNonce = 1n, window = 1024n) {
3452
+ for (let offset = 0n; offset < window; offset += 1n) {
3453
+ const nonce = startNonce + offset;
3454
+ try {
3455
+ const key = await derivedEscrowKey(nonce, recipientHi, recipientLo);
3456
+ return { nonce, key };
3457
+ }
3458
+ catch (error) {
3459
+ const message = error instanceof Error ? error.message : String(error);
3460
+ if (!message.includes('outside BabyJub subgroup')) {
3461
+ throw error;
3462
+ }
3463
+ }
3464
+ }
3465
+ throw new Error(OUT_OF_RANGE_MESSAGE);
3466
+ }
3467
+
3258
3468
  const NOTE_OUTPUT_LEN = 6;
3259
3469
  const OUTPUT_NOTE_TAG_DOMAIN = 3n;
3260
3470
  const STREAM_DOMAIN = 1n;
@@ -3312,6 +3522,9 @@ function mimcHash(parameters) {
3312
3522
  function poseidonHash(poseidon, inputs) {
3313
3523
  return fieldBigint(poseidon.F, poseidon(inputs.map((input) => poseidon.F.e(input))));
3314
3524
  }
3525
+ function deriveEncCipherKey(poseidon, sharedX) {
3526
+ return poseidonHash(poseidon, [DOM_ENC, sharedX]);
3527
+ }
3315
3528
  function sharedKeyFromDepositor(parameters) {
3316
3529
  const scalarHex = frDecimalToHex(parameters.ephemeralKeyScalarDecimal);
3317
3530
  const shared = parameters.ecdhShared(scalarHex, frDecimalToHex(parameters.recipientPublicKey[0]), frDecimalToHex(parameters.recipientPublicKey[1]));
@@ -3413,12 +3626,14 @@ async function encryptOutputNoteForDeposit(parameters) {
3413
3626
  secret,
3414
3627
  applicationId: parameters.deposit.applicationId,
3415
3628
  };
3416
- const [key, nonce] = sharedKeyFromDepositor({
3629
+ const [sharedX, sharedY] = sharedKeyFromDepositor({
3417
3630
  babyJub,
3418
3631
  ecdhShared: parameters.ecdhShared,
3419
3632
  ephemeralKeyScalarDecimal: parameters.deposit.ephemeralKeyScalar,
3420
3633
  recipientPublicKey: parameters.deposit.recipientPublicKeys,
3421
3634
  });
3635
+ const key = deriveEncCipherKey(poseidon, sharedX);
3636
+ const nonce = sharedY;
3422
3637
  const message = plaintextBigints(plaintext);
3423
3638
  const ciphertext = encryptFields({ mimc7, poseidon, key, nonce, plaintext: message });
3424
3639
  const tag = outputNoteTag({ mimc7, poseidon, key, nonce, plaintext: message });
@@ -3427,13 +3642,22 @@ async function encryptOutputNoteForDeposit(parameters) {
3427
3642
  tag: frDecimalFromBigint(tag),
3428
3643
  };
3429
3644
  }
3430
- function commitmentFromPlaintextAndSharedSecret(parameters) {
3431
- const sharedX = bigintFromHex(parameters.sharedSecret.x);
3432
- const sharedY = bigintFromHex(parameters.sharedSecret.y);
3645
+ function ownerPubFromRecipientScalar(babyJub, recipientScalarHex) {
3646
+ const product = babyJub.mulPointEscalar(babyJub.Base8, bigintFromHex(recipientScalarHex) & SCALAR_253_MASK);
3647
+ return [
3648
+ fieldBigint(babyJub.F, product[0]),
3649
+ fieldBigint(babyJub.F, product[1]),
3650
+ ];
3651
+ }
3652
+ function commitmentFromPlaintextAndOwnerPub(parameters) {
3653
+ const ownerKeyHash = poseidonHash(parameters.poseidon, [
3654
+ parameters.ownerPub[0],
3655
+ parameters.ownerPub[1],
3656
+ ]);
3433
3657
  const precommitment = poseidonHash(parameters.poseidon, [
3434
3658
  bigintFromDecimal(parameters.plaintext.secret),
3435
- sharedX,
3436
- sharedY,
3659
+ parameters.ownerMode,
3660
+ ownerKeyHash,
3437
3661
  ]);
3438
3662
  const balance = poseidonHash(parameters.poseidon, [
3439
3663
  bigintFromDecimal(parameters.plaintext.value),
@@ -3453,11 +3677,13 @@ function commitmentFromPlaintextAndSharedSecret(parameters) {
3453
3677
  }
3454
3678
  async function decryptOutputNoteEvent(input) {
3455
3679
  const { babyJub, mimc7, poseidon } = await primitives();
3456
- const [key, nonce] = sharedKeyFromRecipient({
3680
+ const [sharedX, sharedY] = sharedKeyFromRecipient({
3457
3681
  babyJub,
3458
3682
  recipientScalarHex: input.recipientScalarHex,
3459
3683
  ephemeralPublicKey: input.createdEphemeralKey,
3460
3684
  });
3685
+ const key = deriveEncCipherKey(poseidon, sharedX);
3686
+ const nonce = sharedY;
3461
3687
  const decrypted = decryptFields({
3462
3688
  mimc7,
3463
3689
  poseidon,
@@ -3476,14 +3702,11 @@ async function decryptOutputNoteEvent(input) {
3476
3702
  throw new Error('Output note tag verification failed');
3477
3703
  }
3478
3704
  const plaintext = plaintextFromBigints(decrypted);
3479
- const sharedSecret = {
3480
- x: bigintToFrHex(key),
3481
- y: bigintToFrHex(nonce),
3482
- };
3483
- const commitmentHex = commitmentFromPlaintextAndSharedSecret({
3705
+ const commitmentHex = commitmentFromPlaintextAndOwnerPub({
3484
3706
  poseidon,
3485
3707
  plaintext,
3486
- sharedSecret,
3708
+ ownerPub: ownerPubFromRecipientScalar(babyJub, input.recipientScalarHex),
3709
+ ownerMode: input.ownerMode ?? 0n,
3487
3710
  });
3488
3711
  const commitmentMatches = normalizeHex(input.commitmentHashHex) === commitmentHex;
3489
3712
  if (!commitmentMatches) {
@@ -3496,5 +3719,5 @@ async function decryptOutputNoteEvent(input) {
3496
3719
  };
3497
3720
  }
3498
3721
 
3499
- export { BN254_BABYJUB_SCALAR_MAX_EXCLUSIVE, BN254_SCALAR_MOD, COIN_VALUE_STROOPS, DECODED_EPHEMERAL_HRP, DEFAULT_APPLICATION_ID, DEFAULT_STEALTH_SIGN_NONCE, DEMO_AUDIT_PUBLIC_KEY, DEPOSITOR_SHARED_SECRET_PREIMAGE_HRP, NOTE_AUDIT_LEN as KYT_NOTE_AUDIT_LEN, NOTE_AUDIT_LEN$1 as NOTE_AUDIT_LEN, NOTE_OUTPUT_LEN$1 as NOTE_OUTPUT_LEN, NOTE_OUTPUT_LEN as OUTPUT_NOTE_LEN, POOL_MERKLE_TREE_DEPTH, PrivacyPoolSDK, STEALTH_ADDRESS_HRP, TOTAL_PUBLIC_SIGNALS, TRANSACTION_N_AUDIT_SLOTS, TRANSACTION_N_INS, TRANSACTION_N_OUTS, TRANSACTION_TREE_DEPTH, addressToCanonicalXdr, buildKytPassageAuthorization, buildStealthAddressSignMessage, buildTransactionWitnessInput, buildUniformAuditParams, coordHexToDecimal, decodeDecodedEphemeralKey, decodeDepositorSharedSecretPreimage, decodeStealthAddress, decryptOutputNoteEvent, derivePassageFromTransactContext, derivePassageId, ed25519PubkeyPayloadHexToWithdrawFrDecimals, encodeDecodedEphemeralKey, encodeDepositorSharedSecretPreimage, encodeStealthAddress, encryptOutputNoteForDeposit, generateRandomScalarHex32, hashOnboarding, hashOnboardingCanonical, hashPublicLegContext, hashPublicSignalBytes, inspectKytPassage, localSignKytPassageAuthorization, onboardingOptionToScVal, onboardingToScVal, planKytSubmit, privKeyScalarDecimalFromStellarSignature, randomFrDecimal, randomFrDecimal253, recipientPublicKeysDecimalFromStealthAddress, registerKytPassage, resolveDepositsForWitness, resolveSlotApplicationIds, resolveTransactionAuditParams, scalarHexToFrDecimal, sharedSecretFromDepositorPreimage, sharedSecretFromRecipientPreimage, stellarContractAddressToAssetFrDecimals, submitApprovedKytPassage, submitPoolTransact, submitWithKytPassage, withApplicationIdOnDeposit, withApplicationIdOnWithdraw, withdrawObjectFromMerkleWitness, zeroAddressSentinelBuffer };
3722
+ export { BABYJUB_SUBGROUP_ORDER, BN254_BABYJUB_SCALAR_MAX_EXCLUSIVE, BN254_SCALAR_MOD, COIN_VALUE_STROOPS, DECODED_EPHEMERAL_HRP, DEFAULT_APPLICATION_ID, DEFAULT_STEALTH_SIGN_NONCE, DEMO_AUDIT_PUBLIC_KEY, DEPOSITOR_SHARED_SECRET_PREIMAGE_HRP, DOM_ENC, DOM_ESCROW, DOM_NULLIFIER, DOM_PADDING, NOTE_AUDIT_LEN as KYT_NOTE_AUDIT_LEN, NOTE_AUDIT_LEN$1 as NOTE_AUDIT_LEN, NOTE_AUDIT_PLAINTEXT_LEN, NOTE_OUTPUT_LEN$1 as NOTE_OUTPUT_LEN, NOTE_OUTPUT_LEN as OUTPUT_NOTE_LEN, OWNER_BOUND_NOTE_SCHEMA_VERSION, POOL_MERKLE_TREE_DEPTH, PrivacyPoolSDK, SPEND_SCALAR_DOMAIN_TAG, STEALTH_ADDRESS_HRP, TOTAL_PUBLIC_SIGNALS, TRANSACTION_N_AUDIT_SLOTS, TRANSACTION_N_INS, TRANSACTION_N_OUTS, TRANSACTION_TREE_DEPTH, addressToCanonicalXdr, buildKytPassageAuthorization, buildStealthAddressSignMessage, buildTransactionWitnessInput, buildUniformAuditParams, canonicalBabyJubScalarFromInteger, coordHexToDecimal, decodeDecodedEphemeralKey, decodeDepositorSharedSecretPreimage, decodeStealthAddress, decryptOutputNoteEvent, derivePassageFromTransactContext, derivePassageId, derivePassageIdV1, derivedEscrowKey, ed25519PubkeyPayloadHexToWithdrawFrDecimals, encodeDecodedEphemeralKey, encodeDepositorSharedSecretPreimage, encodeStealthAddress, encryptOutputNoteForDeposit, generateRandomScalarHex32, generateWitness, hashPublicLegContext, hashPublicSignalBytes, inspectKytPassage, localSignKytPassageAuthorization, planKytSubmit, privKeyScalarDecimalFromStellarSignature, randomFrDecimal, randomFrDecimal253, recipientPublicKeysDecimalFromStealthAddress, registerKytPassage, resolveAuditPublicKeyFromEnv, resolveDepositsForWitness, resolveSlotApplicationIds, resolveSpendScalarSchemaVersion, resolveTransactionAuditParams, sampleDerivedEscrowKey, scalarHexToFrDecimal, secretFromDepositEphemeralScalarDecimal, sharedSecretFromDepositorPreimage, sharedSecretFromRecipientPreimage, spendScalarHexFromStellarSignature, stellarContractAddressToAssetFrDecimals, submitApprovedKytPassage, submitPoolTransact, submitWithKytPassage, withApplicationIdOnDeposit, withApplicationIdOnWithdraw, withdrawObjectFromMerkleWitness, zeroAddressSentinelBuffer };
3500
3723
  //# sourceMappingURL=index.mjs.map