@arcanetech/stellar-privacy-pool-zk-sdk 0.9.1-rc.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.
Files changed (43) hide show
  1. package/dist/ciphertext-blob.d.ts +17 -0
  2. package/dist/circuit-artifacts.d.ts +9 -0
  3. package/dist/circuit-urls-2x2-COiK1uEc.mjs +6 -0
  4. package/dist/circuit-urls-2x2-COiK1uEc.mjs.map +1 -0
  5. package/dist/circuit-urls-2x2-DVpZIkgS.js +12 -0
  6. package/dist/circuit-urls-2x2-DVpZIkgS.js.map +1 -0
  7. package/dist/circuit-urls-2x2.d.ts +3 -0
  8. package/dist/circuit-urls-6x6-CqdzNC4I.js +12 -0
  9. package/dist/circuit-urls-6x6-CqdzNC4I.js.map +1 -0
  10. package/dist/circuit-urls-6x6-Dtp8u02o.mjs +6 -0
  11. package/dist/circuit-urls-6x6-Dtp8u02o.mjs.map +1 -0
  12. package/dist/circuit-urls-6x6.d.ts +3 -0
  13. package/dist/cli.d.ts +1 -0
  14. package/dist/cli.js +3114 -0
  15. package/dist/cli.js.map +1 -0
  16. package/dist/derived-escrow-key.d.ts +10 -0
  17. package/dist/domain-separators.d.ts +16 -0
  18. package/dist/ephemeral-key.d.ts +28 -0
  19. package/dist/index.d.ts +30 -0
  20. package/dist/index.mjs +3875 -0
  21. package/dist/index.mjs.map +1 -0
  22. package/dist/kyt-flow.d.ts +60 -0
  23. package/dist/kyt-onboarding.d.ts +36 -0
  24. package/dist/kyt-passage.d.ts +83 -0
  25. package/dist/output-note-encryption.d.ts +72 -0
  26. package/dist/prover.d.ts +5 -0
  27. package/dist/sdk.d.ts +130 -0
  28. package/dist/shared-secret.d.ts +24 -0
  29. package/dist/stealth-address.d.ts +23 -0
  30. package/dist/stealth-sign-message.d.ts +20 -0
  31. package/dist/stealth-signature.d.ts +29 -0
  32. package/dist/transaction-audit.d.ts +26 -0
  33. package/dist/types.d.ts +64 -0
  34. package/dist/wasm.d.ts +1 -0
  35. package/dist/withdrawal-transaction-input.d.ts +162 -0
  36. package/dist/witness.d.ts +3 -0
  37. package/dist/zk-artifact-url.d.ts +4 -0
  38. package/dist/zk-layout.d.ts +84 -0
  39. package/package.json +57 -0
  40. package/pkg/client_sdk_wasm.d.ts +120 -0
  41. package/pkg/client_sdk_wasm.js +765 -0
  42. package/pkg/client_sdk_wasm_bg.wasm +0 -0
  43. package/pkg/client_sdk_wasm_bg.wasm.d.ts +21 -0
package/dist/index.mjs ADDED
@@ -0,0 +1,3875 @@
1
+ import { StrKey, Address, Keypair, rpc, TransactionBuilder, Operation, xdr, nativeToScVal, authorizeEntry } from '@stellar/stellar-sdk';
2
+ import { buildBabyjub, buildMimc7, buildPoseidon } from 'circomlibjs';
3
+
4
+ /* @ts-self-types="./client_sdk_wasm.d.ts" */
5
+
6
+ /**
7
+ * Merkle root, path, and coin field strings for the first withdraw leg (JSON → JSON).
8
+ * @param {string} coin_json
9
+ * @param {string} state_json
10
+ * @returns {string}
11
+ */
12
+ function buildWithdrawMerkleWitness(coin_json, state_json) {
13
+ let deferred4_0;
14
+ let deferred4_1;
15
+ try {
16
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
17
+ const ptr0 = passStringToWasm0(coin_json, wasm.__wbindgen_export, wasm.__wbindgen_export2);
18
+ const len0 = WASM_VECTOR_LEN;
19
+ const ptr1 = passStringToWasm0(state_json, wasm.__wbindgen_export, wasm.__wbindgen_export2);
20
+ const len1 = WASM_VECTOR_LEN;
21
+ wasm.buildWithdrawMerkleWitness(retptr, ptr0, len0, ptr1, len1);
22
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
23
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
24
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
25
+ var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
26
+ var ptr3 = r0;
27
+ var len3 = r1;
28
+ if (r3) {
29
+ ptr3 = 0; len3 = 0;
30
+ throw takeObject(r2);
31
+ }
32
+ deferred4_0 = ptr3;
33
+ deferred4_1 = len3;
34
+ return getStringFromWasm0(ptr3, len3);
35
+ } finally {
36
+ wasm.__wbindgen_add_to_stack_pointer(16);
37
+ wasm.__wbindgen_export4(deferred4_0, deferred4_1, 1);
38
+ }
39
+ }
40
+
41
+ /**
42
+ * Calculate owner-bound nullifier hash from nullifier and spend-scalar decimal strings.
43
+ * Returns hex string (0x...)
44
+ * @param {string} nullifier_decimal
45
+ * @param {string} priv_key_scalar_decimal
46
+ * @returns {string}
47
+ */
48
+ function calculateNullifierHash(nullifier_decimal, priv_key_scalar_decimal) {
49
+ let deferred4_0;
50
+ let deferred4_1;
51
+ try {
52
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
53
+ const ptr0 = passStringToWasm0(nullifier_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
54
+ const len0 = WASM_VECTOR_LEN;
55
+ const ptr1 = passStringToWasm0(priv_key_scalar_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
56
+ const len1 = WASM_VECTOR_LEN;
57
+ wasm.calculateNullifierHash(retptr, ptr0, len0, ptr1, len1);
58
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
59
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
60
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
61
+ var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
62
+ var ptr3 = r0;
63
+ var len3 = r1;
64
+ if (r3) {
65
+ ptr3 = 0; len3 = 0;
66
+ throw takeObject(r2);
67
+ }
68
+ deferred4_0 = ptr3;
69
+ deferred4_1 = len3;
70
+ return getStringFromWasm0(ptr3, len3);
71
+ } finally {
72
+ wasm.__wbindgen_add_to_stack_pointer(16);
73
+ wasm.__wbindgen_export4(deferred4_0, deferred4_1, 1);
74
+ }
75
+ }
76
+
77
+ /**
78
+ * `R = Poseidon255(2)(hi, lo)`; `scalar` is the raw Poseidon hash when it is
79
+ * already in `(0, BabyJub subgroup order)`. Out-of-range hashes fail so the
80
+ * caller can rejection-sample a new nonce.
81
+ * @param {string} nonce_decimal
82
+ * @param {string} recipient_hi_decimal
83
+ * @param {string} recipient_lo_decimal
84
+ * @returns {any}
85
+ */
86
+ function derivedEscrowKey$1(nonce_decimal, recipient_hi_decimal, recipient_lo_decimal) {
87
+ try {
88
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
89
+ const ptr0 = passStringToWasm0(nonce_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
90
+ const len0 = WASM_VECTOR_LEN;
91
+ const ptr1 = passStringToWasm0(recipient_hi_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
92
+ const len1 = WASM_VECTOR_LEN;
93
+ const ptr2 = passStringToWasm0(recipient_lo_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
94
+ const len2 = WASM_VECTOR_LEN;
95
+ wasm.derivedEscrowKey(retptr, ptr0, len0, ptr1, len1, ptr2, len2);
96
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
97
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
98
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
99
+ if (r2) {
100
+ throw takeObject(r1);
101
+ }
102
+ return takeObject(r0);
103
+ } finally {
104
+ wasm.__wbindgen_add_to_stack_pointer(16);
105
+ }
106
+ }
107
+
108
+ /**
109
+ * UTF-8 seed → `SHA256` → scalar → BabyJubJub `BASE8 * r` (circom `ECDHEphemeralKey`).
110
+ * `x` and `y` are lowercase hex (no `0x`). Bech32 / stealth string: TypeScript `encodeStealthAddress`.
111
+ * @param {string} seed
112
+ * @returns {any}
113
+ */
114
+ function ecdhEphemeralPublicKey(seed) {
115
+ try {
116
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
117
+ const ptr0 = passStringToWasm0(seed, wasm.__wbindgen_export, wasm.__wbindgen_export2);
118
+ const len0 = WASM_VECTOR_LEN;
119
+ wasm.ecdhEphemeralPublicKey(retptr, ptr0, len0);
120
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
121
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
122
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
123
+ if (r2) {
124
+ throw takeObject(r1);
125
+ }
126
+ return takeObject(r0);
127
+ } finally {
128
+ wasm.__wbindgen_add_to_stack_pointer(16);
129
+ }
130
+ }
131
+
132
+ /**
133
+ * 32-byte scalar as 64 hex chars (optional `0x`) → `ecdh_ephemeral_public_key` (no UTF-8 seed hash).
134
+ * @param {string} scalar_hex
135
+ * @returns {any}
136
+ */
137
+ function ecdhEphemeralPublicKeyFromScalarHex(scalar_hex) {
138
+ try {
139
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
140
+ const ptr0 = passStringToWasm0(scalar_hex, wasm.__wbindgen_export, wasm.__wbindgen_export2);
141
+ const len0 = WASM_VECTOR_LEN;
142
+ wasm.ecdhEphemeralPublicKeyFromScalarHex(retptr, ptr0, len0);
143
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
144
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
145
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
146
+ if (r2) {
147
+ throw takeObject(r1);
148
+ }
149
+ return takeObject(r0);
150
+ } finally {
151
+ wasm.__wbindgen_add_to_stack_pointer(16);
152
+ }
153
+ }
154
+
155
+ /**
156
+ * Circuit `ECDH`: `priv * (pub_x, pub_y)` → shared key (`key[0], key[1]` hex).
157
+ * @param {string} priv_hex
158
+ * @param {string} pub_x_hex
159
+ * @param {string} pub_y_hex
160
+ * @returns {any}
161
+ */
162
+ function ecdhSharedKey(priv_hex, pub_x_hex, pub_y_hex) {
163
+ try {
164
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
165
+ const ptr0 = passStringToWasm0(priv_hex, wasm.__wbindgen_export, wasm.__wbindgen_export2);
166
+ const len0 = WASM_VECTOR_LEN;
167
+ const ptr1 = passStringToWasm0(pub_x_hex, wasm.__wbindgen_export, wasm.__wbindgen_export2);
168
+ const len1 = WASM_VECTOR_LEN;
169
+ const ptr2 = passStringToWasm0(pub_y_hex, wasm.__wbindgen_export, wasm.__wbindgen_export2);
170
+ const len2 = WASM_VECTOR_LEN;
171
+ wasm.ecdhSharedKey(retptr, ptr0, len0, ptr1, len1, ptr2, len2);
172
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
173
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
174
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
175
+ if (r2) {
176
+ throw takeObject(r1);
177
+ }
178
+ return takeObject(r0);
179
+ } finally {
180
+ wasm.__wbindgen_add_to_stack_pointer(16);
181
+ }
182
+ }
183
+
184
+ /**
185
+ * Generate a new coin with random nullifier, secret, and owner public-key field elements.
186
+ * `amount_decimal` is an arbitrary-precision decimal field element (never JS `number`).
187
+ * `asset_hi_decimal` / `asset_lo_decimal` are decimal Fr strings for the Stellar asset contract id (two limbs).
188
+ * Returns JSON: { coin: { value, nullifier, secret, commitment, asset_hi, asset_lo }, commitment_hex, precommitement_hex }
189
+ * @param {string} amount_decimal
190
+ * @param {string} asset_hi_decimal
191
+ * @param {string} asset_lo_decimal
192
+ * @param {string} application_id_decimal
193
+ * @returns {any}
194
+ */
195
+ function generateCoin(amount_decimal, asset_hi_decimal, asset_lo_decimal, application_id_decimal) {
196
+ try {
197
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
198
+ const ptr0 = passStringToWasm0(amount_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
199
+ const len0 = WASM_VECTOR_LEN;
200
+ const ptr1 = passStringToWasm0(asset_hi_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
201
+ const len1 = WASM_VECTOR_LEN;
202
+ const ptr2 = passStringToWasm0(asset_lo_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
203
+ const len2 = WASM_VECTOR_LEN;
204
+ const ptr3 = passStringToWasm0(application_id_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
205
+ const len3 = WASM_VECTOR_LEN;
206
+ wasm.generateCoin(retptr, ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3);
207
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
208
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
209
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
210
+ if (r2) {
211
+ throw takeObject(r1);
212
+ }
213
+ return takeObject(r0);
214
+ } finally {
215
+ wasm.__wbindgen_add_to_stack_pointer(16);
216
+ }
217
+ }
218
+
219
+ /**
220
+ * `Poseidon₁(scalar)` secret + recipient owner public key (hex), matching an aligned deposit witness.
221
+ * @param {string} scalar_hex
222
+ * @param {string} owner_x_hex
223
+ * @param {string} owner_y_hex
224
+ * @param {string} amount_decimal
225
+ * @param {string} asset_hi_decimal
226
+ * @param {string} asset_lo_decimal
227
+ * @param {string} application_id_decimal
228
+ * @returns {any}
229
+ */
230
+ function generateCoinForDepositWithOwnerPubHex(scalar_hex, owner_x_hex, owner_y_hex, amount_decimal, asset_hi_decimal, asset_lo_decimal, application_id_decimal) {
231
+ try {
232
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
233
+ const ptr0 = passStringToWasm0(scalar_hex, wasm.__wbindgen_export, wasm.__wbindgen_export2);
234
+ const len0 = WASM_VECTOR_LEN;
235
+ const ptr1 = passStringToWasm0(owner_x_hex, wasm.__wbindgen_export, wasm.__wbindgen_export2);
236
+ const len1 = WASM_VECTOR_LEN;
237
+ const ptr2 = passStringToWasm0(owner_y_hex, wasm.__wbindgen_export, wasm.__wbindgen_export2);
238
+ const len2 = WASM_VECTOR_LEN;
239
+ const ptr3 = passStringToWasm0(amount_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
240
+ const len3 = WASM_VECTOR_LEN;
241
+ const ptr4 = passStringToWasm0(asset_hi_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
242
+ const len4 = WASM_VECTOR_LEN;
243
+ const ptr5 = passStringToWasm0(asset_lo_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
244
+ const len5 = WASM_VECTOR_LEN;
245
+ const ptr6 = passStringToWasm0(application_id_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
246
+ const len6 = WASM_VECTOR_LEN;
247
+ wasm.generateCoinForDepositWithOwnerPubHex(retptr, ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3, ptr4, len4, ptr5, len5, ptr6, len6);
248
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
249
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
250
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
251
+ if (r2) {
252
+ throw takeObject(r1);
253
+ }
254
+ return takeObject(r0);
255
+ } finally {
256
+ wasm.__wbindgen_add_to_stack_pointer(16);
257
+ }
258
+ }
259
+
260
+ /**
261
+ * `secret` in coin = `Poseidon255(1)(scalar)` per `deposit.circom`; scalar is 32-byte hex (64 chars, optional `0x`).
262
+ * @param {string} scalar_hex
263
+ * @param {string} amount_decimal
264
+ * @param {string} asset_hi_decimal
265
+ * @param {string} asset_lo_decimal
266
+ * @param {string} application_id_decimal
267
+ * @returns {any}
268
+ */
269
+ function generateCoinFromDepositEphemeralScalarHex(scalar_hex, amount_decimal, asset_hi_decimal, asset_lo_decimal, application_id_decimal) {
270
+ try {
271
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
272
+ const ptr0 = passStringToWasm0(scalar_hex, wasm.__wbindgen_export, wasm.__wbindgen_export2);
273
+ const len0 = WASM_VECTOR_LEN;
274
+ const ptr1 = passStringToWasm0(amount_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
275
+ const len1 = WASM_VECTOR_LEN;
276
+ const ptr2 = passStringToWasm0(asset_hi_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
277
+ const len2 = WASM_VECTOR_LEN;
278
+ const ptr3 = passStringToWasm0(asset_lo_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
279
+ const len3 = WASM_VECTOR_LEN;
280
+ const ptr4 = passStringToWasm0(application_id_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
281
+ const len4 = WASM_VECTOR_LEN;
282
+ wasm.generateCoinFromDepositEphemeralScalarHex(retptr, ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3, ptr4, len4);
283
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
284
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
285
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
286
+ if (r2) {
287
+ throw takeObject(r1);
288
+ }
289
+ return takeObject(r0);
290
+ } finally {
291
+ wasm.__wbindgen_add_to_stack_pointer(16);
292
+ }
293
+ }
294
+
295
+ /**
296
+ * Same as `generateCoin`, but commitment uses the given owner public key (64-char hex coords).
297
+ * @param {string} owner_x_hex
298
+ * @param {string} owner_y_hex
299
+ * @param {string} amount_decimal
300
+ * @param {string} asset_hi_decimal
301
+ * @param {string} asset_lo_decimal
302
+ * @param {string} application_id_decimal
303
+ * @returns {any}
304
+ */
305
+ function generateCoinWithOwnerPubHex(owner_x_hex, owner_y_hex, amount_decimal, asset_hi_decimal, asset_lo_decimal, application_id_decimal) {
306
+ try {
307
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
308
+ const ptr0 = passStringToWasm0(owner_x_hex, wasm.__wbindgen_export, wasm.__wbindgen_export2);
309
+ const len0 = WASM_VECTOR_LEN;
310
+ const ptr1 = passStringToWasm0(owner_y_hex, wasm.__wbindgen_export, wasm.__wbindgen_export2);
311
+ const len1 = WASM_VECTOR_LEN;
312
+ const ptr2 = passStringToWasm0(amount_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
313
+ const len2 = WASM_VECTOR_LEN;
314
+ const ptr3 = passStringToWasm0(asset_hi_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
315
+ const len3 = WASM_VECTOR_LEN;
316
+ const ptr4 = passStringToWasm0(asset_lo_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
317
+ const len4 = WASM_VECTOR_LEN;
318
+ const ptr5 = passStringToWasm0(application_id_decimal, wasm.__wbindgen_export, wasm.__wbindgen_export2);
319
+ const len5 = WASM_VECTOR_LEN;
320
+ wasm.generateCoinWithOwnerPubHex(retptr, ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3, ptr4, len4, ptr5, len5);
321
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
322
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
323
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
324
+ if (r2) {
325
+ throw takeObject(r1);
326
+ }
327
+ return takeObject(r0);
328
+ } finally {
329
+ wasm.__wbindgen_add_to_stack_pointer(16);
330
+ }
331
+ }
332
+
333
+ /**
334
+ * Convert snarkjs proof JSON to hex bytes for Soroban contract.
335
+ * @param {string} proof_json
336
+ * @returns {string}
337
+ */
338
+ function proofToHex(proof_json) {
339
+ let deferred2_0;
340
+ let deferred2_1;
341
+ try {
342
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
343
+ const ptr0 = passStringToWasm0(proof_json, wasm.__wbindgen_export, wasm.__wbindgen_export2);
344
+ const len0 = WASM_VECTOR_LEN;
345
+ wasm.proofToHex(retptr, ptr0, len0);
346
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
347
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
348
+ deferred2_0 = r0;
349
+ deferred2_1 = r1;
350
+ return getStringFromWasm0(r0, r1);
351
+ } finally {
352
+ wasm.__wbindgen_add_to_stack_pointer(16);
353
+ wasm.__wbindgen_export4(deferred2_0, deferred2_1, 1);
354
+ }
355
+ }
356
+
357
+ /**
358
+ * Graph witness + arkworks Groth16 prove. Returns `{ proof_hex, public_hex }`.
359
+ * @param {Uint8Array} graph
360
+ * @param {Uint8Array} proving_key
361
+ * @param {Uint8Array} r1cs
362
+ * @param {string} inputs_json
363
+ * @returns {any}
364
+ */
365
+ function proveGroth16(graph, proving_key, r1cs, inputs_json) {
366
+ try {
367
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
368
+ const ptr0 = passArray8ToWasm0(graph, wasm.__wbindgen_export);
369
+ const len0 = WASM_VECTOR_LEN;
370
+ const ptr1 = passArray8ToWasm0(proving_key, wasm.__wbindgen_export);
371
+ const len1 = WASM_VECTOR_LEN;
372
+ const ptr2 = passArray8ToWasm0(r1cs, wasm.__wbindgen_export);
373
+ const len2 = WASM_VECTOR_LEN;
374
+ const ptr3 = passStringToWasm0(inputs_json, wasm.__wbindgen_export, wasm.__wbindgen_export2);
375
+ const len3 = WASM_VECTOR_LEN;
376
+ wasm.proveGroth16(retptr, ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3);
377
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
378
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
379
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
380
+ if (r2) {
381
+ throw takeObject(r1);
382
+ }
383
+ return takeObject(r0);
384
+ } finally {
385
+ wasm.__wbindgen_add_to_stack_pointer(16);
386
+ }
387
+ }
388
+
389
+ /**
390
+ * Convert snarkjs public signals JSON to hex bytes for Soroban contract.
391
+ * @param {string} public_json
392
+ * @returns {string}
393
+ */
394
+ function publicToHex(public_json) {
395
+ let deferred2_0;
396
+ let deferred2_1;
397
+ try {
398
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
399
+ const ptr0 = passStringToWasm0(public_json, wasm.__wbindgen_export, wasm.__wbindgen_export2);
400
+ const len0 = WASM_VECTOR_LEN;
401
+ wasm.publicToHex(retptr, ptr0, len0);
402
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
403
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
404
+ deferred2_0 = r0;
405
+ deferred2_1 = r1;
406
+ return getStringFromWasm0(r0, r1);
407
+ } finally {
408
+ wasm.__wbindgen_add_to_stack_pointer(16);
409
+ wasm.__wbindgen_export4(deferred2_0, deferred2_1, 1);
410
+ }
411
+ }
412
+
413
+ function __wbg_get_imports() {
414
+ const import0 = {
415
+ __proto__: null,
416
+ __wbg_String_8564e559799eccda: function(arg0, arg1) {
417
+ const ret = String(getObject(arg1));
418
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_export, wasm.__wbindgen_export2);
419
+ const len1 = WASM_VECTOR_LEN;
420
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
421
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
422
+ },
423
+ __wbg___wbindgen_is_function_3c846841762788c1: function(arg0) {
424
+ const ret = typeof(getObject(arg0)) === 'function';
425
+ return ret;
426
+ },
427
+ __wbg___wbindgen_is_object_781bc9f159099513: function(arg0) {
428
+ const val = getObject(arg0);
429
+ const ret = typeof(val) === 'object' && val !== null;
430
+ return ret;
431
+ },
432
+ __wbg___wbindgen_is_string_7ef6b97b02428fae: function(arg0) {
433
+ const ret = typeof(getObject(arg0)) === 'string';
434
+ return ret;
435
+ },
436
+ __wbg___wbindgen_is_undefined_52709e72fb9f179c: function(arg0) {
437
+ const ret = getObject(arg0) === undefined;
438
+ return ret;
439
+ },
440
+ __wbg___wbindgen_throw_6ddd609b62940d55: function(arg0, arg1) {
441
+ throw new Error(getStringFromWasm0(arg0, arg1));
442
+ },
443
+ __wbg_call_2d781c1f4d5c0ef8: function() { return handleError(function (arg0, arg1, arg2) {
444
+ const ret = getObject(arg0).call(getObject(arg1), getObject(arg2));
445
+ return addHeapObject(ret);
446
+ }, arguments); },
447
+ __wbg_crypto_38df2bab126b63dc: function(arg0) {
448
+ const ret = getObject(arg0).crypto;
449
+ return addHeapObject(ret);
450
+ },
451
+ __wbg_getRandomValues_c44a50d8cfdaebeb: function() { return handleError(function (arg0, arg1) {
452
+ getObject(arg0).getRandomValues(getObject(arg1));
453
+ }, arguments); },
454
+ __wbg_length_ea16607d7b61445b: function(arg0) {
455
+ const ret = getObject(arg0).length;
456
+ return ret;
457
+ },
458
+ __wbg_msCrypto_bd5a034af96bcba6: function(arg0) {
459
+ const ret = getObject(arg0).msCrypto;
460
+ return addHeapObject(ret);
461
+ },
462
+ __wbg_new_ab79df5bd7c26067: function() {
463
+ const ret = new Object();
464
+ return addHeapObject(ret);
465
+ },
466
+ __wbg_new_with_length_825018a1616e9e55: function(arg0) {
467
+ const ret = new Uint8Array(arg0 >>> 0);
468
+ return addHeapObject(ret);
469
+ },
470
+ __wbg_node_84ea875411254db1: function(arg0) {
471
+ const ret = getObject(arg0).node;
472
+ return addHeapObject(ret);
473
+ },
474
+ __wbg_process_44c7a14e11e9f69e: function(arg0) {
475
+ const ret = getObject(arg0).process;
476
+ return addHeapObject(ret);
477
+ },
478
+ __wbg_prototypesetcall_d62e5099504357e6: function(arg0, arg1, arg2) {
479
+ Uint8Array.prototype.set.call(getArrayU8FromWasm0(arg0, arg1), getObject(arg2));
480
+ },
481
+ __wbg_randomFillSync_6c25eac9869eb53c: function() { return handleError(function (arg0, arg1) {
482
+ getObject(arg0).randomFillSync(takeObject(arg1));
483
+ }, arguments); },
484
+ __wbg_require_b4edbdcf3e2a1ef0: function() { return handleError(function () {
485
+ const ret = module.require;
486
+ return addHeapObject(ret);
487
+ }, arguments); },
488
+ __wbg_set_6be42768c690e380: function(arg0, arg1, arg2) {
489
+ getObject(arg0)[takeObject(arg1)] = takeObject(arg2);
490
+ },
491
+ __wbg_static_accessor_GLOBAL_8adb955bd33fac2f: function() {
492
+ const ret = typeof global === 'undefined' ? null : global;
493
+ return isLikeNone(ret) ? 0 : addHeapObject(ret);
494
+ },
495
+ __wbg_static_accessor_GLOBAL_THIS_ad356e0db91c7913: function() {
496
+ const ret = typeof globalThis === 'undefined' ? null : globalThis;
497
+ return isLikeNone(ret) ? 0 : addHeapObject(ret);
498
+ },
499
+ __wbg_static_accessor_SELF_f207c857566db248: function() {
500
+ const ret = typeof self === 'undefined' ? null : self;
501
+ return isLikeNone(ret) ? 0 : addHeapObject(ret);
502
+ },
503
+ __wbg_static_accessor_WINDOW_bb9f1ba69d61b386: function() {
504
+ const ret = typeof window === 'undefined' ? null : window;
505
+ return isLikeNone(ret) ? 0 : addHeapObject(ret);
506
+ },
507
+ __wbg_subarray_a068d24e39478a8a: function(arg0, arg1, arg2) {
508
+ const ret = getObject(arg0).subarray(arg1 >>> 0, arg2 >>> 0);
509
+ return addHeapObject(ret);
510
+ },
511
+ __wbg_versions_276b2795b1c6a219: function(arg0) {
512
+ const ret = getObject(arg0).versions;
513
+ return addHeapObject(ret);
514
+ },
515
+ __wbindgen_cast_0000000000000001: function(arg0, arg1) {
516
+ // Cast intrinsic for `Ref(Slice(U8)) -> NamedExternref("Uint8Array")`.
517
+ const ret = getArrayU8FromWasm0(arg0, arg1);
518
+ return addHeapObject(ret);
519
+ },
520
+ __wbindgen_cast_0000000000000002: function(arg0, arg1) {
521
+ // Cast intrinsic for `Ref(String) -> Externref`.
522
+ const ret = getStringFromWasm0(arg0, arg1);
523
+ return addHeapObject(ret);
524
+ },
525
+ __wbindgen_object_clone_ref: function(arg0) {
526
+ const ret = getObject(arg0);
527
+ return addHeapObject(ret);
528
+ },
529
+ __wbindgen_object_drop_ref: function(arg0) {
530
+ takeObject(arg0);
531
+ },
532
+ };
533
+ return {
534
+ __proto__: null,
535
+ "./client_sdk_wasm_bg.js": import0,
536
+ };
537
+ }
538
+
539
+ function addHeapObject(obj) {
540
+ if (heap_next === heap.length) heap.push(heap.length + 1);
541
+ const idx = heap_next;
542
+ heap_next = heap[idx];
543
+
544
+ heap[idx] = obj;
545
+ return idx;
546
+ }
547
+
548
+ function dropObject(idx) {
549
+ if (idx < 1028) return;
550
+ heap[idx] = heap_next;
551
+ heap_next = idx;
552
+ }
553
+
554
+ function getArrayU8FromWasm0(ptr, len) {
555
+ ptr = ptr >>> 0;
556
+ return getUint8ArrayMemory0().subarray(ptr / 1, ptr / 1 + len);
557
+ }
558
+
559
+ let cachedDataViewMemory0 = null;
560
+ function getDataViewMemory0() {
561
+ if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer)) {
562
+ cachedDataViewMemory0 = new DataView(wasm.memory.buffer);
563
+ }
564
+ return cachedDataViewMemory0;
565
+ }
566
+
567
+ function getStringFromWasm0(ptr, len) {
568
+ ptr = ptr >>> 0;
569
+ return decodeText(ptr, len);
570
+ }
571
+
572
+ let cachedUint8ArrayMemory0 = null;
573
+ function getUint8ArrayMemory0() {
574
+ if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
575
+ cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
576
+ }
577
+ return cachedUint8ArrayMemory0;
578
+ }
579
+
580
+ function getObject(idx) { return heap[idx]; }
581
+
582
+ function handleError(f, args) {
583
+ try {
584
+ return f.apply(this, args);
585
+ } catch (e) {
586
+ wasm.__wbindgen_export3(addHeapObject(e));
587
+ }
588
+ }
589
+
590
+ let heap = new Array(1024).fill(undefined);
591
+ heap.push(undefined, null, true, false);
592
+
593
+ let heap_next = heap.length;
594
+
595
+ function isLikeNone(x) {
596
+ return x === undefined || x === null;
597
+ }
598
+
599
+ function passArray8ToWasm0(arg, malloc) {
600
+ const ptr = malloc(arg.length * 1, 1) >>> 0;
601
+ getUint8ArrayMemory0().set(arg, ptr / 1);
602
+ WASM_VECTOR_LEN = arg.length;
603
+ return ptr;
604
+ }
605
+
606
+ function passStringToWasm0(arg, malloc, realloc) {
607
+ if (realloc === undefined) {
608
+ const buf = cachedTextEncoder.encode(arg);
609
+ const ptr = malloc(buf.length, 1) >>> 0;
610
+ getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);
611
+ WASM_VECTOR_LEN = buf.length;
612
+ return ptr;
613
+ }
614
+
615
+ let len = arg.length;
616
+ let ptr = malloc(len, 1) >>> 0;
617
+
618
+ const mem = getUint8ArrayMemory0();
619
+
620
+ let offset = 0;
621
+
622
+ for (; offset < len; offset++) {
623
+ const code = arg.charCodeAt(offset);
624
+ if (code > 0x7F) break;
625
+ mem[ptr + offset] = code;
626
+ }
627
+ if (offset !== len) {
628
+ if (offset !== 0) {
629
+ arg = arg.slice(offset);
630
+ }
631
+ ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
632
+ const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
633
+ const ret = cachedTextEncoder.encodeInto(arg, view);
634
+
635
+ offset += ret.written;
636
+ ptr = realloc(ptr, len, offset, 1) >>> 0;
637
+ }
638
+
639
+ WASM_VECTOR_LEN = offset;
640
+ return ptr;
641
+ }
642
+
643
+ function takeObject(idx) {
644
+ const ret = getObject(idx);
645
+ dropObject(idx);
646
+ return ret;
647
+ }
648
+
649
+ let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
650
+ cachedTextDecoder.decode();
651
+ const MAX_SAFARI_DECODE_BYTES = 2146435072;
652
+ let numBytesDecoded = 0;
653
+ function decodeText(ptr, len) {
654
+ numBytesDecoded += len;
655
+ if (numBytesDecoded >= MAX_SAFARI_DECODE_BYTES) {
656
+ cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
657
+ cachedTextDecoder.decode();
658
+ numBytesDecoded = len;
659
+ }
660
+ return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
661
+ }
662
+
663
+ const cachedTextEncoder = new TextEncoder();
664
+
665
+ if (!('encodeInto' in cachedTextEncoder)) {
666
+ cachedTextEncoder.encodeInto = function (arg, view) {
667
+ const buf = cachedTextEncoder.encode(arg);
668
+ view.set(buf);
669
+ return {
670
+ read: arg.length,
671
+ written: buf.length
672
+ };
673
+ };
674
+ }
675
+
676
+ let WASM_VECTOR_LEN = 0;
677
+
678
+ let wasm;
679
+ function __wbg_finalize_init(instance, module) {
680
+ wasm = instance.exports;
681
+ cachedDataViewMemory0 = null;
682
+ cachedUint8ArrayMemory0 = null;
683
+ return wasm;
684
+ }
685
+
686
+ async function __wbg_load(module, imports) {
687
+ if (typeof Response === 'function' && module instanceof Response) {
688
+ if (typeof WebAssembly.instantiateStreaming === 'function') {
689
+ try {
690
+ return await WebAssembly.instantiateStreaming(module, imports);
691
+ } catch (e) {
692
+ const validResponse = module.ok && expectedResponseType(module.type);
693
+
694
+ if (validResponse && module.headers.get('Content-Type') !== 'application/wasm') {
695
+ 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);
696
+
697
+ } else { throw e; }
698
+ }
699
+ }
700
+
701
+ const bytes = await module.arrayBuffer();
702
+ return await WebAssembly.instantiate(bytes, imports);
703
+ } else {
704
+ const instance = await WebAssembly.instantiate(module, imports);
705
+
706
+ if (instance instanceof WebAssembly.Instance) {
707
+ return { instance, module };
708
+ } else {
709
+ return instance;
710
+ }
711
+ }
712
+
713
+ function expectedResponseType(type) {
714
+ switch (type) {
715
+ case 'basic': case 'cors': case 'default': return true;
716
+ }
717
+ return false;
718
+ }
719
+ }
720
+
721
+ function initSync(module) {
722
+ if (wasm !== undefined) return wasm;
723
+
724
+
725
+ if (module !== undefined) {
726
+ if (Object.getPrototypeOf(module) === Object.prototype) {
727
+ ({module} = module);
728
+ } else {
729
+ console.warn('using deprecated parameters for `initSync()`; pass a single object instead');
730
+ }
731
+ }
732
+
733
+ const imports = __wbg_get_imports();
734
+ if (!(module instanceof WebAssembly.Module)) {
735
+ module = new WebAssembly.Module(module);
736
+ }
737
+ const instance = new WebAssembly.Instance(module, imports);
738
+ return __wbg_finalize_init(instance);
739
+ }
740
+
741
+ async function __wbg_init(module_or_path) {
742
+ if (wasm !== undefined) return wasm;
743
+
744
+
745
+ if (module_or_path !== undefined) {
746
+ if (Object.getPrototypeOf(module_or_path) === Object.prototype) {
747
+ ({module_or_path} = module_or_path);
748
+ } else {
749
+ console.warn('using deprecated parameters for the initialization function; pass a single object instead');
750
+ }
751
+ }
752
+
753
+ if (module_or_path === undefined) {
754
+ module_or_path = new URL('client_sdk_wasm_bg.wasm', import.meta.url);
755
+ }
756
+ const imports = __wbg_get_imports();
757
+
758
+ if (typeof module_or_path === 'string' || (typeof Request === 'function' && module_or_path instanceof Request) || (typeof URL === 'function' && module_or_path instanceof URL)) {
759
+ module_or_path = fetch(module_or_path);
760
+ }
761
+
762
+ const { instance, module } = await __wbg_load(await module_or_path, imports);
763
+
764
+ return __wbg_finalize_init(instance);
765
+ }
766
+
767
+ var wasmBindings = /*#__PURE__*/Object.freeze({
768
+ __proto__: null,
769
+ buildWithdrawMerkleWitness: buildWithdrawMerkleWitness,
770
+ calculateNullifierHash: calculateNullifierHash,
771
+ default: __wbg_init,
772
+ derivedEscrowKey: derivedEscrowKey$1,
773
+ ecdhEphemeralPublicKey: ecdhEphemeralPublicKey,
774
+ ecdhEphemeralPublicKeyFromScalarHex: ecdhEphemeralPublicKeyFromScalarHex,
775
+ ecdhSharedKey: ecdhSharedKey,
776
+ generateCoin: generateCoin,
777
+ generateCoinForDepositWithOwnerPubHex: generateCoinForDepositWithOwnerPubHex,
778
+ generateCoinFromDepositEphemeralScalarHex: generateCoinFromDepositEphemeralScalarHex,
779
+ generateCoinWithOwnerPubHex: generateCoinWithOwnerPubHex,
780
+ initSync: initSync,
781
+ proofToHex: proofToHex,
782
+ proveGroth16: proveGroth16,
783
+ publicToHex: publicToHex
784
+ });
785
+
786
+ const isNode$1 = typeof process !== 'undefined' && !!process.versions?.node;
787
+ let wasmModule = null;
788
+ async function loadWasm(wasmBinary) {
789
+ if (wasmModule)
790
+ return wasmModule;
791
+ if (isNode$1) {
792
+ if (wasmBinary) {
793
+ initSync({ module: wasmBinary });
794
+ }
795
+ else {
796
+ const path = await import('path');
797
+ const { fileURLToPath } = await import('url');
798
+ const fs = await import('fs');
799
+ const dir = path.dirname(fileURLToPath(import.meta.url));
800
+ const wasmPath = path.resolve(dir, '..', 'pkg', 'client_sdk_wasm_bg.wasm');
801
+ const buffer = fs.readFileSync(wasmPath);
802
+ initSync({ module: buffer });
803
+ }
804
+ wasmModule = wasmBindings;
805
+ }
806
+ else {
807
+ if (wasmBinary) {
808
+ initSync({ module: wasmBinary });
809
+ }
810
+ else {
811
+ await __wbg_init();
812
+ }
813
+ wasmModule = wasmBindings;
814
+ }
815
+ return wasmModule;
816
+ }
817
+
818
+ /** Off-chain ZK layout table. Must stay byte-identical to `libs/zk::ZkLayoutParams`. */
819
+ const LEGACY_ZK_NONCE = 0n;
820
+ const COMMITMENT_V2_ZK_NONCE = 2n;
821
+ const BINDING_ZK_NONCE = 3n;
822
+ const SIX_BY_SIX_ZK_NONCE = 6n;
823
+ const SIX_BY_SIX_BINDING_ZK_NONCE = 7n;
824
+ const LEGACY_PUBLIC_INPUT_PREFIX_LEN = 5;
825
+ const V2_PUBLIC_INPUT_PREFIX_LEN = 7;
826
+ const NOTE_AUDIT_LEN$3 = 12;
827
+ const NOTE_OUTPUT_LEN$2 = 6;
828
+ var BundledZkCircuit;
829
+ (function (BundledZkCircuit) {
830
+ BundledZkCircuit["TwoByTwo"] = "2x2";
831
+ BundledZkCircuit["SixBySix"] = "6x6";
832
+ })(BundledZkCircuit || (BundledZkCircuit = {}));
833
+ function isDevZkCircuitConfig(config) {
834
+ return !('circuit' in config);
835
+ }
836
+ const DEFAULT_ZK_CONFIG_NONCE = BINDING_ZK_NONCE;
837
+ const DEFAULT_ZK_CIRCUITS = {
838
+ [BINDING_ZK_NONCE.toString()]: {
839
+ nIns: 2,
840
+ nOuts: 2,
841
+ publicNInputs: 1,
842
+ publicNOutputs: 1,
843
+ circuit: BundledZkCircuit.TwoByTwo,
844
+ },
845
+ [SIX_BY_SIX_BINDING_ZK_NONCE.toString()]: {
846
+ nIns: 6,
847
+ nOuts: 6,
848
+ publicNInputs: 1,
849
+ publicNOutputs: 1,
850
+ circuit: BundledZkCircuit.SixBySix,
851
+ },
852
+ };
853
+ function layoutFromCircuitConfig(config) {
854
+ return zkLayoutFromShapeBinding(config.nIns, config.nOuts, config.publicNInputs, config.publicNOutputs, config.nIns + config.nOuts, NOTE_AUDIT_LEN$3, NOTE_OUTPUT_LEN$2);
855
+ }
856
+ function resolveZkCircuitConfig(zkCircuits, zkConfigNonce) {
857
+ const nonce = zkConfigNonce ?? DEFAULT_ZK_CONFIG_NONCE;
858
+ const circuits = zkCircuits ?? DEFAULT_ZK_CIRCUITS;
859
+ const config = circuits[nonce.toString()];
860
+ if (!config) {
861
+ throw new Error(`no zk circuit configured for nonce ${nonce.toString()}`);
862
+ }
863
+ return { nonce, config };
864
+ }
865
+ function bundledCircuitFileNames(circuit) {
866
+ if (circuit === BundledZkCircuit.SixBySix) {
867
+ return {
868
+ graphFileName: 'main_6x6.graph.bin',
869
+ r1csFileName: 'main_6x6.r1cs.gz',
870
+ provingKeyFileName: 'main_6x6_proving_key.bin',
871
+ verificationKeyFileName: 'main_6x6_verification_key.json',
872
+ zkeyFileName: 'main_6x6_final.zkey',
873
+ };
874
+ }
875
+ return {
876
+ graphFileName: 'main.graph.bin',
877
+ r1csFileName: 'main.r1cs.gz',
878
+ provingKeyFileName: 'main_proving_key.bin',
879
+ verificationKeyFileName: 'main_verification_key.json',
880
+ zkeyFileName: 'main_final.zkey',
881
+ };
882
+ }
883
+ function zkLayoutFromShape(nIns, nOuts, publicNInputs, publicNOutputs, nAuditSlots, noteAuditLen, noteOutputLen, publicInputPrefixLen = LEGACY_PUBLIC_INPUT_PREFIX_LEN) {
884
+ const auditOffset = nIns + nOuts + nOuts * 2;
885
+ const outputNoteOffset = auditOffset + nAuditSlots * 2 + nAuditSlots * noteAuditLen + nAuditSlots;
886
+ return {
887
+ nIns,
888
+ nOuts,
889
+ publicNInputs,
890
+ publicNOutputs,
891
+ nAuditSlots,
892
+ noteAuditLen,
893
+ noteOutputLen,
894
+ publicInputPrefixLen,
895
+ auditOffset,
896
+ outputNoteOffset,
897
+ };
898
+ }
899
+ function zkLayoutFromShapeBinding(nIns, nOuts, publicNInputs, publicNOutputs, nAuditSlots, noteAuditLen, noteOutputLen) {
900
+ const auditOffset = nIns + nOuts + nOuts * 2;
901
+ const outputNoteOffset = auditOffset + 2 + nAuditSlots;
902
+ return {
903
+ nIns,
904
+ nOuts,
905
+ publicNInputs,
906
+ publicNOutputs,
907
+ nAuditSlots,
908
+ noteAuditLen,
909
+ noteOutputLen,
910
+ publicInputPrefixLen: V2_PUBLIC_INPUT_PREFIX_LEN,
911
+ auditOffset,
912
+ outputNoteOffset,
913
+ };
914
+ }
915
+ function ciphertextsInPublicSignals(layout) {
916
+ const withCiphertext = layout.auditOffset +
917
+ layout.nAuditSlots * 2 +
918
+ layout.nAuditSlots * layout.noteAuditLen +
919
+ layout.nAuditSlots;
920
+ return layout.outputNoteOffset === withCiphertext;
921
+ }
922
+ function ciphertextFieldCount(layout) {
923
+ return layout.nAuditSlots * layout.noteAuditLen + layout.nOuts * layout.noteOutputLen;
924
+ }
925
+ function auditEphemeralPublicKeyCount(layout) {
926
+ return ciphertextsInPublicSignals(layout) ? layout.nAuditSlots : 1;
927
+ }
928
+ function indexAuditTags(layout) {
929
+ if (ciphertextsInPublicSignals(layout)) {
930
+ return (layout.auditOffset +
931
+ layout.nAuditSlots * 2 +
932
+ layout.nAuditSlots * layout.noteAuditLen);
933
+ }
934
+ return layout.auditOffset + auditEphemeralPublicKeyCount(layout) * 2;
935
+ }
936
+ function indexOutputNoteTags(layout) {
937
+ if (ciphertextsInPublicSignals(layout)) {
938
+ return layout.outputNoteOffset + layout.nOuts * layout.noteOutputLen;
939
+ }
940
+ return layout.outputNoteOffset;
941
+ }
942
+ function publicOutputsLen(layout) {
943
+ if (ciphertextsInPublicSignals(layout)) {
944
+ return layout.outputNoteOffset + layout.nOuts * layout.noteOutputLen + layout.nOuts;
945
+ }
946
+ return layout.outputNoteOffset + layout.nOuts;
947
+ }
948
+ function totalPublicSignals(layout) {
949
+ return (publicOutputsLen(layout) +
950
+ layout.publicInputPrefixLen +
951
+ 2 * layout.publicNInputs +
952
+ 2 * layout.publicNOutputs +
953
+ layout.publicNInputs +
954
+ layout.publicNOutputs);
955
+ }
956
+ function stateRootIndex(layout) {
957
+ return publicOutputsLen(layout);
958
+ }
959
+ function legacyOwnerBoundLayout() {
960
+ return zkLayoutFromShape(2, 2, 1, 1, 4, NOTE_AUDIT_LEN$3, NOTE_OUTPUT_LEN$2);
961
+ }
962
+ function standardLayout() {
963
+ return zkLayoutFromShape(2, 2, 1, 1, 4, NOTE_AUDIT_LEN$3, NOTE_OUTPUT_LEN$2, V2_PUBLIC_INPUT_PREFIX_LEN);
964
+ }
965
+ function sixBySixLayout() {
966
+ return zkLayoutFromShape(6, 6, 1, 1, 12, NOTE_AUDIT_LEN$3, NOTE_OUTPUT_LEN$2, V2_PUBLIC_INPUT_PREFIX_LEN);
967
+ }
968
+ function standardBindingLayout() {
969
+ return zkLayoutFromShapeBinding(2, 2, 1, 1, 4, NOTE_AUDIT_LEN$3, NOTE_OUTPUT_LEN$2);
970
+ }
971
+ function sixBySixBindingLayout() {
972
+ return zkLayoutFromShapeBinding(6, 6, 1, 1, 12, NOTE_AUDIT_LEN$3, NOTE_OUTPUT_LEN$2);
973
+ }
974
+ function layoutForKnownNonce(nonce) {
975
+ if (nonce === LEGACY_ZK_NONCE) {
976
+ return legacyOwnerBoundLayout();
977
+ }
978
+ if (nonce === COMMITMENT_V2_ZK_NONCE) {
979
+ return standardLayout();
980
+ }
981
+ if (nonce === BINDING_ZK_NONCE) {
982
+ return standardBindingLayout();
983
+ }
984
+ if (nonce === SIX_BY_SIX_ZK_NONCE) {
985
+ return sixBySixLayout();
986
+ }
987
+ if (nonce === SIX_BY_SIX_BINDING_ZK_NONCE) {
988
+ return sixBySixBindingLayout();
989
+ }
990
+ throw new Error(`unknown zk config nonce ${nonce.toString()}`);
991
+ }
992
+ function circuitProfileFromName(name) {
993
+ const normalized = name.trim().toLowerCase();
994
+ if (normalized === '6x6' || normalized === 'six' || normalized === '6') {
995
+ return {
996
+ name: '6x6',
997
+ nonce: SIX_BY_SIX_BINDING_ZK_NONCE,
998
+ layout: sixBySixBindingLayout(),
999
+ wasmFileName: 'main_6x6.wasm',
1000
+ zkeyFileName: 'main_6x6_final.zkey',
1001
+ };
1002
+ }
1003
+ if (normalized === '2x2' || normalized === 'standard' || normalized === '2') {
1004
+ return {
1005
+ name: '2x2',
1006
+ nonce: BINDING_ZK_NONCE,
1007
+ layout: standardBindingLayout(),
1008
+ wasmFileName: 'main.wasm',
1009
+ zkeyFileName: 'main_final.zkey',
1010
+ };
1011
+ }
1012
+ throw new Error(`unknown circuit profile ${name}`);
1013
+ }
1014
+ function circuitProfileFromNonce(nonce) {
1015
+ if (nonce === SIX_BY_SIX_ZK_NONCE ||
1016
+ nonce === SIX_BY_SIX_BINDING_ZK_NONCE) {
1017
+ return circuitProfileFromName('6x6');
1018
+ }
1019
+ return circuitProfileFromName('2x2');
1020
+ }
1021
+
1022
+ const ZK_ARTIFACT_GITHUB_REPO = "Polynom-Labs/stellar-privacy-layer-contracts";
1023
+ const ZK_SDK_PACKAGE_VERSION = "0.8.0";
1024
+ function defaultZkArtifactBaseUrl(version = ZK_SDK_PACKAGE_VERSION) {
1025
+ const tag = version.startsWith("v") ? version.slice(1) : version;
1026
+ return `https://github.com/${ZK_ARTIFACT_GITHUB_REPO}/releases/download/v${tag}`;
1027
+ }
1028
+ function trimArtifactBaseUrl(value) {
1029
+ let trimmed = value.trim();
1030
+ while (trimmed.endsWith("/")) {
1031
+ trimmed = trimmed.slice(0, -1);
1032
+ }
1033
+ return trimmed;
1034
+ }
1035
+
1036
+ const isNode = typeof process !== 'undefined' && !!process.versions?.node;
1037
+ function toUint8Array(src) {
1038
+ if (src instanceof Uint8Array) {
1039
+ return src;
1040
+ }
1041
+ if (src instanceof ArrayBuffer) {
1042
+ return new Uint8Array(src);
1043
+ }
1044
+ return new Uint8Array(src.buffer, src.byteOffset, src.byteLength);
1045
+ }
1046
+ function nodeEnvArtifactBaseUrl() {
1047
+ if (!isNode) {
1048
+ return undefined;
1049
+ }
1050
+ const fromEnv = process.env.ZK_ARTIFACT_BASE_URL?.trim();
1051
+ return fromEnv ? trimArtifactBaseUrl(fromEnv) : undefined;
1052
+ }
1053
+ function resolveZkArtifactBaseUrl(explicit) {
1054
+ const trimmed = explicit?.trim();
1055
+ if (trimmed) {
1056
+ return trimArtifactBaseUrl(trimmed);
1057
+ }
1058
+ return nodeEnvArtifactBaseUrl() ?? defaultZkArtifactBaseUrl();
1059
+ }
1060
+ function isHttpUrl(value) {
1061
+ return /^https?:\/\//i.test(value) || value.startsWith('file:');
1062
+ }
1063
+ async function readNodeAssetFile(filePath) {
1064
+ const fs = await import('fs');
1065
+ if (!fs.existsSync(filePath)) {
1066
+ throw new Error(`Circuit artifact not found at ${filePath}. Set zkArtifactBaseUrl or ZK_ARTIFACT_BASE_URL.`);
1067
+ }
1068
+ return fs.readFileSync(filePath);
1069
+ }
1070
+ async function fetchArtifact(url) {
1071
+ const response = await fetch(url);
1072
+ if (!response.ok) {
1073
+ throw new Error(`Failed to fetch ${url}: ${String(response.status)}`);
1074
+ }
1075
+ return new Uint8Array(await response.arrayBuffer());
1076
+ }
1077
+ function remoteArtifactHref(base, fileName) {
1078
+ const withSlash = `${trimArtifactBaseUrl(base)}/`;
1079
+ if (isHttpUrl(withSlash)) {
1080
+ return new URL(fileName, withSlash).href;
1081
+ }
1082
+ if (typeof window !== 'undefined') {
1083
+ return new URL(fileName, new URL(withSlash, window.location.href)).href;
1084
+ }
1085
+ return `${withSlash}${fileName}`;
1086
+ }
1087
+ async function loadNamedArtifact(base, fileName) {
1088
+ if (isNode && !isHttpUrl(base)) {
1089
+ const nodePath = await import('path');
1090
+ return readNodeAssetFile(nodePath.resolve(base, fileName));
1091
+ }
1092
+ return fetchArtifact(remoteArtifactHref(base, fileName));
1093
+ }
1094
+ async function loadBundledCircuitArtifacts(circuit, artifactBaseUrl) {
1095
+ const base = resolveZkArtifactBaseUrl(artifactBaseUrl);
1096
+ const names = bundledCircuitFileNames(circuit);
1097
+ const [graph, r1cs, provingKey] = await Promise.all([
1098
+ loadNamedArtifact(base, names.graphFileName),
1099
+ loadNamedArtifact(base, names.r1csFileName),
1100
+ loadNamedArtifact(base, names.provingKeyFileName),
1101
+ ]);
1102
+ return { graph, r1cs, provingKey };
1103
+ }
1104
+ async function resolveCircuitArtifacts(config, artifactBaseUrl) {
1105
+ if (isDevZkCircuitConfig(config)) {
1106
+ return {
1107
+ graph: toUint8Array(config.circuitGraph),
1108
+ r1cs: toUint8Array(config.r1cs),
1109
+ provingKey: toUint8Array(config.provingKey),
1110
+ };
1111
+ }
1112
+ return loadBundledCircuitArtifacts(config.circuit, artifactBaseUrl);
1113
+ }
1114
+
1115
+ var dist = {};
1116
+
1117
+ Object.defineProperty(dist, "__esModule", { value: true });
1118
+ dist.bech32m = bech32 = dist.bech32 = void 0;
1119
+ const ALPHABET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l';
1120
+ const ALPHABET_MAP = {};
1121
+ for (let z = 0; z < ALPHABET.length; z++) {
1122
+ const x = ALPHABET.charAt(z);
1123
+ ALPHABET_MAP[x] = z;
1124
+ }
1125
+ function polymodStep(pre) {
1126
+ const b = pre >> 25;
1127
+ return (((pre & 0x1ffffff) << 5) ^
1128
+ (-((b >> 0) & 1) & 0x3b6a57b2) ^
1129
+ (-((b >> 1) & 1) & 0x26508e6d) ^
1130
+ (-((b >> 2) & 1) & 0x1ea119fa) ^
1131
+ (-((b >> 3) & 1) & 0x3d4233dd) ^
1132
+ (-((b >> 4) & 1) & 0x2a1462b3));
1133
+ }
1134
+ function prefixChk(prefix) {
1135
+ let chk = 1;
1136
+ for (let i = 0; i < prefix.length; ++i) {
1137
+ const c = prefix.charCodeAt(i);
1138
+ if (c < 33 || c > 126)
1139
+ return 'Invalid prefix (' + prefix + ')';
1140
+ chk = polymodStep(chk) ^ (c >> 5);
1141
+ }
1142
+ chk = polymodStep(chk);
1143
+ for (let i = 0; i < prefix.length; ++i) {
1144
+ const v = prefix.charCodeAt(i);
1145
+ chk = polymodStep(chk) ^ (v & 0x1f);
1146
+ }
1147
+ return chk;
1148
+ }
1149
+ function convert(data, inBits, outBits, pad) {
1150
+ let value = 0;
1151
+ let bits = 0;
1152
+ const maxV = (1 << outBits) - 1;
1153
+ const result = [];
1154
+ for (let i = 0; i < data.length; ++i) {
1155
+ value = (value << inBits) | data[i];
1156
+ bits += inBits;
1157
+ while (bits >= outBits) {
1158
+ bits -= outBits;
1159
+ result.push((value >> bits) & maxV);
1160
+ }
1161
+ }
1162
+ if (pad) {
1163
+ if (bits > 0) {
1164
+ result.push((value << (outBits - bits)) & maxV);
1165
+ }
1166
+ }
1167
+ else {
1168
+ if (bits >= inBits)
1169
+ return 'Excess padding';
1170
+ if ((value << (outBits - bits)) & maxV)
1171
+ return 'Non-zero padding';
1172
+ }
1173
+ return result;
1174
+ }
1175
+ function toWords(bytes) {
1176
+ return convert(bytes, 8, 5, true);
1177
+ }
1178
+ function fromWordsUnsafe(words) {
1179
+ const res = convert(words, 5, 8, false);
1180
+ if (Array.isArray(res))
1181
+ return res;
1182
+ }
1183
+ function fromWords(words) {
1184
+ const res = convert(words, 5, 8, false);
1185
+ if (Array.isArray(res))
1186
+ return res;
1187
+ throw new Error(res);
1188
+ }
1189
+ function getLibraryFromEncoding(encoding) {
1190
+ let ENCODING_CONST;
1191
+ if (encoding === 'bech32') {
1192
+ ENCODING_CONST = 1;
1193
+ }
1194
+ else {
1195
+ ENCODING_CONST = 0x2bc830a3;
1196
+ }
1197
+ function encode(prefix, words, LIMIT) {
1198
+ LIMIT = LIMIT || 90;
1199
+ if (prefix.length + 7 + words.length > LIMIT)
1200
+ throw new TypeError('Exceeds length limit');
1201
+ prefix = prefix.toLowerCase();
1202
+ // determine chk mod
1203
+ let chk = prefixChk(prefix);
1204
+ if (typeof chk === 'string')
1205
+ throw new Error(chk);
1206
+ let result = prefix + '1';
1207
+ for (let i = 0; i < words.length; ++i) {
1208
+ const x = words[i];
1209
+ if (x >> 5 !== 0)
1210
+ throw new Error('Non 5-bit word');
1211
+ chk = polymodStep(chk) ^ x;
1212
+ result += ALPHABET.charAt(x);
1213
+ }
1214
+ for (let i = 0; i < 6; ++i) {
1215
+ chk = polymodStep(chk);
1216
+ }
1217
+ chk ^= ENCODING_CONST;
1218
+ for (let i = 0; i < 6; ++i) {
1219
+ const v = (chk >> ((5 - i) * 5)) & 0x1f;
1220
+ result += ALPHABET.charAt(v);
1221
+ }
1222
+ return result;
1223
+ }
1224
+ function __decode(str, LIMIT) {
1225
+ LIMIT = LIMIT || 90;
1226
+ if (str.length < 8)
1227
+ return str + ' too short';
1228
+ if (str.length > LIMIT)
1229
+ return 'Exceeds length limit';
1230
+ // don't allow mixed case
1231
+ const lowered = str.toLowerCase();
1232
+ const uppered = str.toUpperCase();
1233
+ if (str !== lowered && str !== uppered)
1234
+ return 'Mixed-case string ' + str;
1235
+ str = lowered;
1236
+ const split = str.lastIndexOf('1');
1237
+ if (split === -1)
1238
+ return 'No separator character for ' + str;
1239
+ if (split === 0)
1240
+ return 'Missing prefix for ' + str;
1241
+ const prefix = str.slice(0, split);
1242
+ const wordChars = str.slice(split + 1);
1243
+ if (wordChars.length < 6)
1244
+ return 'Data too short';
1245
+ let chk = prefixChk(prefix);
1246
+ if (typeof chk === 'string')
1247
+ return chk;
1248
+ const words = [];
1249
+ for (let i = 0; i < wordChars.length; ++i) {
1250
+ const c = wordChars.charAt(i);
1251
+ const v = ALPHABET_MAP[c];
1252
+ if (v === undefined)
1253
+ return 'Unknown character ' + c;
1254
+ chk = polymodStep(chk) ^ v;
1255
+ // not in the checksum?
1256
+ if (i + 6 >= wordChars.length)
1257
+ continue;
1258
+ words.push(v);
1259
+ }
1260
+ if (chk !== ENCODING_CONST)
1261
+ return 'Invalid checksum for ' + str;
1262
+ return { prefix, words };
1263
+ }
1264
+ function decodeUnsafe(str, LIMIT) {
1265
+ const res = __decode(str, LIMIT);
1266
+ if (typeof res === 'object')
1267
+ return res;
1268
+ }
1269
+ function decode(str, LIMIT) {
1270
+ const res = __decode(str, LIMIT);
1271
+ if (typeof res === 'object')
1272
+ return res;
1273
+ throw new Error(res);
1274
+ }
1275
+ return {
1276
+ decodeUnsafe,
1277
+ decode,
1278
+ encode,
1279
+ toWords,
1280
+ fromWordsUnsafe,
1281
+ fromWords,
1282
+ };
1283
+ }
1284
+ var bech32 = dist.bech32 = getLibraryFromEncoding('bech32');
1285
+ dist.bech32m = getLibraryFromEncoding('bech32m');
1286
+
1287
+ /** Bech32 HRP for {@link DecodedEphemeralKey} only (`x ‖ y`, 64 bytes). */
1288
+ const DECODED_EPHEMERAL_HRP = 'epk1';
1289
+ /** Bech32 HRP for {@link DecodedDepositorSharedSecretPreimage} (96 bytes). */
1290
+ const DEPOSITOR_SHARED_SECRET_PREIMAGE_HRP = 'epk_dep_pre1';
1291
+ const FIELD_BYTES$1 = 32;
1292
+ const EPK_POINT_PAYLOAD = FIELD_BYTES$1 * 2;
1293
+ const EPK_DEP_PRE_PAYLOAD = FIELD_BYTES$1 * 3;
1294
+ const BECH32_LONG_LIMIT = 1023;
1295
+ function normalizeHex$3(hex) {
1296
+ const s = hex.trim().replace(/^0x/i, '');
1297
+ if (!/^[0-9a-fA-F]*$/.test(s)) {
1298
+ throw new Error('ephemeral-key: hex must contain only 0-9, a-f');
1299
+ }
1300
+ return s.length % 2 === 0 ? s : `0${s}`;
1301
+ }
1302
+ function hexToBytes$2(hex) {
1303
+ const norm = normalizeHex$3(hex);
1304
+ const out = new Uint8Array(norm.length / 2);
1305
+ for (let i = 0; i < out.length; i++) {
1306
+ out[i] = parseInt(norm.slice(i * 2, i * 2 + 2), 16);
1307
+ }
1308
+ return out;
1309
+ }
1310
+ function bytesToHex$2(bytes) {
1311
+ let s = '';
1312
+ for (let i = 0; i < bytes.length; i++) {
1313
+ s += bytes[i].toString(16).padStart(2, '0');
1314
+ }
1315
+ return s;
1316
+ }
1317
+ function concat2(a, b) {
1318
+ const out = new Uint8Array(a.length + b.length);
1319
+ out.set(a, 0);
1320
+ out.set(b, a.length);
1321
+ return out;
1322
+ }
1323
+ function concat3(a, b, c) {
1324
+ const out = new Uint8Array(a.length + b.length + c.length);
1325
+ out.set(a, 0);
1326
+ out.set(b, a.length);
1327
+ out.set(c, a.length + b.length);
1328
+ return out;
1329
+ }
1330
+ function require32(label, bytes) {
1331
+ if (bytes.length !== FIELD_BYTES$1) {
1332
+ throw new Error(`ephemeral-key: ${label} must encode exactly ${FIELD_BYTES$1} bytes, got ${bytes.length}`);
1333
+ }
1334
+ }
1335
+ /**
1336
+ * 32-byte big-endian integer as hex (64 chars), **< 2^253**, so BabyJub ECDH matches
1337
+ * `circuits/encryption.circom` `Num2Bits(253)` and `libs/cryptography` `scalar_mul_253`.
1338
+ */
1339
+ function generateRandomScalarHex32() {
1340
+ const g = globalThis.crypto;
1341
+ if (!g?.getRandomValues) {
1342
+ throw new Error('ephemeral-key: crypto.getRandomValues is required');
1343
+ }
1344
+ const max = 1n << 253n;
1345
+ for (let attempt = 0; attempt < 65536; attempt++) {
1346
+ const b = new Uint8Array(32);
1347
+ g.getRandomValues(b);
1348
+ const hex = bytesToHex$2(b);
1349
+ if (BigInt(`0x${hex}`) < max) {
1350
+ return hex;
1351
+ }
1352
+ }
1353
+ throw new Error('ephemeral-key: failed to sample scalar < 2^253');
1354
+ }
1355
+ /** Bech32 `epk1`: encodes `x ‖ y` (64 bytes). */
1356
+ function encodeDecodedEphemeralKey(decoded) {
1357
+ const xb = hexToBytes$2(decoded.x);
1358
+ const yb = hexToBytes$2(decoded.y);
1359
+ require32('x', xb);
1360
+ require32('y', yb);
1361
+ const payload = concat2(xb, yb);
1362
+ const words = bech32.toWords(payload);
1363
+ return bech32.encode(DECODED_EPHEMERAL_HRP, words, BECH32_LONG_LIMIT);
1364
+ }
1365
+ function decodeDecodedEphemeralKey(encoded) {
1366
+ const { prefix, words } = bech32.decode(encoded, BECH32_LONG_LIMIT);
1367
+ if (prefix !== DECODED_EPHEMERAL_HRP) {
1368
+ throw new Error(`ephemeral-key: expected HRP ${DECODED_EPHEMERAL_HRP}, got ${JSON.stringify(prefix)}`);
1369
+ }
1370
+ const bytes = new Uint8Array(bech32.fromWords(words));
1371
+ if (bytes.length !== EPK_POINT_PAYLOAD) {
1372
+ throw new Error(`ephemeral-key: epk1 payload must be ${EPK_POINT_PAYLOAD} bytes, got ${bytes.length}`);
1373
+ }
1374
+ return {
1375
+ x: bytesToHex$2(bytes.subarray(0, FIELD_BYTES$1)),
1376
+ y: bytesToHex$2(bytes.subarray(FIELD_BYTES$1)),
1377
+ };
1378
+ }
1379
+ /** Bech32 `epk_dep_pre1`: `randomNonceScalar ‖ recipient.x ‖ recipient.y`. */
1380
+ function encodeDepositorSharedSecretPreimage(decoded) {
1381
+ const sb = hexToBytes$2(decoded.randomNonceScalar);
1382
+ const xb = hexToBytes$2(decoded.recipientStealthAddress.x);
1383
+ const yb = hexToBytes$2(decoded.recipientStealthAddress.y);
1384
+ require32('randomNonceScalar', sb);
1385
+ require32('recipientStealthAddress.x', xb);
1386
+ require32('recipientStealthAddress.y', yb);
1387
+ const payload = concat3(sb, xb, yb);
1388
+ const words = bech32.toWords(payload);
1389
+ return bech32.encode(DEPOSITOR_SHARED_SECRET_PREIMAGE_HRP, words, BECH32_LONG_LIMIT);
1390
+ }
1391
+ function decodeDepositorSharedSecretPreimage(encoded) {
1392
+ const { prefix, words } = bech32.decode(encoded, BECH32_LONG_LIMIT);
1393
+ if (prefix !== DEPOSITOR_SHARED_SECRET_PREIMAGE_HRP) {
1394
+ throw new Error(`ephemeral-key: expected HRP ${DEPOSITOR_SHARED_SECRET_PREIMAGE_HRP}, got ${JSON.stringify(prefix)}`);
1395
+ }
1396
+ const bytes = new Uint8Array(bech32.fromWords(words));
1397
+ if (bytes.length !== EPK_DEP_PRE_PAYLOAD) {
1398
+ throw new Error(`ephemeral-key: epk_dep_pre1 payload must be ${EPK_DEP_PRE_PAYLOAD} bytes, got ${bytes.length}`);
1399
+ }
1400
+ return {
1401
+ randomNonceScalar: bytesToHex$2(bytes.subarray(0, FIELD_BYTES$1)),
1402
+ recipientStealthAddress: {
1403
+ x: bytesToHex$2(bytes.subarray(FIELD_BYTES$1, FIELD_BYTES$1 * 2)),
1404
+ y: bytesToHex$2(bytes.subarray(FIELD_BYTES$1 * 2)),
1405
+ },
1406
+ };
1407
+ }
1408
+
1409
+ /**
1410
+ * Depositor: `randomNonceScalar * recipientStealthPoint` (same as circom `ECDH` with depositor scalar).
1411
+ */
1412
+ function sharedSecretFromDepositorPreimage(ecdhShared, preimage) {
1413
+ const out = ecdhShared(preimage.randomNonceScalar, preimage.recipientStealthAddress.x, preimage.recipientStealthAddress.y);
1414
+ return { x: out.x, y: out.y };
1415
+ }
1416
+ /**
1417
+ * Recipient: `recipientScalar * ephemeralKey` (same shared point as depositor path when keys match).
1418
+ */
1419
+ function sharedSecretFromRecipientPreimage(ecdhShared, preimage) {
1420
+ const out = ecdhShared(preimage.recipientScalar, preimage.ephemeralKey.x, preimage.ephemeralKey.y);
1421
+ return { x: out.x, y: out.y };
1422
+ }
1423
+
1424
+ const STEALTH_ADDRESS_HRP = 'stpl1';
1425
+ /** BIP-173 default 90 is too small for 64-byte payload (32+32 field coords) after 8→5 bit conversion. */
1426
+ const BECH32_STEALTH_LIMIT = 1023;
1427
+ function normalizeHex$2(hex) {
1428
+ const s = hex.trim().replace(/^0x/i, '');
1429
+ if (!/^[0-9a-fA-F]*$/.test(s)) {
1430
+ throw new Error('stealth-address: hex must contain only 0-9, a-f');
1431
+ }
1432
+ return s.length % 2 === 0 ? s : `0${s}`;
1433
+ }
1434
+ function hexToBytes$1(hex) {
1435
+ const norm = normalizeHex$2(hex);
1436
+ const out = new Uint8Array(norm.length / 2);
1437
+ for (let i = 0; i < out.length; i++) {
1438
+ out[i] = parseInt(norm.slice(i * 2, i * 2 + 2), 16);
1439
+ }
1440
+ return out;
1441
+ }
1442
+ function bytesToHex$1(bytes) {
1443
+ let s = '';
1444
+ for (let i = 0; i < bytes.length; i++) {
1445
+ s += bytes[i].toString(16).padStart(2, '0');
1446
+ }
1447
+ return s;
1448
+ }
1449
+ function concatBytes$1(a, b) {
1450
+ const out = new Uint8Array(a.length + b.length);
1451
+ out.set(a, 0);
1452
+ out.set(b, a.length);
1453
+ return out;
1454
+ }
1455
+ /**
1456
+ * Encodes `x || y` as Bech32 (BIP-173) with human-readable part {@link STEALTH_ADDRESS_HRP} (`stpl1`).
1457
+ * `x` and `y` must have the same byte length so decoding can split the payload in half.
1458
+ */
1459
+ function encodeStealthAddress(decoded) {
1460
+ const xb = hexToBytes$1(decoded.x);
1461
+ const yb = hexToBytes$1(decoded.y);
1462
+ if (xb.length !== yb.length) {
1463
+ throw new Error('stealth-address: x and y must encode the same number of bytes for a reversible address');
1464
+ }
1465
+ const payload = concatBytes$1(xb, yb);
1466
+ const words = bech32.toWords(payload);
1467
+ return bech32.encode(STEALTH_ADDRESS_HRP, words, BECH32_STEALTH_LIMIT);
1468
+ }
1469
+ /**
1470
+ * Decodes a `stpl1` Bech32 stealth address into `x` and `y` (each half of the payload, as lowercase hex).
1471
+ */
1472
+ function decodeStealthAddress(address) {
1473
+ const { prefix, words } = bech32.decode(address, BECH32_STEALTH_LIMIT);
1474
+ if (prefix !== STEALTH_ADDRESS_HRP) {
1475
+ throw new Error(`stealth-address: expected HRP ${STEALTH_ADDRESS_HRP}, got ${JSON.stringify(prefix)}`);
1476
+ }
1477
+ const bytes = new Uint8Array(bech32.fromWords(words));
1478
+ if (bytes.length === 0 || bytes.length % 2 !== 0) {
1479
+ throw new Error('stealth-address: payload length must be positive and even');
1480
+ }
1481
+ const mid = bytes.length / 2;
1482
+ return {
1483
+ x: bytesToHex$1(bytes.subarray(0, mid)),
1484
+ y: bytesToHex$1(bytes.subarray(mid)),
1485
+ };
1486
+ }
1487
+
1488
+ /** Default nonce when deriving the wallet sign-in message. */
1489
+ const DEFAULT_STEALTH_SIGN_NONCE = 'main address';
1490
+ /** Domain tag mixed into the spend-scalar digest (H6). */
1491
+ const SPEND_SCALAR_DOMAIN_TAG = 'privacy-pool-spend-scalar-v1';
1492
+ /** Schema version bound into the spend-scalar message and digest. */
1493
+ const OWNER_BOUND_NOTE_SCHEMA_VERSION = 1;
1494
+ function resolveSpendScalarSchemaVersion(domain) {
1495
+ return domain.schemaVersion ?? OWNER_BOUND_NOTE_SCHEMA_VERSION;
1496
+ }
1497
+ /**
1498
+ * Plaintext for Stellar wallet message signing (spend-key derivation).
1499
+ * Sign the exact bytes of this string (UTF-8) with the stellar account key.
1500
+ *
1501
+ * The derived scalar is the owner-bound spend key for notes in this environment.
1502
+ */
1503
+ function buildStealthAddressSignMessage(address, domain, nonce = DEFAULT_STEALTH_SIGN_NONCE) {
1504
+ const schemaVersion = resolveSpendScalarSchemaVersion(domain);
1505
+ return [
1506
+ 'Arcane privacy layer: derive your private-note spend key.',
1507
+ '',
1508
+ `Wallet: ${address}`,
1509
+ `Network: ${domain.networkPassphrase}`,
1510
+ `Pool: ${domain.poolContract}`,
1511
+ `Registry: ${domain.registryContract}`,
1512
+ `Schema: owner-bound-note-v${schemaVersion}`,
1513
+ `Nonce: ${nonce}`,
1514
+ '',
1515
+ 'This signature derives the key that authorizes spending your private notes in this environment.',
1516
+ ].join('\n');
1517
+ }
1518
+
1519
+ const DOM_PADDING = 1347436868n;
1520
+ const DOM_NULLIFIER = 1346917708n;
1521
+ const DOM_ESCROW = 1346720579n;
1522
+ const DOM_ENC = 1346719299n;
1523
+ const DOM_AUDIT_TAG = 1346458695n;
1524
+ const DOM_OUTPUT_NOTE_TAG = 1347310663n;
1525
+ const BABYJUB_SUBGROUP_ORDER = 2736030358979909402780800718157159386076813972158567259200215660948447373041n;
1526
+ /**
1527
+ * Map any integer into `(0, l)` so it satisfies circom `LessThan(252)` vs
1528
+ * `BABYJUB_SUBGROUP_ORDER` and `BabyPbk`. Values already in range are unchanged.
1529
+ */
1530
+ function canonicalBabyJubScalarFromInteger(value) {
1531
+ if (value > 0n && value < BABYJUB_SUBGROUP_ORDER) {
1532
+ return value;
1533
+ }
1534
+ return (value % (BABYJUB_SUBGROUP_ORDER - 1n)) + 1n;
1535
+ }
1536
+
1537
+ function hexToBytes(hex) {
1538
+ const out = new Uint8Array(hex.length / 2);
1539
+ for (let i = 0; i < out.length; i++) {
1540
+ out[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
1541
+ }
1542
+ return out;
1543
+ }
1544
+ /** Base64 → bytes via `atob` (browsers; Node 16+). No Node `Buffer`. */
1545
+ function decodeBase64ToBytes(s) {
1546
+ const t = s.replace(/\s/g, '');
1547
+ if (typeof atob !== 'function') {
1548
+ throw new Error('Base64 decoding requires atob (browser or Node 16+)');
1549
+ }
1550
+ try {
1551
+ const binary = atob(t);
1552
+ const out = new Uint8Array(binary.length);
1553
+ for (let i = 0; i < binary.length; i++) {
1554
+ out[i] = binary.charCodeAt(i);
1555
+ }
1556
+ return out;
1557
+ }
1558
+ catch {
1559
+ throw new Error('Invalid base64 signature');
1560
+ }
1561
+ }
1562
+ /**
1563
+ * Ed25519 signature as **128 hex chars** (optional `0x`) or **base64** (typically 88 chars for 64 bytes, whitespace ignored).
1564
+ */
1565
+ function parseStellarEd25519SignatureRaw(input) {
1566
+ const trimmed = input.trim();
1567
+ const no0x = trimmed.replace(/^0x/i, '');
1568
+ if (/^[0-9a-fA-F]+$/.test(no0x) && no0x.length === 128) {
1569
+ return hexToBytes(no0x.toLowerCase());
1570
+ }
1571
+ const fromB64 = decodeBase64ToBytes(trimmed);
1572
+ if (fromB64.length !== 64) {
1573
+ throw new Error(`Decoded signature must be 64 bytes (Ed25519); got ${fromB64.length} from base64`);
1574
+ }
1575
+ return fromB64;
1576
+ }
1577
+ /** SHA-256 via Web Crypto only (`crypto.subtle`) — works in browsers and Node 19+ (global `crypto`). */
1578
+ async function sha256$1(data) {
1579
+ const subtle = globalThis.crypto?.subtle;
1580
+ if (!subtle) {
1581
+ throw new Error('SHA-256 requires crypto.subtle (HTTPS or localhost in browsers, or Node.js 19+).');
1582
+ }
1583
+ const copy = new Uint8Array(data.length);
1584
+ copy.set(data);
1585
+ return new Uint8Array(await subtle.digest('SHA-256', copy));
1586
+ }
1587
+ function appendU32BE$1(parts, value) {
1588
+ const buf = new Uint8Array(4);
1589
+ new DataView(buf.buffer).setUint32(0, value >>> 0, false);
1590
+ parts.push(buf);
1591
+ }
1592
+ function appendUtf8Prefixed(parts, text) {
1593
+ const bytes = new TextEncoder().encode(text);
1594
+ appendU32BE$1(parts, bytes.length);
1595
+ parts.push(bytes);
1596
+ }
1597
+ function concatBytes(parts) {
1598
+ const total = parts.reduce((sum, part) => sum + part.length, 0);
1599
+ const out = new Uint8Array(total);
1600
+ let offset = 0;
1601
+ for (const part of parts) {
1602
+ out.set(part, offset);
1603
+ offset += part.length;
1604
+ }
1605
+ return out;
1606
+ }
1607
+ /**
1608
+ * Domain-separated spend-scalar digest: SHA-256(
1609
+ * SPEND_SCALAR_DOMAIN_TAG || network || pool || registry || schemaVersion || signature
1610
+ * ).
1611
+ */
1612
+ async function spendScalarDigestFromStellarSignature(signature, domain) {
1613
+ const raw = parseStellarEd25519SignatureRaw(signature);
1614
+ const parts = [new TextEncoder().encode(SPEND_SCALAR_DOMAIN_TAG)];
1615
+ appendUtf8Prefixed(parts, domain.networkPassphrase);
1616
+ appendUtf8Prefixed(parts, domain.poolContract);
1617
+ appendUtf8Prefixed(parts, domain.registryContract);
1618
+ appendU32BE$1(parts, resolveSpendScalarSchemaVersion(domain));
1619
+ parts.push(raw);
1620
+ return sha256$1(concatBytes(parts));
1621
+ }
1622
+ function digestToCanonicalScalar(digest) {
1623
+ let v = 0n;
1624
+ for (let i = 0; i < digest.length; i++) {
1625
+ v = (v << 8n) + BigInt(digest[i]);
1626
+ }
1627
+ return canonicalBabyJubScalarFromInteger(v);
1628
+ }
1629
+ function canonicalScalarHex(scalar) {
1630
+ return scalar.toString(16).padStart(64, '0');
1631
+ }
1632
+ async function spendScalarHexFromStellarSignature(signature, domain) {
1633
+ const digest = await spendScalarDigestFromStellarSignature(signature, domain);
1634
+ return canonicalScalarHex(digestToCanonicalScalar(digest));
1635
+ }
1636
+ /**
1637
+ * Stellar Ed25519 signature (hex or base64) → domain-separated SHA-256 → scalar → WASM ECDH.
1638
+ */
1639
+ async function stealthAddressFromStellarSignature(ecdhFromScalarHex, encodeStealth, signature, domain) {
1640
+ const digest = await spendScalarDigestFromStellarSignature(signature, domain);
1641
+ const decoded = ecdhFromScalarHex(canonicalScalarHex(digestToCanonicalScalar(digest)));
1642
+ return encodeStealth(decoded);
1643
+ }
1644
+ /**
1645
+ * Domain-separated SHA-256(signature, network, pool, registry, schema) reduced into
1646
+ * `(0, BabyJub subgroup order)` so `privKeyScalar` matches `BabyPbk` and circom `LessThan(l)`.
1647
+ */
1648
+ async function privKeyScalarDecimalFromStellarSignature(signature, domain) {
1649
+ const digest = await spendScalarDigestFromStellarSignature(signature, domain);
1650
+ return digestToCanonicalScalar(digest).toString(10);
1651
+ }
1652
+
1653
+ const TRANSACTION_N_AUDIT_SLOTS = 4;
1654
+ const DEFAULT_APPLICATION_ID = '101';
1655
+ /** BabyJub audit public key (decimal Fr) used in BDD / local demo when env is unset. */
1656
+ const DEMO_AUDIT_PUBLIC_KEY = [
1657
+ '21605515851820432880964235241069234202284600780825340516808373216881770219365',
1658
+ '18856460861531942120859708048677603751294231190189224157283439874962410808705',
1659
+ ];
1660
+ function isActiveWithdraw(slot) {
1661
+ return slot.value !== '0';
1662
+ }
1663
+ function isActiveDeposit(slot) {
1664
+ return slot.value !== '0';
1665
+ }
1666
+ function resolveWithdrawSlot(slot) {
1667
+ if (slot === 'dummy') {
1668
+ return null;
1669
+ }
1670
+ return slot;
1671
+ }
1672
+ function resolveDepositSlot(slot) {
1673
+ if (slot === 'dummy') {
1674
+ return null;
1675
+ }
1676
+ return slot;
1677
+ }
1678
+ function buildUniformAuditParams(applicationId = DEFAULT_APPLICATION_ID, auditPublicKey, _nAuditSlots = TRANSACTION_N_AUDIT_SLOTS) {
1679
+ return {
1680
+ applicationId,
1681
+ noteAuditPublicKey: auditPublicKey,
1682
+ auditEphemeralScalar: randomFrDecimal253(),
1683
+ };
1684
+ }
1685
+ function resolveSlotApplicationIds(audit, withdrawSlots, depositSlots) {
1686
+ return {
1687
+ inputApplicationIds: withdrawSlots.map((slot) => {
1688
+ const resolved = resolveWithdrawSlot(slot);
1689
+ return resolved && isActiveWithdraw(resolved) ? audit.applicationId : '0';
1690
+ }),
1691
+ outputApplicationIds: depositSlots.map((slot) => {
1692
+ const resolved = resolveDepositSlot(slot);
1693
+ return resolved && isActiveDeposit(resolved) ? audit.applicationId : '0';
1694
+ }),
1695
+ };
1696
+ }
1697
+ function withApplicationIdOnDeposit(deposit, applicationId) {
1698
+ return { ...deposit, applicationId };
1699
+ }
1700
+ function withApplicationIdOnWithdraw(withdraw, applicationId) {
1701
+ return { ...withdraw, applicationId };
1702
+ }
1703
+ /**
1704
+ * Prefer an explicit key, then `NOTE_AUDIT_PUBLIC_KEY_X`/`_Y` env (decimal Fr),
1705
+ * then the built-in demo key. Used by CLI/`demo.sh` for per-app audit pubkeys.
1706
+ */
1707
+ function resolveAuditPublicKeyFromEnv(auditPublicKey) {
1708
+ if (auditPublicKey) {
1709
+ return auditPublicKey;
1710
+ }
1711
+ const x = process.env.NOTE_AUDIT_PUBLIC_KEY_X?.trim();
1712
+ const y = process.env.NOTE_AUDIT_PUBLIC_KEY_Y?.trim();
1713
+ if (x && y) {
1714
+ return [x, y];
1715
+ }
1716
+ return DEMO_AUDIT_PUBLIC_KEY;
1717
+ }
1718
+ function resolveTransactionAuditParams(applicationId, auditPublicKey, nAuditSlots = TRANSACTION_N_AUDIT_SLOTS) {
1719
+ return buildUniformAuditParams(applicationId, resolveAuditPublicKeyFromEnv(auditPublicKey), nAuditSlots);
1720
+ }
1721
+
1722
+ /** Matches `Transaction(20, 2, 2, publicNInputs, publicNOutputs, 4, 12, 6)` in `circuits/main.circom`. */
1723
+ const TRANSACTION_TREE_DEPTH = 20;
1724
+ const TRANSACTION_N_INS = 2;
1725
+ const TRANSACTION_N_OUTS = 2;
1726
+ const NOTE_AUDIT_LEN$2 = 12;
1727
+ const NOTE_OUTPUT_LEN$1 = 6;
1728
+ /** Must match `Transaction(..., publicNInputs, publicNOutputs)` and contract `get_public_slot_config`. */
1729
+ const TRANSACTION_PUBLIC_N_INPUTS = 1;
1730
+ const TRANSACTION_PUBLIC_N_OUTPUTS = 1;
1731
+ /** BN254 scalar field modulus (ark `Fr`, circom signals). */
1732
+ const BN254_SCALAR_MOD = 21888242871839275222246405745257275088548364400416034343698204186575808495617n;
1733
+ /**
1734
+ * BabyJub ECDH in `circuits/encryption.circom` uses `Num2Bits(253)`; scalars must be < 2^253
1735
+ * (matches `libs/cryptography` `scalar_mul_253`).
1736
+ */
1737
+ const BN254_BABYJUB_SCALAR_MAX_EXCLUSIVE = 1n << 253n;
1738
+ function padPublicLegs(legs, publicNInputs, publicNOutputs) {
1739
+ const padPairs = (values, expected, label) => {
1740
+ if (values.length > expected) {
1741
+ throw new Error(`withdrawal-transaction-input: expected at most ${expected} ${label}`);
1742
+ }
1743
+ return [
1744
+ ...values,
1745
+ ...Array.from({ length: expected - values.length }, () => ['0', '0']),
1746
+ ];
1747
+ };
1748
+ const padAmounts = (values, expected, label) => {
1749
+ if (values.length > expected) {
1750
+ throw new Error(`withdrawal-transaction-input: expected at most ${expected} ${label}`);
1751
+ }
1752
+ return [...values, ...Array.from({ length: expected - values.length }, () => '0')];
1753
+ };
1754
+ return {
1755
+ publicWithdrawnAssets: padPairs(legs.publicWithdrawnAssets, publicNOutputs, 'public withdrawn assets'),
1756
+ publicDepositedAssets: padPairs(legs.publicDepositedAssets, publicNInputs, 'public deposited assets'),
1757
+ publicDeposits: padAmounts(legs.publicDeposits, publicNInputs, 'public deposits'),
1758
+ publicWithdrawals: padAmounts(legs.publicWithdrawals, publicNOutputs, 'public withdrawals'),
1759
+ };
1760
+ }
1761
+ function normalizeHex$1(hex) {
1762
+ const s = hex.trim().replace(/^0x/i, '');
1763
+ if (!/^[0-9a-fA-F]*$/.test(s)) {
1764
+ throw new Error('withdrawal-transaction-input: invalid hex');
1765
+ }
1766
+ return s.length % 2 === 0 ? s : `0${s}`;
1767
+ }
1768
+ /** 32-byte field coordinate (hex, no 0x) → decimal string mod BN254 scalar field. */
1769
+ function coordHexToDecimal(hex) {
1770
+ const h = normalizeHex$1(hex);
1771
+ if (h.length > 64) {
1772
+ throw new Error('withdrawal-transaction-input: coordinate hex too long');
1773
+ }
1774
+ const v = BigInt(`0x${h}`);
1775
+ return (v % BN254_SCALAR_MOD).toString(10);
1776
+ }
1777
+ /**
1778
+ * 32-byte big-endian scalar hex → decimal for circom `ephemeralKeyScalar` / ECDH `priv`.
1779
+ * Integer must be < 2^253 (not reduced mod r — values ≥ 2^253 are rejected).
1780
+ */
1781
+ function scalarHexToFrDecimal(hex) {
1782
+ const h = normalizeHex$1(hex);
1783
+ if (h.length > 64) {
1784
+ throw new Error('withdrawal-transaction-input: scalar hex too long');
1785
+ }
1786
+ const v = BigInt(`0x${h.padStart(64, '0').slice(-64)}`);
1787
+ if (v >= BN254_BABYJUB_SCALAR_MAX_EXCLUSIVE) {
1788
+ throw new Error('depositor ephemeral scalar must be < 2^253 (BabyJub Num2Bits); resample with random-scalar');
1789
+ }
1790
+ return v.toString(10);
1791
+ }
1792
+ /**
1793
+ * Stellar G-address Ed25519 payload (32 bytes as 64 hex, optional 0x) → two circom public decimals
1794
+ * (`withdrawAddressHi` / `withdrawAddressLo`). No mod-r; each half fits in 128 bits.
1795
+ */
1796
+ function ed25519PubkeyPayloadHexToWithdrawFrDecimals(hex) {
1797
+ const h = normalizeHex$1(hex).padStart(64, '0').slice(-64);
1798
+ const hi = BigInt(`0x${h.slice(0, 32)}`);
1799
+ const lo = BigInt(`0x${h.slice(32, 64)}`);
1800
+ return { hi: hi.toString(10), lo: lo.toString(10) };
1801
+ }
1802
+ /**
1803
+ * Stellar contract id (`C…`) → two circom field decimals for `asset[0]`, `asset[1]` (same 32-byte split as accounts).
1804
+ */
1805
+ function stellarContractAddressToAssetFrDecimals(address) {
1806
+ const raw = StrKey.decodeContract(address);
1807
+ const hex = Buffer.from(raw).toString('hex');
1808
+ const { hi, lo } = ed25519PubkeyPayloadHexToWithdrawFrDecimals(hex);
1809
+ return [hi, lo];
1810
+ }
1811
+ /** Uniform random `Fr` as decimal (32 random bytes, mod r). For Poseidon-only inputs (e.g. nullifiers). */
1812
+ function randomFrDecimal() {
1813
+ const hex = generateRandomScalarHex32();
1814
+ const v = BigInt(`0x${normalizeHex$1(hex)}`);
1815
+ return (v % BN254_SCALAR_MOD).toString(10);
1816
+ }
1817
+ /** Random scalar < 2^253 for BabyJub ECDH / `Num2Bits(253)` (uses {@link generateRandomScalarHex32}). */
1818
+ function randomFrDecimal253() {
1819
+ const hex = generateRandomScalarHex32();
1820
+ return BigInt(`0x${normalizeHex$1(hex)}`).toString(10);
1821
+ }
1822
+ /** Spend-scalar hex in `(0, BabyJub subgroup order)` so dummy withdraws satisfy `LessThan(l)`. */
1823
+ function randomCanonicalBabyJubScalarHex() {
1824
+ const hex = generateRandomScalarHex32();
1825
+ const reduced = canonicalBabyJubScalarFromInteger(BigInt(`0x${normalizeHex$1(hex)}`));
1826
+ return reduced.toString(16).padStart(64, '0');
1827
+ }
1828
+ function zerosTreeSiblings() {
1829
+ return Array(TRANSACTION_TREE_DEPTH).fill('0');
1830
+ }
1831
+ function dummyWithdraw(wasm) {
1832
+ const nullifier = randomFrDecimal();
1833
+ const secretHex = generateRandomScalarHex32();
1834
+ const secret = (BigInt(`0x${normalizeHex$1(secretHex)}`) % BN254_SCALAR_MOD).toString(10);
1835
+ const scalarHex = randomCanonicalBabyJubScalarHex();
1836
+ const privKeyScalar = scalarHexToFrDecimal(scalarHex);
1837
+ const pt = wasm.ecdhEphemeralPublicKeyFromScalarHex(scalarHex);
1838
+ return {
1839
+ value: '0',
1840
+ nullifier,
1841
+ secret,
1842
+ asset: ['0', '0'],
1843
+ applicationId: '0',
1844
+ ownerPub: [coordHexToDecimal(pt.x), coordHexToDecimal(pt.y)],
1845
+ privKeyScalar,
1846
+ paddingRandom: randomFrDecimal(),
1847
+ escrowNonce: '0',
1848
+ recipientStellar: ['0', '0'],
1849
+ stateSiblings: zerosTreeSiblings(),
1850
+ stateIndex: '0',
1851
+ };
1852
+ }
1853
+ function dummyDeposit(wasm) {
1854
+ const nullifier = randomFrDecimal();
1855
+ const ephemeralKeyScalar = randomFrDecimal253();
1856
+ const skHex = generateRandomScalarHex32();
1857
+ const pt = wasm.ecdhEphemeralPublicKeyFromScalarHex(skHex);
1858
+ return {
1859
+ value: '0',
1860
+ nullifier,
1861
+ ephemeralKeyScalar,
1862
+ asset: ['0', '0'],
1863
+ applicationId: '0',
1864
+ recipientPublicKeys: [coordHexToDecimal(pt.x), coordHexToDecimal(pt.y)],
1865
+ escrowNonce: '0',
1866
+ recipientStellar: ['0', '0'],
1867
+ };
1868
+ }
1869
+ function resolveWithdraw(slot, wasm) {
1870
+ return slot === 'dummy' ? dummyWithdraw(wasm) : slot;
1871
+ }
1872
+ function resolveDeposit(slot, wasm) {
1873
+ return slot === 'dummy' ? dummyDeposit(wasm) : slot;
1874
+ }
1875
+ function resolveDepositsForWitness(depositSlots, wasm) {
1876
+ return [
1877
+ resolveDeposit(depositSlots[0], wasm),
1878
+ resolveDeposit(depositSlots[1], wasm),
1879
+ ];
1880
+ }
1881
+ function padWithdrawSlots(slots, nIns) {
1882
+ if (slots.length > nIns) {
1883
+ throw new Error(`withdrawal-transaction-input: expected at most ${nIns} withdraw slots`);
1884
+ }
1885
+ return [...slots, ...Array.from({ length: nIns - slots.length }, () => 'dummy')];
1886
+ }
1887
+ function padDepositSlots(slots, nOuts) {
1888
+ if (slots.length > nOuts) {
1889
+ throw new Error(`withdrawal-transaction-input: expected at most ${nOuts} deposit slots`);
1890
+ }
1891
+ return [...slots, ...Array.from({ length: nOuts - slots.length }, () => 'dummy')];
1892
+ }
1893
+ function buildTransactionWitnessInput(publicParams, publicLegs, withdrawSlots, depositSlots, audit, wasm, dims = {}) {
1894
+ const nIns = dims.nIns ?? TRANSACTION_N_INS;
1895
+ const nOuts = dims.nOuts ?? TRANSACTION_N_OUTS;
1896
+ const publicNInputs = dims.publicNInputs ?? TRANSACTION_PUBLIC_N_INPUTS;
1897
+ const publicNOutputs = dims.publicNOutputs ?? TRANSACTION_PUBLIC_N_OUTPUTS;
1898
+ const paddedWithdraws = padWithdrawSlots(withdrawSlots, nIns);
1899
+ const paddedDeposits = padDepositSlots(depositSlots, nOuts);
1900
+ const paddedLegs = padPublicLegs(publicLegs, publicNInputs, publicNOutputs);
1901
+ const withdraws = paddedWithdraws.map((slot) => resolveWithdraw(slot, wasm));
1902
+ const deposits = paddedDeposits.map((slot) => resolveDeposit(slot, wasm));
1903
+ const appIds = resolveSlotApplicationIds(audit, paddedWithdraws, paddedDeposits);
1904
+ return {
1905
+ stateRoot: publicParams.stateRoot,
1906
+ withdrawAddressHi: publicParams.withdrawAddressHi,
1907
+ withdrawAddressLo: publicParams.withdrawAddressLo,
1908
+ escrowRecipientHi: publicParams.escrowRecipientHi ?? '0',
1909
+ escrowRecipientLo: publicParams.escrowRecipientLo ?? '0',
1910
+ sweepOutputOwnerPubX: publicParams.sweepOutputOwnerPubX ?? '0',
1911
+ sweepOutputOwnerPubY: publicParams.sweepOutputOwnerPubY ?? '0',
1912
+ privKeyScalars: withdraws.map((w) => w.privKeyScalar),
1913
+ ownerPubs: withdraws.map((w) => w.ownerPub),
1914
+ paddingRandoms: withdraws.map((w) => w.paddingRandom),
1915
+ withdrawnValues: withdraws.map((w) => w.value),
1916
+ withdrawnNullifiers: withdraws.map((w) => w.nullifier),
1917
+ withdrawnSecrets: withdraws.map((w) => w.secret),
1918
+ withdrawnAssets: withdraws.map((w) => w.asset),
1919
+ withdrawnEscrowNonces: withdraws.map((w) => w.escrowNonce),
1920
+ inputRecipientStellar: withdraws.map((w) => w.recipientStellar),
1921
+ stateSiblings: withdraws.map((w) => w.stateSiblings),
1922
+ stateIndex: withdraws.map((w) => w.stateIndex),
1923
+ depositedValues: deposits.map((d) => d.value),
1924
+ depositedNullifiers: deposits.map((d) => d.nullifier),
1925
+ depositedAssets: deposits.map((d) => d.asset),
1926
+ depositedEphemeralKeyScalars: deposits.map((d) => d.ephemeralKeyScalar),
1927
+ depositedRecipientPublicKeys: deposits.map((d) => d.recipientPublicKeys),
1928
+ depositedEscrowNonces: deposits.map((d) => d.escrowNonce ?? '0'),
1929
+ outputRecipientStellar: deposits.map((d) => d.recipientStellar ?? ['0', '0']),
1930
+ inputApplicationIds: appIds.inputApplicationIds,
1931
+ outputApplicationIds: appIds.outputApplicationIds,
1932
+ auditEphemeralScalar: audit.auditEphemeralScalar,
1933
+ noteAuditPublicKey: audit.noteAuditPublicKey,
1934
+ publicWithdrawnAssets: paddedLegs.publicWithdrawnAssets,
1935
+ publicDepositedAssets: paddedLegs.publicDepositedAssets,
1936
+ publicDeposits: paddedLegs.publicDeposits,
1937
+ publicWithdrawals: paddedLegs.publicWithdrawals,
1938
+ };
1939
+ }
1940
+ /** `stpl1…` stealth address → `[x, y]` as decimal field strings for `depositedRecipientPublicKeys`. */
1941
+ function recipientPublicKeysDecimalFromStealthAddress(stealthAddress) {
1942
+ const { x, y } = decodeStealthAddress(stealthAddress);
1943
+ return [coordHexToDecimal(x), coordHexToDecimal(y)];
1944
+ }
1945
+ /** First withdraw leg: Merkle witness + owner public key (hex) and matching scalar. */
1946
+ function withdrawObjectFromMerkleWitness(witness, ownerPubHex, applicationId, privKeyScalar) {
1947
+ return {
1948
+ value: witness.value,
1949
+ nullifier: witness.nullifier,
1950
+ secret: witness.secret,
1951
+ asset: witness.withdrawnAsset,
1952
+ applicationId,
1953
+ ownerPub: [coordHexToDecimal(ownerPubHex.x), coordHexToDecimal(ownerPubHex.y)],
1954
+ privKeyScalar,
1955
+ paddingRandom: randomFrDecimal(),
1956
+ escrowNonce: '0',
1957
+ recipientStellar: ['0', '0'],
1958
+ stateSiblings: witness.stateSiblings,
1959
+ stateIndex: witness.stateIndex,
1960
+ };
1961
+ }
1962
+
1963
+ const FR_SIZE$1 = 32;
1964
+ const CIPHERTEXT_BLOB_HEADER_BYTES = 4;
1965
+ const FR_MODULUS$1 = 21888242871839275222246405745257275088548364400416034343698204186575808495617n;
1966
+ function moduleFr$1(value) {
1967
+ const reduced = value % FR_MODULUS$1;
1968
+ return reduced >= 0n ? reduced : reduced + FR_MODULUS$1;
1969
+ }
1970
+ function fieldToBytes(value) {
1971
+ let remaining = moduleFr$1(value);
1972
+ const buf = Buffer.alloc(FR_SIZE$1);
1973
+ for (let index = FR_SIZE$1 - 1; index >= 0; index -= 1) {
1974
+ buf[index] = Number(remaining & 0xffn);
1975
+ remaining >>= 8n;
1976
+ }
1977
+ return buf;
1978
+ }
1979
+ function decimalOrHexToBigint(value) {
1980
+ const trimmed = value.trim();
1981
+ if (/^0x/i.test(trimmed) || /^[0-9a-f]{64}$/i.test(trimmed)) {
1982
+ return BigInt(`0x${trimmed.replace(/^0x/i, '')}`);
1983
+ }
1984
+ return BigInt(trimmed);
1985
+ }
1986
+ function encodeCiphertextBlob(fields) {
1987
+ const prefix = Buffer.alloc(CIPHERTEXT_BLOB_HEADER_BYTES);
1988
+ prefix.writeUInt32BE(fields.length);
1989
+ return Buffer.concat([
1990
+ prefix,
1991
+ ...fields.map((field) => fieldToBytes(decimalOrHexToBigint(field))),
1992
+ ]);
1993
+ }
1994
+ function decodeCiphertextBlob(blob) {
1995
+ if (blob.length < CIPHERTEXT_BLOB_HEADER_BYTES) {
1996
+ throw new Error('ciphertext_bytes too short');
1997
+ }
1998
+ const count = blob.readUInt32BE(0);
1999
+ const need = CIPHERTEXT_BLOB_HEADER_BYTES + count * FR_SIZE$1;
2000
+ if (blob.length < need) {
2001
+ throw new Error('ciphertext_bytes truncated');
2002
+ }
2003
+ const fields = [];
2004
+ let offset = CIPHERTEXT_BLOB_HEADER_BYTES;
2005
+ for (let index = 0; index < count; index += 1) {
2006
+ fields.push(blob.subarray(offset, offset + FR_SIZE$1).toString('hex'));
2007
+ offset += FR_SIZE$1;
2008
+ }
2009
+ return fields;
2010
+ }
2011
+ function encodeTransactionCiphertextBlob(parameters) {
2012
+ const expected = ciphertextFieldCount(parameters.layout);
2013
+ const fields = [];
2014
+ for (const slot of parameters.auditCiphertexts) {
2015
+ fields.push(...slot);
2016
+ }
2017
+ for (const note of parameters.outputNoteCiphertexts) {
2018
+ fields.push(...note);
2019
+ }
2020
+ if (fields.length !== expected) {
2021
+ throw new Error(`ciphertext blob expected ${String(expected)} fields, got ${String(fields.length)}`);
2022
+ }
2023
+ return encodeCiphertextBlob(fields);
2024
+ }
2025
+ function splitCiphertextBlob(parameters) {
2026
+ const fields = decodeCiphertextBlob(parameters.blob);
2027
+ const expected = ciphertextFieldCount(parameters.layout);
2028
+ if (fields.length !== expected) {
2029
+ throw new Error(`ciphertext blob expected ${String(expected)} fields, got ${String(fields.length)}`);
2030
+ }
2031
+ const { nAuditSlots, noteAuditLen, nOuts, noteOutputLen } = parameters.layout;
2032
+ const auditCiphertexts = [];
2033
+ let offset = 0;
2034
+ for (let slot = 0; slot < nAuditSlots; slot += 1) {
2035
+ auditCiphertexts.push(fields.slice(offset, offset + noteAuditLen));
2036
+ offset += noteAuditLen;
2037
+ }
2038
+ const outputNoteCiphertexts = [];
2039
+ for (let note = 0; note < nOuts; note += 1) {
2040
+ outputNoteCiphertexts.push(fields.slice(offset, offset + noteOutputLen));
2041
+ offset += noteOutputLen;
2042
+ }
2043
+ return { auditCiphertexts, outputNoteCiphertexts };
2044
+ }
2045
+
2046
+ const NOTE_OUTPUT_LEN = 6;
2047
+ const NOTE_AUDIT_LEN$1 = 12;
2048
+ const STREAM_DOMAIN = 1n;
2049
+ const FR_SIZE = 32;
2050
+ const FR_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617n;
2051
+ const ONE = 1n;
2052
+ const ZERO = 0n;
2053
+ const BABYJUB_SCALAR_BITS = 253n;
2054
+ const SCALAR_253_MASK = (ONE << BABYJUB_SCALAR_BITS) - ONE;
2055
+ let primitivesPromise;
2056
+ function primitives() {
2057
+ primitivesPromise ?? (primitivesPromise = Promise.all([
2058
+ buildBabyjub(),
2059
+ buildMimc7(),
2060
+ buildPoseidon(),
2061
+ ]).then(([babyJub, mimc7, poseidon]) => ({ babyJub, mimc7, poseidon })));
2062
+ return primitivesPromise;
2063
+ }
2064
+ function normalizeHex(value) {
2065
+ return value.trim().replace(/^0x/i, '').padStart(FR_SIZE * 2, '0');
2066
+ }
2067
+ function bigintFromHex(value) {
2068
+ return BigInt(`0x${normalizeHex(value)}`);
2069
+ }
2070
+ function bigintFromDecimal(value) {
2071
+ const parsed = BigInt(value);
2072
+ return parsed % FR_MODULUS;
2073
+ }
2074
+ function bigintToFrHex(value) {
2075
+ let v = moduleFr(value);
2076
+ const buf = Buffer.alloc(FR_SIZE);
2077
+ for (let index = FR_SIZE - 1; index >= 0; index -= 1) {
2078
+ buf[index] = Number(v & 0xffn);
2079
+ v >>= 8n;
2080
+ }
2081
+ return buf.toString('hex');
2082
+ }
2083
+ function frDecimalToHex(value) {
2084
+ return bigintToFrHex(bigintFromDecimal(value));
2085
+ }
2086
+ function frDecimalFromBigint(value) {
2087
+ const reduced = value >= ZERO ? value % FR_MODULUS : (value % FR_MODULUS) + FR_MODULUS;
2088
+ return reduced.toString(10);
2089
+ }
2090
+ function fieldBigint(field, value) {
2091
+ return BigInt(field.toString(value));
2092
+ }
2093
+ function moduleFr(value) {
2094
+ const reduced = value % FR_MODULUS;
2095
+ return reduced >= ZERO ? reduced : reduced + FR_MODULUS;
2096
+ }
2097
+ function mimcHash(parameters) {
2098
+ return fieldBigint(parameters.mimc7.F, parameters.mimc7.hash(parameters.mimc7.F.e(parameters.message), parameters.mimc7.F.e(parameters.key)));
2099
+ }
2100
+ function poseidonHash(poseidon, inputs) {
2101
+ return fieldBigint(poseidon.F, poseidon(inputs.map((input) => poseidon.F.e(input))));
2102
+ }
2103
+ function deriveEncCipherKey(poseidon, sharedX) {
2104
+ return poseidonHash(poseidon, [DOM_ENC, sharedX]);
2105
+ }
2106
+ function sharedKeyFromDepositor(parameters) {
2107
+ const scalarHex = frDecimalToHex(parameters.ephemeralKeyScalarDecimal);
2108
+ const shared = parameters.ecdhShared(scalarHex, frDecimalToHex(parameters.recipientPublicKey[0]), frDecimalToHex(parameters.recipientPublicKey[1]));
2109
+ return [bigintFromHex(shared.x), bigintFromHex(shared.y)];
2110
+ }
2111
+ function sharedKeyFromRecipient(parameters) {
2112
+ const { babyJub, recipientScalarHex, ephemeralPublicKey } = parameters;
2113
+ const point = [
2114
+ babyJub.F.e(bigintFromHex(ephemeralPublicKey[0])),
2115
+ babyJub.F.e(bigintFromHex(ephemeralPublicKey[1])),
2116
+ ];
2117
+ if (!babyJub.inCurve(point)) {
2118
+ throw new Error('Created ephemeral public key is not on BabyJubJub curve');
2119
+ }
2120
+ const product = babyJub.mulPointEscalar(point, bigintFromHex(recipientScalarHex) & SCALAR_253_MASK);
2121
+ return [
2122
+ fieldBigint(babyJub.F, product[0]),
2123
+ fieldBigint(babyJub.F, product[1]),
2124
+ ];
2125
+ }
2126
+ function poseidonMacTag(parameters) {
2127
+ return poseidonHash(parameters.poseidon, [
2128
+ parameters.domain,
2129
+ parameters.key,
2130
+ parameters.nonce,
2131
+ ...parameters.message,
2132
+ ]);
2133
+ }
2134
+ function outputNoteTag(parameters) {
2135
+ return poseidonMacTag({
2136
+ poseidon: parameters.poseidon,
2137
+ domain: DOM_OUTPUT_NOTE_TAG,
2138
+ key: parameters.key,
2139
+ nonce: parameters.nonce,
2140
+ message: parameters.plaintext,
2141
+ });
2142
+ }
2143
+ function encryptFields(parameters) {
2144
+ return parameters.plaintext.map((field, index) => {
2145
+ const seed = poseidonHash(parameters.poseidon, [
2146
+ parameters.nonce,
2147
+ STREAM_DOMAIN,
2148
+ BigInt(index),
2149
+ ]);
2150
+ const stream = mimcHash({
2151
+ mimc7: parameters.mimc7,
2152
+ message: seed,
2153
+ key: parameters.key,
2154
+ });
2155
+ return moduleFr(field + stream);
2156
+ });
2157
+ }
2158
+ function decryptFields(parameters) {
2159
+ return parameters.ciphertext.map((field, index) => {
2160
+ const seed = poseidonHash(parameters.poseidon, [
2161
+ parameters.nonce,
2162
+ STREAM_DOMAIN,
2163
+ BigInt(index),
2164
+ ]);
2165
+ const stream = mimcHash({
2166
+ mimc7: parameters.mimc7,
2167
+ message: seed,
2168
+ key: parameters.key,
2169
+ });
2170
+ return moduleFr(bigintFromHex(field) - stream);
2171
+ });
2172
+ }
2173
+ function plaintextBigints(plaintext) {
2174
+ return [
2175
+ bigintFromDecimal(plaintext.value),
2176
+ bigintFromDecimal(plaintext.assetHi),
2177
+ bigintFromDecimal(plaintext.assetLo),
2178
+ bigintFromDecimal(plaintext.nullifier),
2179
+ bigintFromDecimal(plaintext.secret),
2180
+ bigintFromDecimal(plaintext.applicationId),
2181
+ ];
2182
+ }
2183
+ function plaintextFromBigints(fields) {
2184
+ return {
2185
+ value: frDecimalFromBigint(fields[0] ?? ZERO),
2186
+ assetHi: frDecimalFromBigint(fields[1] ?? ZERO),
2187
+ assetLo: frDecimalFromBigint(fields[2] ?? ZERO),
2188
+ nullifier: frDecimalFromBigint(fields[3] ?? ZERO),
2189
+ secret: frDecimalFromBigint(fields[4] ?? ZERO),
2190
+ applicationId: frDecimalFromBigint(fields[5] ?? ZERO),
2191
+ };
2192
+ }
2193
+ async function secretFromDepositEphemeralScalarDecimal(ephemeralKeyScalarDecimal) {
2194
+ const { poseidon } = await primitives();
2195
+ const secret = poseidonHash(poseidon, [bigintFromDecimal(ephemeralKeyScalarDecimal)]);
2196
+ return frDecimalFromBigint(secret);
2197
+ }
2198
+ async function encryptOutputNoteForDeposit(parameters) {
2199
+ const { babyJub, mimc7, poseidon } = await primitives();
2200
+ const secret = await secretFromDepositEphemeralScalarDecimal(parameters.deposit.ephemeralKeyScalar);
2201
+ const plaintext = {
2202
+ value: parameters.deposit.value,
2203
+ assetHi: parameters.deposit.asset[0],
2204
+ assetLo: parameters.deposit.asset[1],
2205
+ nullifier: parameters.deposit.nullifier,
2206
+ secret,
2207
+ applicationId: parameters.deposit.applicationId,
2208
+ };
2209
+ const [sharedX, sharedY] = sharedKeyFromDepositor({
2210
+ babyJub,
2211
+ ecdhShared: parameters.ecdhShared,
2212
+ ephemeralKeyScalarDecimal: parameters.deposit.ephemeralKeyScalar,
2213
+ recipientPublicKey: parameters.deposit.recipientPublicKeys,
2214
+ });
2215
+ const key = deriveEncCipherKey(poseidon, sharedX);
2216
+ const nonce = sharedY;
2217
+ const message = plaintextBigints(plaintext);
2218
+ const ciphertext = encryptFields({ mimc7, poseidon, key, nonce, plaintext: message });
2219
+ const tag = outputNoteTag({ poseidon, key, nonce, plaintext: message });
2220
+ return {
2221
+ ciphertext: ciphertext.map((field) => frDecimalFromBigint(field)),
2222
+ tag: frDecimalFromBigint(tag),
2223
+ };
2224
+ }
2225
+ function ownerPubFromRecipientScalar(babyJub, recipientScalarHex) {
2226
+ const product = babyJub.mulPointEscalar(babyJub.Base8, bigintFromHex(recipientScalarHex) & SCALAR_253_MASK);
2227
+ return [
2228
+ fieldBigint(babyJub.F, product[0]),
2229
+ fieldBigint(babyJub.F, product[1]),
2230
+ ];
2231
+ }
2232
+ function commitmentFromPlaintextAndOwnerPub(parameters) {
2233
+ const commitment = poseidonHash(parameters.poseidon, [
2234
+ bigintFromDecimal(parameters.plaintext.value),
2235
+ bigintFromDecimal(parameters.plaintext.secret),
2236
+ bigintFromDecimal(parameters.plaintext.nullifier),
2237
+ parameters.ownerPub[0],
2238
+ parameters.ownerPub[1],
2239
+ parameters.ownerMode,
2240
+ bigintFromDecimal(parameters.plaintext.assetHi),
2241
+ bigintFromDecimal(parameters.plaintext.assetLo),
2242
+ bigintFromDecimal(parameters.plaintext.applicationId),
2243
+ ]);
2244
+ return normalizeHex(commitment.toString(16));
2245
+ }
2246
+ async function decryptOutputNoteEvent(input) {
2247
+ const { babyJub, mimc7, poseidon } = await primitives();
2248
+ const [sharedX, sharedY] = sharedKeyFromRecipient({
2249
+ babyJub,
2250
+ recipientScalarHex: input.recipientScalarHex,
2251
+ ephemeralPublicKey: input.createdEphemeralKey,
2252
+ });
2253
+ const key = deriveEncCipherKey(poseidon, sharedX);
2254
+ const nonce = sharedY;
2255
+ const decrypted = decryptFields({
2256
+ mimc7,
2257
+ poseidon,
2258
+ key,
2259
+ nonce,
2260
+ ciphertext: input.ciphertext,
2261
+ });
2262
+ const expectedTag = outputNoteTag({
2263
+ poseidon,
2264
+ key,
2265
+ nonce,
2266
+ plaintext: decrypted,
2267
+ });
2268
+ if (expectedTag !== bigintFromHex(input.tag)) {
2269
+ throw new Error('Output note tag verification failed');
2270
+ }
2271
+ const plaintext = plaintextFromBigints(decrypted);
2272
+ const commitmentHex = commitmentFromPlaintextAndOwnerPub({
2273
+ poseidon,
2274
+ plaintext,
2275
+ ownerPub: ownerPubFromRecipientScalar(babyJub, input.recipientScalarHex),
2276
+ ownerMode: input.ownerMode ?? 0n,
2277
+ });
2278
+ const commitmentMatches = normalizeHex(input.commitmentHashHex) === commitmentHex;
2279
+ if (!commitmentMatches) {
2280
+ throw new Error('Output note commitment checksum mismatch');
2281
+ }
2282
+ return {
2283
+ ...plaintext,
2284
+ commitmentHex,
2285
+ commitmentMatches,
2286
+ };
2287
+ }
2288
+ function ownerModeFromEscrowNonce(escrowNonce) {
2289
+ return bigintFromDecimal(escrowNonce) === ZERO ? ZERO : ONE;
2290
+ }
2291
+ function emptyFlagFromValue(value) {
2292
+ return bigintFromDecimal(value) === ZERO ? ONE : ZERO;
2293
+ }
2294
+ function precommitmentFromOpening(parameters) {
2295
+ const ownerKeyHash = poseidonHash(parameters.poseidon, [
2296
+ parameters.ownerPub[0],
2297
+ parameters.ownerPub[1],
2298
+ ]);
2299
+ return poseidonHash(parameters.poseidon, [
2300
+ parameters.secret,
2301
+ parameters.ownerMode,
2302
+ ownerKeyHash,
2303
+ ]);
2304
+ }
2305
+ async function encryptNoteAuditSlot(parameters) {
2306
+ if (parameters.plaintext.length !== NOTE_AUDIT_LEN$1) {
2307
+ throw new Error(`encryptNoteAuditSlot: expected ${String(NOTE_AUDIT_LEN$1)} limbs`);
2308
+ }
2309
+ const { babyJub, mimc7, poseidon } = await primitives();
2310
+ const [sharedX, sharedY] = sharedKeyFromDepositor({
2311
+ babyJub,
2312
+ ecdhShared: parameters.ecdhShared,
2313
+ ephemeralKeyScalarDecimal: parameters.auditEphemeralScalar,
2314
+ recipientPublicKey: parameters.auditPublicKey,
2315
+ });
2316
+ const key = deriveEncCipherKey(poseidon, sharedX);
2317
+ const nonce = sharedY;
2318
+ const message = parameters.plaintext.map((field) => bigintFromDecimal(field));
2319
+ const ciphertext = encryptFields({ mimc7, poseidon, key, nonce, plaintext: message });
2320
+ const tag = poseidonMacTag({
2321
+ poseidon,
2322
+ domain: DOM_AUDIT_TAG,
2323
+ key,
2324
+ nonce,
2325
+ message,
2326
+ });
2327
+ return {
2328
+ ciphertext: ciphertext.map((field) => frDecimalFromBigint(field)),
2329
+ tag: frDecimalFromBigint(tag),
2330
+ };
2331
+ }
2332
+ function auditPlaintextForWithdraw(parameters) {
2333
+ const value = parameters.witness.withdrawnValues[parameters.index] ?? '0';
2334
+ const ownerPub = parameters.witness.ownerPubs[parameters.index] ?? ['0', '0'];
2335
+ const escrowNonce = parameters.witness.withdrawnEscrowNonces[parameters.index] ?? '0';
2336
+ const secret = bigintFromDecimal(parameters.witness.withdrawnSecrets[parameters.index] ?? '0');
2337
+ const ownerMode = ownerModeFromEscrowNonce(escrowNonce);
2338
+ const precommitment = precommitmentFromOpening({
2339
+ poseidon: parameters.poseidon,
2340
+ secret,
2341
+ ownerMode,
2342
+ ownerPub: [bigintFromDecimal(ownerPub[0]), bigintFromDecimal(ownerPub[1])],
2343
+ });
2344
+ const asset = parameters.witness.withdrawnAssets[parameters.index] ?? ['0', '0'];
2345
+ const stellar = parameters.witness.inputRecipientStellar[parameters.index] ?? ['0', '0'];
2346
+ return [
2347
+ frDecimalFromBigint(emptyFlagFromValue(value)),
2348
+ value,
2349
+ asset[0],
2350
+ asset[1],
2351
+ frDecimalFromBigint(precommitment),
2352
+ parameters.witness.withdrawnNullifiers[parameters.index] ?? '0',
2353
+ ownerPub[0],
2354
+ ownerPub[1],
2355
+ parameters.witness.inputApplicationIds[parameters.index] ?? '0',
2356
+ stellar[0],
2357
+ stellar[1],
2358
+ escrowNonce,
2359
+ ];
2360
+ }
2361
+ async function auditPlaintextForDeposit(parameters) {
2362
+ const value = parameters.witness.depositedValues[parameters.index] ?? '0';
2363
+ const ownerPub = parameters.witness.depositedRecipientPublicKeys[parameters.index] ?? ['0', '0'];
2364
+ const escrowNonce = parameters.witness.depositedEscrowNonces[parameters.index] ?? '0';
2365
+ const secret = poseidonHash(parameters.poseidon, [
2366
+ bigintFromDecimal(parameters.witness.depositedEphemeralKeyScalars[parameters.index] ?? '0'),
2367
+ ]);
2368
+ const ownerMode = ownerModeFromEscrowNonce(escrowNonce);
2369
+ const precommitment = precommitmentFromOpening({
2370
+ poseidon: parameters.poseidon,
2371
+ secret,
2372
+ ownerMode,
2373
+ ownerPub: [bigintFromDecimal(ownerPub[0]), bigintFromDecimal(ownerPub[1])],
2374
+ });
2375
+ const asset = parameters.witness.depositedAssets[parameters.index] ?? ['0', '0'];
2376
+ const stellar = parameters.witness.outputRecipientStellar[parameters.index] ?? ['0', '0'];
2377
+ return [
2378
+ frDecimalFromBigint(emptyFlagFromValue(value)),
2379
+ value,
2380
+ asset[0],
2381
+ asset[1],
2382
+ frDecimalFromBigint(precommitment),
2383
+ parameters.witness.depositedNullifiers[parameters.index] ?? '0',
2384
+ ownerPub[0],
2385
+ ownerPub[1],
2386
+ parameters.witness.outputApplicationIds[parameters.index] ?? '0',
2387
+ stellar[0],
2388
+ stellar[1],
2389
+ escrowNonce,
2390
+ ];
2391
+ }
2392
+ async function encryptTransactionCiphertextBlob(parameters) {
2393
+ const { poseidon } = await primitives();
2394
+ const nIns = parameters.witness.withdrawnValues.length;
2395
+ const nOuts = parameters.witness.depositedValues.length;
2396
+ const nAuditSlots = parameters.layout.nAuditSlots;
2397
+ const auditCiphertexts = [];
2398
+ for (let slot = 0; slot < nAuditSlots; slot += 1) {
2399
+ const plaintext = slot < nIns
2400
+ ? auditPlaintextForWithdraw({
2401
+ poseidon,
2402
+ witness: parameters.witness,
2403
+ index: slot,
2404
+ })
2405
+ : await auditPlaintextForDeposit({
2406
+ poseidon,
2407
+ witness: parameters.witness,
2408
+ index: slot - nIns,
2409
+ });
2410
+ const encrypted = await encryptNoteAuditSlot({
2411
+ auditPublicKey: parameters.witness.noteAuditPublicKey,
2412
+ auditEphemeralScalar: parameters.witness.auditEphemeralScalar,
2413
+ plaintext,
2414
+ ecdhShared: parameters.ecdhShared,
2415
+ });
2416
+ auditCiphertexts.push(encrypted.ciphertext);
2417
+ }
2418
+ const outputNoteCiphertexts = [];
2419
+ for (let index = 0; index < nOuts; index += 1) {
2420
+ const deposit = {
2421
+ value: parameters.witness.depositedValues[index] ?? '0',
2422
+ nullifier: parameters.witness.depositedNullifiers[index] ?? '0',
2423
+ ephemeralKeyScalar: parameters.witness.depositedEphemeralKeyScalars[index] ?? '0',
2424
+ asset: parameters.witness.depositedAssets[index] ?? ['0', '0'],
2425
+ applicationId: parameters.witness.outputApplicationIds[index] ?? '0',
2426
+ recipientPublicKeys: parameters.witness.depositedRecipientPublicKeys[index] ?? ['0', '0'],
2427
+ };
2428
+ const encrypted = await encryptOutputNoteForDeposit({
2429
+ deposit,
2430
+ ecdhShared: parameters.ecdhShared,
2431
+ });
2432
+ outputNoteCiphertexts.push([...encrypted.ciphertext]);
2433
+ }
2434
+ const blob = encodeTransactionCiphertextBlob({
2435
+ layout: parameters.layout,
2436
+ auditCiphertexts,
2437
+ outputNoteCiphertexts,
2438
+ });
2439
+ return {
2440
+ ciphertextHex: blob.toString('hex'),
2441
+ auditCiphertexts,
2442
+ outputNoteCiphertexts,
2443
+ };
2444
+ }
2445
+
2446
+ /** Stroops amount as a decimal field string. Reject JS `number` so 18-decimal values cannot silently narrow. */
2447
+ function coinValueDecimal(amount) {
2448
+ if (typeof amount === "number") {
2449
+ throw new TypeError("coin value must be bigint or decimal string, not number");
2450
+ }
2451
+ if (typeof amount === "bigint") {
2452
+ if (amount < 0n) {
2453
+ throw new RangeError("amount must be a non-negative integer");
2454
+ }
2455
+ return amount.toString(10);
2456
+ }
2457
+ if (typeof amount !== "string") {
2458
+ throw new TypeError("coin value must be bigint or decimal string, not number");
2459
+ }
2460
+ const trimmed = amount.trim();
2461
+ if (!/^[0-9]+$/.test(trimmed)) {
2462
+ throw new TypeError("coin value decimal string must be a non-negative integer");
2463
+ }
2464
+ return trimmed;
2465
+ }
2466
+ function generatedCoinFromWasm(value) {
2467
+ const raw = value;
2468
+ const precommitementHex = raw.precommitementHex ?? raw.precommitement_hex;
2469
+ if (!precommitementHex) {
2470
+ throw new Error("generated coin missing precommitement hex");
2471
+ }
2472
+ return {
2473
+ coin: raw.coin,
2474
+ commitment_hex: raw.commitment_hex,
2475
+ precommitement_hex: precommitementHex,
2476
+ precommitementHex,
2477
+ };
2478
+ }
2479
+ class PrivacyPoolSDK {
2480
+ constructor(wasm, options, resolved) {
2481
+ this.wasm = wasm;
2482
+ this.options = options;
2483
+ this.zkConfigNonce = resolved.nonce;
2484
+ this.circuitConfig = resolved.config;
2485
+ this.layout = layoutFromCircuitConfig(resolved.config);
2486
+ }
2487
+ getZkConfigNonce() {
2488
+ return this.zkConfigNonce;
2489
+ }
2490
+ getLayout() {
2491
+ return this.layout;
2492
+ }
2493
+ /**
2494
+ * Initialize the SDK by loading WASM modules.
2495
+ *
2496
+ * In Node.js, proving artifacts load from `zkArtifactBaseUrl` or
2497
+ * `ZK_ARTIFACT_BASE_URL`, defaulting to this package's GitHub release.
2498
+ * In browser, pass pre-loaded WASM via options:
2499
+ * ```ts
2500
+ * const sdk = await PrivacyPoolSDK.init({
2501
+ * wasmBinary: await fetch('/pkg/client_sdk_wasm_bg.wasm').then(r => r.arrayBuffer()),
2502
+ * zkArtifactBaseUrl: 'https://github.com/Polynom-Labs/stellar-privacy-layer-contracts/releases/download/v0.8.0',
2503
+ * });
2504
+ * ```
2505
+ */
2506
+ static async init(options) {
2507
+ const opts = options ?? {};
2508
+ const wasm = await loadWasm(opts.wasmBinary);
2509
+ const resolved = resolveZkCircuitConfig(opts.zkCircuits, opts.zkConfigNonce);
2510
+ const sdk = new PrivacyPoolSDK(wasm, opts, resolved);
2511
+ sdk.circuitArtifacts = await resolveCircuitArtifacts(resolved.config, opts.zkArtifactBaseUrl);
2512
+ return sdk;
2513
+ }
2514
+ /**
2515
+ * Uniform 32-byte scalar as lowercase hex (Web Crypto). Same in browser and Node 19+.
2516
+ */
2517
+ static generateRandomScalarHex32() {
2518
+ return generateRandomScalarHex32();
2519
+ }
2520
+ /**
2521
+ * Text to sign with a Stellar wallet for spend-key derivation (UTF-8). No WASM required.
2522
+ * The message binds network, pool, registry, and schema version (H6).
2523
+ */
2524
+ static buildStealthAddressSignMessage(address, domain, nonce = DEFAULT_STEALTH_SIGN_NONCE) {
2525
+ return buildStealthAddressSignMessage(address, domain, nonce);
2526
+ }
2527
+ /**
2528
+ * Generate a new coin with random nullifier, secret, and random owner-pub field elements (dev / self-contained tests).
2529
+ * @param amount Decimal field element as `bigint` or decimal `string` (never JS `number`).
2530
+ * @param assetHiDecimal / assetLoDecimal Decimal Fr strings for Stellar asset contract id (two limbs).
2531
+ */
2532
+ generateCoin(amount, assetHiDecimal, assetLoDecimal, applicationIdDecimal = "0") {
2533
+ return generatedCoinFromWasm(this.wasm.generateCoin(coinValueDecimal(amount), assetHiDecimal, assetLoDecimal, applicationIdDecimal));
2534
+ }
2535
+ /**
2536
+ * Generate a coin with the same commitment shape as on-chain deposit: pass owner public key (hex x, y).
2537
+ * @param amount Decimal field element (`bigint` | `string`).
2538
+ */
2539
+ generateCoinWithOwnerPub(ownerPub, amount, assetHiDecimal, assetLoDecimal, applicationIdDecimal = "0") {
2540
+ return generatedCoinFromWasm(this.wasm.generateCoinWithOwnerPubHex(ownerPub.x, ownerPub.y, coinValueDecimal(amount), assetHiDecimal, assetLoDecimal, applicationIdDecimal));
2541
+ }
2542
+ /**
2543
+ * Coin for a depositor `ephemeralKeyScalar` (32-byte hex): `coin.secret = Poseidon255(1)(scalar)` as in `deposit.circom`.
2544
+ * @param amount Decimal field element (`bigint` | `string`).
2545
+ */
2546
+ generateCoinFromDepositEphemeralScalarHex(scalarHex, amount, assetHiDecimal, assetLoDecimal, applicationIdDecimal = "0") {
2547
+ return generatedCoinFromWasm(this.wasm.generateCoinFromDepositEphemeralScalarHex(scalarHex, coinValueDecimal(amount), assetHiDecimal, assetLoDecimal, applicationIdDecimal));
2548
+ }
2549
+ /**
2550
+ * Aligned deposit coin: `secret = Poseidon₁(scalar)` and owner pub from recipient hex coords.
2551
+ * @param amount Decimal field element (`bigint` | `string`).
2552
+ */
2553
+ generateCoinForDepositWithOwnerPubHex(scalarHex, ownerXHex, ownerYHex, amount, assetHiDecimal, assetLoDecimal, applicationIdDecimal = "0") {
2554
+ return generatedCoinFromWasm(this.wasm.generateCoinForDepositWithOwnerPubHex(scalarHex, ownerXHex, ownerYHex, coinValueDecimal(amount), assetHiDecimal, assetLoDecimal, applicationIdDecimal));
2555
+ }
2556
+ /**
2557
+ * Merkle root, path, and coin fields for the first withdraw leg (Rust LeanIMT + Poseidon).
2558
+ */
2559
+ buildWithdrawMerkleWitness(coin, state) {
2560
+ const coinJson = JSON.stringify(coin);
2561
+ const stateJson = JSON.stringify(state);
2562
+ const resultJson = this.wasm.buildWithdrawMerkleWitness(coinJson, stateJson);
2563
+ return JSON.parse(resultJson);
2564
+ }
2565
+ /**
2566
+ * Full `Transaction(20,2,2)` withdrawal proof: one real withdraw + dummies, using coin/state and depositor ECDH point (hex).
2567
+ *
2568
+ * Optional **partial public withdraw**: spend the full coin commitment `coin.value` (V), send `publicWithdrawStroops` (W) to the
2569
+ * Stellar receiver, and re-deposit the remainder (V−W) as a new private note to `changeRecipientStealthAddress` (same circuit balance).
2570
+ */
2571
+ async proveWithdrawal(coin, state, params) {
2572
+ const witness = this.buildWithdrawMerkleWitness(coin, state);
2573
+ const ownerPubHex = this.ecdhEphemeralPublicKeyFromScalarHex(BigInt(params.privKeyScalar).toString(16).padStart(64, "0"));
2574
+ const w0 = withdrawObjectFromMerkleWitness(witness, ownerPubHex, params.applicationId ?? coin.application_id ?? "0", params.privKeyScalar);
2575
+ const fullV = BigInt(coin.value);
2576
+ let publicWithdrawals;
2577
+ let deposits;
2578
+ if (params.publicWithdrawStroops !== undefined) {
2579
+ const W = params.publicWithdrawStroops;
2580
+ if (params.changeRecipientStealthAddress === undefined) {
2581
+ throw new Error("proveWithdrawal: changeRecipientStealthAddress is required when publicWithdrawStroops is set");
2582
+ }
2583
+ if (W <= 0n || W >= fullV) {
2584
+ throw new Error("proveWithdrawal: publicWithdrawStroops must be strictly between 0 and coin.value");
2585
+ }
2586
+ const change = fullV - W;
2587
+ publicWithdrawals = [W.toString()];
2588
+ const changeDeposit = {
2589
+ value: change.toString(),
2590
+ nullifier: randomFrDecimal(),
2591
+ ephemeralKeyScalar: randomFrDecimal253(),
2592
+ asset: [coin.asset_hi, coin.asset_lo],
2593
+ applicationId: params.applicationId ?? "0",
2594
+ recipientPublicKeys: recipientPublicKeysDecimalFromStealthAddress(params.changeRecipientStealthAddress),
2595
+ };
2596
+ deposits = [changeDeposit];
2597
+ }
2598
+ else {
2599
+ publicWithdrawals = [coin.value];
2600
+ deposits = [];
2601
+ }
2602
+ // On-chain `transact` sends `publicWithdrawals` / `publicWithdrawnAssets` to the withdraw account.
2603
+ const publicLegs = {
2604
+ publicWithdrawnAssets: [[coin.asset_hi, coin.asset_lo]],
2605
+ publicDepositedAssets: [["0", "0"]],
2606
+ publicDeposits: ["0"],
2607
+ publicWithdrawals,
2608
+ };
2609
+ return this.proveTransactionSlots({
2610
+ stateRoot: witness.stateRoot,
2611
+ withdrawAddressHi: params.withdrawAddressHi,
2612
+ withdrawAddressLo: params.withdrawAddressLo,
2613
+ privKeyScalar: params.privKeyScalar,
2614
+ }, publicLegs, [w0], deposits, params.audit ??
2615
+ resolveTransactionAuditParams(params.applicationId ?? coin.application_id ?? DEFAULT_APPLICATION_ID, DEMO_AUDIT_PUBLIC_KEY, this.layout.nAuditSlots));
2616
+ }
2617
+ /**
2618
+ * Convert a snarkjs proof JSON to hex bytes for Soroban.
2619
+ */
2620
+ proofToHex(proof) {
2621
+ return this.wasm.proofToHex(JSON.stringify(proof));
2622
+ }
2623
+ /**
2624
+ * Convert snarkjs public signals to hex bytes for Soroban.
2625
+ */
2626
+ publicToHex(publicSignals) {
2627
+ return this.wasm.publicToHex(JSON.stringify(publicSignals));
2628
+ }
2629
+ /**
2630
+ * BabyJubJub ephemeral point from a 32-byte scalar (hex). For custom {@link WithdrawObject} / tests.
2631
+ */
2632
+ ecdhEphemeralPublicKeyFromScalarHex(scalarHex) {
2633
+ return this.wasm.ecdhEphemeralPublicKeyFromScalarHex(scalarHex);
2634
+ }
2635
+ /** Circuit `ECDH`: scalar (32-byte hex) × recipient BabyJub point → shared key hex coords. */
2636
+ ecdhSharedKey(scalarHex, recipientPubXHex, recipientPubYHex) {
2637
+ return this.wasm.ecdhSharedKey(scalarHex, recipientPubXHex, recipientPubYHex);
2638
+ }
2639
+ /**
2640
+ * `Transaction(20,nIns,nOuts)` proof from high-level legs: maps to witness input (incl. `"dummy"` ECDH via WASM), then Groth16 → Soroban hex.
2641
+ * Slots are padded to the selected ZK config layout (bundled 2×2 or 6×6).
2642
+ */
2643
+ async proveTransaction(publicParams, publicLegs, withdraws, deposits, audit) {
2644
+ return this.proveTransactionSlots(publicParams, publicLegs, withdraws, deposits, audit);
2645
+ }
2646
+ async proveTransactionSlots(publicParams, publicLegs, withdraws, deposits, audit) {
2647
+ const wasmEcdh = {
2648
+ ecdhEphemeralPublicKeyFromScalarHex: (h) => this.wasm.ecdhEphemeralPublicKeyFromScalarHex(h),
2649
+ };
2650
+ const { nIns, nOuts, publicNInputs, publicNOutputs } = this.layout;
2651
+ const witnessInput = buildTransactionWitnessInput(publicParams, publicLegs, withdraws, deposits, audit, wasmEcdh, { nIns, nOuts, publicNInputs, publicNOutputs });
2652
+ const artifacts = this.circuitArtifacts;
2653
+ if (!artifacts) {
2654
+ throw new Error("PrivacyPoolSDK circuit artifacts are not loaded");
2655
+ }
2656
+ const proved = this.wasm.proveGroth16(artifacts.graph, artifacts.provingKey, artifacts.r1cs, JSON.stringify(witnessInput));
2657
+ const encrypted = await encryptTransactionCiphertextBlob({
2658
+ witness: witnessInput,
2659
+ layout: this.layout,
2660
+ ecdhShared: (priv, pubX, pubY) => this.wasm.ecdhSharedKey(priv, pubX, pubY),
2661
+ });
2662
+ return {
2663
+ proof_hex: proved.proof_hex,
2664
+ public_hex: proved.public_hex,
2665
+ ciphertext_hex: encrypted.ciphertextHex,
2666
+ output_note_ephemeral_scalars: witnessInput.depositedEphemeralKeyScalars,
2667
+ };
2668
+ }
2669
+ /**
2670
+ * Calculate owner-bound nullifier hash: Poseidon(DOM_NULLIFIER, nullifier, privKeyScalar)
2671
+ * @param nullifier Nullifier decimal string from coin data
2672
+ * @param privKeyScalar Spend scalar decimal string
2673
+ * @returns Hex string (0x...) of the hash bytes
2674
+ */
2675
+ calculateNullifierHash(nullifier, privKeyScalar) {
2676
+ return this.wasm.calculateNullifierHash(nullifier, privKeyScalar);
2677
+ }
2678
+ /**
2679
+ * Ed25519 signature from signing {@link buildStealthAddressSignMessage}: **128 hex chars** (optional `0x`)
2680
+ * or **base64** (64 raw bytes after decode). Domain-separated SHA-256 → scalar → ECDH → `stpl1` Bech32.
2681
+ */
2682
+ async generateStealthAddressFromStellarSignature(signature, domain) {
2683
+ return stealthAddressFromStellarSignature((h) => this.wasm.ecdhEphemeralPublicKeyFromScalarHex(h), encodeStealthAddress, signature, domain);
2684
+ }
2685
+ encodeDecodedEphemeralKey(decoded) {
2686
+ return encodeDecodedEphemeralKey(decoded);
2687
+ }
2688
+ decodeDecodedEphemeralKey(encoded) {
2689
+ return decodeDecodedEphemeralKey(encoded);
2690
+ }
2691
+ encodeDepositorSharedSecretPreimage(decoded) {
2692
+ return encodeDepositorSharedSecretPreimage(decoded);
2693
+ }
2694
+ decodeDepositorSharedSecretPreimage(encoded) {
2695
+ return decodeDepositorSharedSecretPreimage(encoded);
2696
+ }
2697
+ sharedSecretFromDepositorPreimage(preimage) {
2698
+ return sharedSecretFromDepositorPreimage((a, b, c) => this.wasm.ecdhSharedKey(a, b, c), preimage);
2699
+ }
2700
+ sharedSecretFromRecipientPreimage(preimage) {
2701
+ return sharedSecretFromRecipientPreimage((a, b, c) => this.wasm.ecdhSharedKey(a, b, c), preimage);
2702
+ }
2703
+ }
2704
+
2705
+ /** @deprecated Witness generation is in the main SDK WASM (`proveGroth16`). */
2706
+ async function generateWitness(_input, _circuitWasm, _wasmFileName) {
2707
+ throw new Error('generateWitness is removed. Call PrivacyPoolSDK.proveTransaction (graph witness + Groth16 in sdk.wasm).');
2708
+ }
2709
+
2710
+ /** Pool Merkle tree depth (matches `coin::TREE_DEPTH` / `Transaction` circuit). */
2711
+ const POOL_MERKLE_TREE_DEPTH = 20;
2712
+ /** Default coin value in stroops (1 XLM); matches Rust `coin::COIN_VALUE`. */
2713
+ const COIN_VALUE_STROOPS = 1000000000;
2714
+
2715
+ /**
2716
+ * Checks if something is Uint8Array. Be careful: nodejs Buffer will return true.
2717
+ * @param a - value to test
2718
+ * @returns `true` when the value is a Uint8Array-compatible view.
2719
+ * @example
2720
+ * Check whether a value is a Uint8Array-compatible view.
2721
+ * ```ts
2722
+ * isBytes(new Uint8Array([1, 2, 3]));
2723
+ * ```
2724
+ */
2725
+ function isBytes(a) {
2726
+ // Plain `instanceof Uint8Array` is too strict for some Buffer / proxy / cross-realm cases.
2727
+ // The fallback still requires a real ArrayBuffer view, so plain
2728
+ // JSON-deserialized `{ constructor: ... }` spoofing is rejected, and
2729
+ // `BYTES_PER_ELEMENT === 1` keeps the fallback on byte-oriented views.
2730
+ return (a instanceof Uint8Array ||
2731
+ (ArrayBuffer.isView(a) &&
2732
+ a.constructor.name === 'Uint8Array' &&
2733
+ 'BYTES_PER_ELEMENT' in a &&
2734
+ a.BYTES_PER_ELEMENT === 1));
2735
+ }
2736
+ /**
2737
+ * Asserts something is Uint8Array.
2738
+ * @param value - value to validate
2739
+ * @param length - optional exact length constraint
2740
+ * @param title - label included in thrown errors
2741
+ * @returns The validated byte array.
2742
+ * @throws On wrong argument types. {@link TypeError}
2743
+ * @throws On wrong argument ranges or values. {@link RangeError}
2744
+ * @example
2745
+ * Validate that a value is a byte array.
2746
+ * ```ts
2747
+ * abytes(new Uint8Array([1, 2, 3]));
2748
+ * ```
2749
+ */
2750
+ function abytes(value, length, title = '') {
2751
+ const bytes = isBytes(value);
2752
+ const len = value?.length;
2753
+ const needsLen = length !== undefined;
2754
+ if (!bytes || (needsLen)) {
2755
+ const prefix = title && `"${title}" `;
2756
+ const ofLen = '';
2757
+ const got = bytes ? `length=${len}` : `type=${typeof value}`;
2758
+ const message = prefix + 'expected Uint8Array' + ofLen + ', got ' + got;
2759
+ if (!bytes)
2760
+ throw new TypeError(message);
2761
+ throw new RangeError(message);
2762
+ }
2763
+ return value;
2764
+ }
2765
+ /**
2766
+ * Asserts a hash instance has not been destroyed or finished.
2767
+ * @param instance - hash instance to validate
2768
+ * @param checkFinished - whether to reject finalized instances
2769
+ * @throws If the hash instance has already been destroyed or finalized. {@link Error}
2770
+ * @example
2771
+ * Validate that a hash instance is still usable.
2772
+ * ```ts
2773
+ * import { aexists } from '@noble/hashes/utils.js';
2774
+ * import { sha256 } from '@noble/hashes/sha2.js';
2775
+ * const hash = sha256.create();
2776
+ * aexists(hash);
2777
+ * ```
2778
+ */
2779
+ function aexists(instance, checkFinished = true) {
2780
+ if (instance.destroyed)
2781
+ throw new Error('Hash instance has been destroyed');
2782
+ if (checkFinished && instance.finished)
2783
+ throw new Error('Hash#digest() has already been called');
2784
+ }
2785
+ /**
2786
+ * Asserts output is a sufficiently-sized byte array.
2787
+ * @param out - destination buffer
2788
+ * @param instance - hash instance providing output length
2789
+ * Oversized buffers are allowed; downstream code only promises to fill the first `outputLen` bytes.
2790
+ * @throws On wrong argument types. {@link TypeError}
2791
+ * @throws On wrong argument ranges or values. {@link RangeError}
2792
+ * @example
2793
+ * Validate a caller-provided digest buffer.
2794
+ * ```ts
2795
+ * import { aoutput } from '@noble/hashes/utils.js';
2796
+ * import { sha256 } from '@noble/hashes/sha2.js';
2797
+ * const hash = sha256.create();
2798
+ * aoutput(new Uint8Array(hash.outputLen), hash);
2799
+ * ```
2800
+ */
2801
+ function aoutput(out, instance) {
2802
+ abytes(out, undefined, 'digestInto() output');
2803
+ const min = instance.outputLen;
2804
+ if (out.length < min) {
2805
+ throw new RangeError('"digestInto() output" expected to be of length >=' + min);
2806
+ }
2807
+ }
2808
+ /**
2809
+ * Zeroizes typed arrays in place. Warning: JS provides no guarantees.
2810
+ * @param arrays - arrays to overwrite with zeros
2811
+ * @example
2812
+ * Zeroize sensitive buffers in place.
2813
+ * ```ts
2814
+ * clean(new Uint8Array([1, 2, 3]));
2815
+ * ```
2816
+ */
2817
+ function clean(...arrays) {
2818
+ for (let i = 0; i < arrays.length; i++) {
2819
+ arrays[i].fill(0);
2820
+ }
2821
+ }
2822
+ /**
2823
+ * Creates a DataView for byte-level manipulation.
2824
+ * @param arr - source typed array
2825
+ * @returns DataView over the same buffer region.
2826
+ * @example
2827
+ * Create a DataView over an existing buffer.
2828
+ * ```ts
2829
+ * createView(new Uint8Array(4));
2830
+ * ```
2831
+ */
2832
+ function createView(arr) {
2833
+ return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
2834
+ }
2835
+ /**
2836
+ * Rotate-right operation for uint32 values.
2837
+ * @param word - source word
2838
+ * @param shift - shift amount in bits
2839
+ * @returns Rotated word.
2840
+ * @example
2841
+ * Rotate a 32-bit word to the right.
2842
+ * ```ts
2843
+ * rotr(0x12345678, 8);
2844
+ * ```
2845
+ */
2846
+ function rotr(word, shift) {
2847
+ return (word << (32 - shift)) | (word >>> shift);
2848
+ }
2849
+ // Built-in hex conversion https://caniuse.com/mdn-javascript_builtins_uint8array_fromhex
2850
+ const hasHexBuiltin = /* @__PURE__ */ (() =>
2851
+ // @ts-ignore
2852
+ typeof Uint8Array.from([]).toHex === 'function' && typeof Uint8Array.fromHex === 'function')();
2853
+ // Array where index 0xf0 (240) is mapped to string 'f0'
2854
+ const hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, '0'));
2855
+ /**
2856
+ * Convert byte array to hex string.
2857
+ * Uses the built-in function when available and assumes it matches the tested
2858
+ * fallback semantics.
2859
+ * @param bytes - bytes to encode
2860
+ * @returns Lowercase hexadecimal string.
2861
+ * @throws On wrong argument types. {@link TypeError}
2862
+ * @example
2863
+ * Convert bytes to lowercase hexadecimal.
2864
+ * ```ts
2865
+ * bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])); // 'cafe0123'
2866
+ * ```
2867
+ */
2868
+ function bytesToHex(bytes) {
2869
+ abytes(bytes);
2870
+ // @ts-ignore
2871
+ if (hasHexBuiltin)
2872
+ return bytes.toHex();
2873
+ // pre-caching improves the speed 6x
2874
+ let hex = '';
2875
+ for (let i = 0; i < bytes.length; i++) {
2876
+ hex += hexes[bytes[i]];
2877
+ }
2878
+ return hex;
2879
+ }
2880
+ /**
2881
+ * Creates a callable hash function from a stateful class constructor.
2882
+ * @param hashCons - hash constructor or factory
2883
+ * @param info - optional metadata such as DER OID
2884
+ * @returns Frozen callable hash wrapper with `.create()`.
2885
+ * Wrapper construction eagerly calls `hashCons(undefined)` once to read
2886
+ * `outputLen` / `blockLen`, so constructor side effects happen at module
2887
+ * init time.
2888
+ * @example
2889
+ * Wrap a stateful hash constructor into a callable helper.
2890
+ * ```ts
2891
+ * import { createHasher } from '@noble/hashes/utils.js';
2892
+ * import { sha256 } from '@noble/hashes/sha2.js';
2893
+ * const wrapped = createHasher(sha256.create, { oid: sha256.oid });
2894
+ * wrapped(new Uint8Array([1]));
2895
+ * ```
2896
+ */
2897
+ function createHasher(hashCons, info = {}) {
2898
+ const hashC = (msg, opts) => hashCons(opts)
2899
+ .update(msg)
2900
+ .digest();
2901
+ const tmp = hashCons(undefined);
2902
+ hashC.outputLen = tmp.outputLen;
2903
+ hashC.blockLen = tmp.blockLen;
2904
+ hashC.canXOF = tmp.canXOF;
2905
+ hashC.create = (opts) => hashCons(opts);
2906
+ Object.assign(hashC, info);
2907
+ return Object.freeze(hashC);
2908
+ }
2909
+ /**
2910
+ * Creates OID metadata for NIST hashes with prefix `06 09 60 86 48 01 65 03 04 02`.
2911
+ * @param suffix - final OID byte for the selected hash.
2912
+ * The helper accepts any byte even though only the documented NIST hash
2913
+ * suffixes are meaningful downstream.
2914
+ * @returns Object containing the DER-encoded OID.
2915
+ * @example
2916
+ * Build OID metadata for a NIST hash.
2917
+ * ```ts
2918
+ * oidNist(0x01);
2919
+ * ```
2920
+ */
2921
+ const oidNist = (suffix) => ({
2922
+ // Current NIST hashAlgs suffixes used here fit in one DER subidentifier octet.
2923
+ // Larger suffix values would need base-128 OID encoding and a different length byte.
2924
+ oid: Uint8Array.from([0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, suffix]),
2925
+ });
2926
+
2927
+ /**
2928
+ * Internal Merkle-Damgard hash utils.
2929
+ * @module
2930
+ */
2931
+ /**
2932
+ * Shared 32-bit conditional boolean primitive reused by SHA-256, SHA-1, and MD5 `F`.
2933
+ * Returns bits from `b` when `a` is set, otherwise from `c`.
2934
+ * The XOR form is equivalent to MD5's `F(X,Y,Z) = XY v not(X)Z` because the masked terms never
2935
+ * set the same bit.
2936
+ * @param a - selector word
2937
+ * @param b - word chosen when selector bit is set
2938
+ * @param c - word chosen when selector bit is clear
2939
+ * @returns Mixed 32-bit word.
2940
+ * @example
2941
+ * Combine three words with the shared 32-bit choice primitive.
2942
+ * ```ts
2943
+ * Chi(0xffffffff, 0x12345678, 0x87654321);
2944
+ * ```
2945
+ */
2946
+ function Chi(a, b, c) {
2947
+ return (a & b) ^ (~a & c);
2948
+ }
2949
+ /**
2950
+ * Shared 32-bit majority primitive reused by SHA-256 and SHA-1.
2951
+ * Returns bits shared by at least two inputs.
2952
+ * @param a - first input word
2953
+ * @param b - second input word
2954
+ * @param c - third input word
2955
+ * @returns Mixed 32-bit word.
2956
+ * @example
2957
+ * Combine three words with the shared 32-bit majority primitive.
2958
+ * ```ts
2959
+ * Maj(0xffffffff, 0x12345678, 0x87654321);
2960
+ * ```
2961
+ */
2962
+ function Maj(a, b, c) {
2963
+ return (a & b) ^ (a & c) ^ (b & c);
2964
+ }
2965
+ /**
2966
+ * Merkle-Damgard hash construction base class.
2967
+ * Could be used to create MD5, RIPEMD, SHA1, SHA2.
2968
+ * Accepts only byte-aligned `Uint8Array` input, even when the underlying spec describes bit
2969
+ * strings with partial-byte tails.
2970
+ * @param blockLen - internal block size in bytes
2971
+ * @param outputLen - digest size in bytes
2972
+ * @param padOffset - trailing length field size in bytes
2973
+ * @param isLE - whether length and state words are encoded in little-endian
2974
+ * @example
2975
+ * Use a concrete subclass to get the shared Merkle-Damgard update/digest flow.
2976
+ * ```ts
2977
+ * import { _SHA1 } from '@noble/hashes/legacy.js';
2978
+ * const hash = new _SHA1();
2979
+ * hash.update(new Uint8Array([97, 98, 99]));
2980
+ * hash.digest();
2981
+ * ```
2982
+ */
2983
+ class HashMD {
2984
+ blockLen;
2985
+ outputLen;
2986
+ canXOF = false;
2987
+ padOffset;
2988
+ isLE;
2989
+ // For partial updates less than block size
2990
+ buffer;
2991
+ view;
2992
+ finished = false;
2993
+ length = 0;
2994
+ pos = 0;
2995
+ destroyed = false;
2996
+ constructor(blockLen, outputLen, padOffset, isLE) {
2997
+ this.blockLen = blockLen;
2998
+ this.outputLen = outputLen;
2999
+ this.padOffset = padOffset;
3000
+ this.isLE = isLE;
3001
+ this.buffer = new Uint8Array(blockLen);
3002
+ this.view = createView(this.buffer);
3003
+ }
3004
+ update(data) {
3005
+ aexists(this);
3006
+ abytes(data);
3007
+ const { view, buffer, blockLen } = this;
3008
+ const len = data.length;
3009
+ for (let pos = 0; pos < len;) {
3010
+ const take = Math.min(blockLen - this.pos, len - pos);
3011
+ // Fast path only when there is no buffered partial block: `take === blockLen` implies
3012
+ // `this.pos === 0`, so we can process full blocks directly from the input view.
3013
+ if (take === blockLen) {
3014
+ const dataView = createView(data);
3015
+ for (; blockLen <= len - pos; pos += blockLen)
3016
+ this.process(dataView, pos);
3017
+ continue;
3018
+ }
3019
+ buffer.set(data.subarray(pos, pos + take), this.pos);
3020
+ this.pos += take;
3021
+ pos += take;
3022
+ if (this.pos === blockLen) {
3023
+ this.process(view, 0);
3024
+ this.pos = 0;
3025
+ }
3026
+ }
3027
+ this.length += data.length;
3028
+ this.roundClean();
3029
+ return this;
3030
+ }
3031
+ digestInto(out) {
3032
+ aexists(this);
3033
+ aoutput(out, this);
3034
+ this.finished = true;
3035
+ // Padding
3036
+ // We can avoid allocation of buffer for padding completely if it
3037
+ // was previously not allocated here. But it won't change performance.
3038
+ const { buffer, view, blockLen, isLE } = this;
3039
+ let { pos } = this;
3040
+ // append the bit '1' to the message
3041
+ buffer[pos++] = 0b10000000;
3042
+ clean(this.buffer.subarray(pos));
3043
+ // we have less than padOffset left in buffer, so we cannot put length in
3044
+ // current block, need process it and pad again
3045
+ if (this.padOffset > blockLen - pos) {
3046
+ this.process(view, 0);
3047
+ pos = 0;
3048
+ }
3049
+ // Pad until full block byte with zeros
3050
+ for (let i = pos; i < blockLen; i++)
3051
+ buffer[i] = 0;
3052
+ // `padOffset` reserves the whole length field. For SHA-384/512 the high 64 bits stay zero from
3053
+ // the padding fill above, and JS will overflow before user input can make that half non-zero.
3054
+ // So we only need to write the low 64 bits here.
3055
+ view.setBigUint64(blockLen - 8, BigInt(this.length * 8), isLE);
3056
+ this.process(view, 0);
3057
+ const oview = createView(out);
3058
+ const len = this.outputLen;
3059
+ // NOTE: we do division by 4 later, which must be fused in single op with modulo by JIT
3060
+ if (len % 4)
3061
+ throw new Error('_sha2: outputLen must be aligned to 32bit');
3062
+ const outLen = len / 4;
3063
+ const state = this.get();
3064
+ if (outLen > state.length)
3065
+ throw new Error('_sha2: outputLen bigger than state');
3066
+ for (let i = 0; i < outLen; i++)
3067
+ oview.setUint32(4 * i, state[i], isLE);
3068
+ }
3069
+ digest() {
3070
+ const { buffer, outputLen } = this;
3071
+ this.digestInto(buffer);
3072
+ // Copy before destroy(): subclasses wipe `buffer` during cleanup, but `digest()` must return
3073
+ // fresh bytes to the caller.
3074
+ const res = buffer.slice(0, outputLen);
3075
+ this.destroy();
3076
+ return res;
3077
+ }
3078
+ _cloneInto(to) {
3079
+ to ||= new this.constructor();
3080
+ to.set(...this.get());
3081
+ const { blockLen, buffer, length, finished, destroyed, pos } = this;
3082
+ to.destroyed = destroyed;
3083
+ to.finished = finished;
3084
+ to.length = length;
3085
+ to.pos = pos;
3086
+ // Only partial-block bytes need copying: when `length % blockLen === 0`, `pos === 0` and
3087
+ // later `update()` / `digestInto()` overwrite `to.buffer` from the start before reading it.
3088
+ if (length % blockLen)
3089
+ to.buffer.set(buffer);
3090
+ return to;
3091
+ }
3092
+ clone() {
3093
+ return this._cloneInto();
3094
+ }
3095
+ }
3096
+ /**
3097
+ * Initial SHA-2 state: fractional parts of square roots of first 16 primes 2..53.
3098
+ * Check out `test/misc/sha2-gen-iv.js` for recomputation guide.
3099
+ */
3100
+ /** Initial SHA256 state from RFC 6234 §6.1: the first 32 bits of the fractional parts of the
3101
+ * square roots of the first eight prime numbers. Exported as a shared table; callers must treat
3102
+ * it as read-only because constructors copy words from it by index. */
3103
+ const SHA256_IV = /* @__PURE__ */ Uint32Array.from([
3104
+ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
3105
+ ]);
3106
+
3107
+ /**
3108
+ * SHA2 hash function. A.k.a. sha256, sha384, sha512, sha512_224, sha512_256.
3109
+ * SHA256 is the fastest hash implementable in JS, even faster than Blake3.
3110
+ * Check out {@link https://www.rfc-editor.org/rfc/rfc4634 | RFC 4634} and
3111
+ * {@link https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf | FIPS 180-4}.
3112
+ * @module
3113
+ */
3114
+ /**
3115
+ * SHA-224 / SHA-256 round constants from RFC 6234 §5.1: the first 32 bits
3116
+ * of the cube roots of the first 64 primes (2..311).
3117
+ */
3118
+ // prettier-ignore
3119
+ const SHA256_K = /* @__PURE__ */ Uint32Array.from([
3120
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
3121
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
3122
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
3123
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
3124
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
3125
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
3126
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
3127
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
3128
+ ]);
3129
+ /** Reusable SHA-224 / SHA-256 message schedule buffer `W_t` from RFC 6234 §6.2 step 1. */
3130
+ const SHA256_W = /* @__PURE__ */ new Uint32Array(64);
3131
+ /** Internal SHA-224 / SHA-256 compression engine from RFC 6234 §6.2. */
3132
+ class SHA2_32B extends HashMD {
3133
+ constructor(outputLen) {
3134
+ super(64, outputLen, 8, false);
3135
+ }
3136
+ get() {
3137
+ const { A, B, C, D, E, F, G, H } = this;
3138
+ return [A, B, C, D, E, F, G, H];
3139
+ }
3140
+ // prettier-ignore
3141
+ set(A, B, C, D, E, F, G, H) {
3142
+ this.A = A | 0;
3143
+ this.B = B | 0;
3144
+ this.C = C | 0;
3145
+ this.D = D | 0;
3146
+ this.E = E | 0;
3147
+ this.F = F | 0;
3148
+ this.G = G | 0;
3149
+ this.H = H | 0;
3150
+ }
3151
+ process(view, offset) {
3152
+ // Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array
3153
+ for (let i = 0; i < 16; i++, offset += 4)
3154
+ SHA256_W[i] = view.getUint32(offset, false);
3155
+ for (let i = 16; i < 64; i++) {
3156
+ const W15 = SHA256_W[i - 15];
3157
+ const W2 = SHA256_W[i - 2];
3158
+ const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ (W15 >>> 3);
3159
+ const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ (W2 >>> 10);
3160
+ SHA256_W[i] = (s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16]) | 0;
3161
+ }
3162
+ // Compression function main loop, 64 rounds
3163
+ let { A, B, C, D, E, F, G, H } = this;
3164
+ for (let i = 0; i < 64; i++) {
3165
+ const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);
3166
+ const T1 = (H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i]) | 0;
3167
+ const sigma0 = rotr(A, 2) ^ rotr(A, 13) ^ rotr(A, 22);
3168
+ const T2 = (sigma0 + Maj(A, B, C)) | 0;
3169
+ H = G;
3170
+ G = F;
3171
+ F = E;
3172
+ E = (D + T1) | 0;
3173
+ D = C;
3174
+ C = B;
3175
+ B = A;
3176
+ A = (T1 + T2) | 0;
3177
+ }
3178
+ // Add the compressed chunk to the current hash value
3179
+ A = (A + this.A) | 0;
3180
+ B = (B + this.B) | 0;
3181
+ C = (C + this.C) | 0;
3182
+ D = (D + this.D) | 0;
3183
+ E = (E + this.E) | 0;
3184
+ F = (F + this.F) | 0;
3185
+ G = (G + this.G) | 0;
3186
+ H = (H + this.H) | 0;
3187
+ this.set(A, B, C, D, E, F, G, H);
3188
+ }
3189
+ roundClean() {
3190
+ clean(SHA256_W);
3191
+ }
3192
+ destroy() {
3193
+ // HashMD callers route post-destroy usability through `destroyed`; zeroizing alone still leaves
3194
+ // update()/digest() callable on reused instances.
3195
+ this.destroyed = true;
3196
+ this.set(0, 0, 0, 0, 0, 0, 0, 0);
3197
+ clean(this.buffer);
3198
+ }
3199
+ }
3200
+ /** Internal SHA-256 hash class grounded in RFC 6234 §6.2. */
3201
+ class _SHA256 extends SHA2_32B {
3202
+ // We cannot use array here since array allows indexing by variable
3203
+ // which means optimizer/compiler cannot use registers.
3204
+ A = SHA256_IV[0] | 0;
3205
+ B = SHA256_IV[1] | 0;
3206
+ C = SHA256_IV[2] | 0;
3207
+ D = SHA256_IV[3] | 0;
3208
+ E = SHA256_IV[4] | 0;
3209
+ F = SHA256_IV[5] | 0;
3210
+ G = SHA256_IV[6] | 0;
3211
+ H = SHA256_IV[7] | 0;
3212
+ constructor() {
3213
+ super(32);
3214
+ }
3215
+ }
3216
+ /**
3217
+ * SHA2-256 hash function from RFC 4634. In JS it's the fastest: even faster than Blake3. Some info:
3218
+ *
3219
+ * - Trying 2^128 hashes would get 50% chance of collision, using birthday attack.
3220
+ * - BTC network is doing 2^70 hashes/sec (2^95 hashes/year) as per 2025.
3221
+ * - Each sha256 hash is executing 2^18 bit operations.
3222
+ * - Good 2024 ASICs can do 200Th/sec with 3500 watts of power, corresponding to 2^36 hashes/joule.
3223
+ * @param msg - message bytes to hash
3224
+ * @returns Digest bytes.
3225
+ * @example
3226
+ * Hash a message with SHA2-256.
3227
+ * ```ts
3228
+ * sha256(new Uint8Array([97, 98, 99]));
3229
+ * ```
3230
+ */
3231
+ const sha256 = /* @__PURE__ */ createHasher(() => new _SHA256(),
3232
+ /* @__PURE__ */ oidNist(0x01));
3233
+
3234
+ const KYT_PASSAGE_AUTH_DOMAIN = 'privacy-pool-kyt-passage-v1';
3235
+ const PUBLIC_LEG_CONTEXT_DOMAIN = 'privacy-pool-public-leg-context-v1';
3236
+ const PASSAGE_ID_DOMAIN = 'privacy-pool-passage-id-v3';
3237
+ const PASSAGE_ID_DOMAIN_V2 = 'privacy-pool-passage-id-v2';
3238
+ const PASSAGE_ID_DOMAIN_V1 = 'privacy-pool-passage-id-v1';
3239
+ const NOTE_AUDIT_LEN = 12;
3240
+ const TOTAL_PUBLIC_SIGNALS = 93;
3241
+ const NOTE_AUDIT_PLAINTEXT_LEN = 12;
3242
+ const FIELD_BYTES = 32;
3243
+ const LENGTH_PREFIX_BYTES = 4;
3244
+ function sha256Hex(data) {
3245
+ return bytesToHex(sha256(data));
3246
+ }
3247
+ function publicSignalsBuffer(publicSignalsBytes) {
3248
+ return typeof publicSignalsBytes === 'string'
3249
+ ? Buffer.from(publicSignalsBytes.replace(/^0x/, ''), 'hex')
3250
+ : publicSignalsBytes;
3251
+ }
3252
+ function expectedSignalCountForNonce(zkConfigNonce = 0n) {
3253
+ return totalPublicSignals(layoutForKnownNonce(zkConfigNonce));
3254
+ }
3255
+ function stateRootIndexForNonce(zkConfigNonce = 0n) {
3256
+ return stateRootIndex(layoutForKnownNonce(zkConfigNonce));
3257
+ }
3258
+ function parsePublicSignalsBytes(publicSignalsBytes, zkConfigNonce = 0n) {
3259
+ const expectedCount = expectedSignalCountForNonce(zkConfigNonce);
3260
+ const buf = publicSignalsBuffer(publicSignalsBytes);
3261
+ let offset = 0;
3262
+ let hasLengthPrefix = false;
3263
+ if (buf.length >= LENGTH_PREFIX_BYTES) {
3264
+ const len = buf.readUInt32BE(0);
3265
+ if (buf.length === LENGTH_PREFIX_BYTES + len * FIELD_BYTES) {
3266
+ offset = LENGTH_PREFIX_BYTES;
3267
+ hasLengthPrefix = true;
3268
+ }
3269
+ }
3270
+ const signalBytes = buf.subarray(offset);
3271
+ if (signalBytes.length !== expectedCount * FIELD_BYTES) {
3272
+ throw new Error(`expected ${expectedCount} public signals`);
3273
+ }
3274
+ return {
3275
+ fields: Array.from({ length: expectedCount }, (_, index) => Buffer.from(signalBytes.subarray(index * FIELD_BYTES, (index + 1) * FIELD_BYTES))),
3276
+ hasLengthPrefix,
3277
+ };
3278
+ }
3279
+ function encodePublicSignalsBytes(fields, hasLengthPrefix) {
3280
+ const body = Buffer.concat(fields);
3281
+ if (!hasLengthPrefix) {
3282
+ return body;
3283
+ }
3284
+ const prefix = Buffer.alloc(LENGTH_PREFIX_BYTES);
3285
+ prefix.writeUInt32BE(fields.length);
3286
+ return Buffer.concat([prefix, body]);
3287
+ }
3288
+ function appendBytes(parts, chunk) {
3289
+ parts.push(chunk);
3290
+ }
3291
+ function appendU8(parts, value) {
3292
+ parts.push(Buffer.from([value & 0xff]));
3293
+ }
3294
+ function appendU32BE(parts, value) {
3295
+ const buf = Buffer.alloc(4);
3296
+ buf.writeUInt32BE(value >>> 0);
3297
+ parts.push(buf);
3298
+ }
3299
+ function appendU64BE(parts, value) {
3300
+ const buf = Buffer.alloc(8);
3301
+ buf.writeBigUInt64BE(BigInt(value));
3302
+ parts.push(buf);
3303
+ }
3304
+ function appendU128BE(parts, value) {
3305
+ const buf = Buffer.alloc(16);
3306
+ buf.writeBigUInt64BE(value >> 64n, 0);
3307
+ buf.writeBigUInt64BE(value & ((1n << 64n) - 1n), 8);
3308
+ parts.push(buf);
3309
+ }
3310
+ function appendAddressStrkey(parts, address) {
3311
+ const bytes = Buffer.from(address.trim(), 'utf8');
3312
+ appendU32BE(parts, bytes.length);
3313
+ parts.push(bytes);
3314
+ }
3315
+ /** Canonical zero-address sentinel for absent public-leg slots: `u32_be(0)` with no XDR bytes. */
3316
+ function zeroAddressSentinelBuffer() {
3317
+ return Buffer.alloc(4);
3318
+ }
3319
+ function addressToCanonicalXdr(address) {
3320
+ return Address.fromString(address.trim()).toScVal().toXDR();
3321
+ }
3322
+ function appendAddressXdr(parts, address) {
3323
+ const xdr = addressToCanonicalXdr(address);
3324
+ appendU32BE(parts, xdr.length);
3325
+ parts.push(xdr);
3326
+ }
3327
+ function appendBytes32(parts, hex) {
3328
+ parts.push(Buffer.from(hex.replace(/^0x/, ''), 'hex'));
3329
+ }
3330
+ function frToBuffer32(decimal) {
3331
+ let value = BigInt(decimal);
3332
+ const buf = Buffer.alloc(32);
3333
+ for (let i = 31; i >= 0; i -= 1) {
3334
+ buf[i] = Number(value & 0xffn);
3335
+ value >>= 8n;
3336
+ }
3337
+ return buf;
3338
+ }
3339
+ function isPositiveFr(decimal) {
3340
+ try {
3341
+ return BigInt(decimal) > 0n;
3342
+ }
3343
+ catch {
3344
+ return false;
3345
+ }
3346
+ }
3347
+ function zeroFrBuffer() {
3348
+ return Buffer.alloc(32, 0);
3349
+ }
3350
+ function zeroAddressBuffer() {
3351
+ return zeroAddressSentinelBuffer();
3352
+ }
3353
+ function encodeLegSlot(parts, kind, slot, isPresent, assetHi, assetLo, amount, address) {
3354
+ appendU8(parts, kind);
3355
+ appendU32BE(parts, slot);
3356
+ appendU8(parts, isPresent ? 1 : 0);
3357
+ if (isPresent && address) {
3358
+ parts.push(frToBuffer32(assetHi));
3359
+ parts.push(frToBuffer32(assetLo));
3360
+ appendU128BE(parts, BigInt(amount));
3361
+ appendAddressXdr(parts, address);
3362
+ }
3363
+ else {
3364
+ parts.push(zeroFrBuffer());
3365
+ parts.push(zeroFrBuffer());
3366
+ appendU128BE(parts, 0n);
3367
+ parts.push(zeroAddressBuffer());
3368
+ }
3369
+ }
3370
+ function hashPublicSignalBytes(publicSignalsBytes, zkConfigNonce = 0n) {
3371
+ const parsed = parsePublicSignalsBytes(publicSignalsBytes, zkConfigNonce);
3372
+ parsed.fields[stateRootIndexForNonce(zkConfigNonce)] = Buffer.alloc(FIELD_BYTES);
3373
+ return sha256Hex(encodePublicSignalsBytes(parsed.fields, parsed.hasLengthPrefix));
3374
+ }
3375
+ function hashPublicLegContext(layout, input) {
3376
+ const parts = [];
3377
+ appendBytes(parts, Buffer.from(PUBLIC_LEG_CONTEXT_DOMAIN, 'utf8'));
3378
+ appendU32BE(parts, layout.publicNOutputs);
3379
+ appendU32BE(parts, layout.publicNInputs);
3380
+ for (let i = 0; i < layout.publicNOutputs; i += 1) {
3381
+ const amount = input.publicDeposits[i] ?? '0';
3382
+ const present = isPositiveFr(amount);
3383
+ const asset = input.publicDepositedAssets[i] ?? ['0', '0'];
3384
+ encodeLegSlot(parts, 1, i, present, present ? asset[0] : '0', present ? asset[1] : '0', amount, present ? input.owner : undefined);
3385
+ }
3386
+ for (let j = 0; j < layout.publicNInputs; j += 1) {
3387
+ const amount = input.publicWithdrawals[j] ?? '0';
3388
+ const present = isPositiveFr(amount);
3389
+ const asset = input.publicWithdrawnAssets[j] ?? ['0', '0'];
3390
+ encodeLegSlot(parts, 2, j, present, present ? asset[0] : '0', present ? asset[1] : '0', amount, present ? input.withdrawAddress : undefined);
3391
+ }
3392
+ return sha256Hex(Buffer.concat(parts));
3393
+ }
3394
+ function derivePassageId(owner, nonce, publicSignalHash, publicLegContextHash, ciphertextHash) {
3395
+ const parts = [];
3396
+ appendBytes(parts, Buffer.from(PASSAGE_ID_DOMAIN, 'utf8'));
3397
+ appendAddressStrkey(parts, owner);
3398
+ appendU64BE(parts, nonce);
3399
+ appendBytes32(parts, publicSignalHash);
3400
+ appendBytes32(parts, publicLegContextHash);
3401
+ appendBytes32(parts, ciphertextHash);
3402
+ return sha256Hex(Buffer.concat(parts));
3403
+ }
3404
+ function derivePassageIdV2(owner, nonce, publicSignalHash, publicLegContextHash) {
3405
+ const parts = [];
3406
+ appendBytes(parts, Buffer.from(PASSAGE_ID_DOMAIN_V2, 'utf8'));
3407
+ appendAddressStrkey(parts, owner);
3408
+ appendU64BE(parts, nonce);
3409
+ appendBytes32(parts, publicSignalHash);
3410
+ appendBytes32(parts, publicLegContextHash);
3411
+ return sha256Hex(Buffer.concat(parts));
3412
+ }
3413
+ function derivePassageIdV1(owner, nonce, publicSignalHash, publicLegContextHash, onboardingHash) {
3414
+ const parts = [];
3415
+ appendBytes(parts, Buffer.from(PASSAGE_ID_DOMAIN_V1, 'utf8'));
3416
+ appendAddressStrkey(parts, owner);
3417
+ appendU64BE(parts, nonce);
3418
+ appendBytes32(parts, publicSignalHash);
3419
+ appendBytes32(parts, publicLegContextHash);
3420
+ appendBytes32(parts, onboardingHash);
3421
+ return sha256Hex(Buffer.concat(parts));
3422
+ }
3423
+ function buildKytPassageAuthorization(input) {
3424
+ const parts = [];
3425
+ appendBytes(parts, Buffer.from(KYT_PASSAGE_AUTH_DOMAIN, 'utf8'));
3426
+ appendAddressStrkey(parts, input.poolContract);
3427
+ appendAddressStrkey(parts, input.kytRegistry);
3428
+ appendBytes32(parts, input.passageId);
3429
+ appendU32BE(parts, input.expiresAtLedger);
3430
+ const authorizationHash = sha256Hex(Buffer.concat(parts));
3431
+ return {
3432
+ authorizationHash,
3433
+ poolContract: input.poolContract,
3434
+ kytRegistry: input.kytRegistry,
3435
+ passageId: input.passageId,
3436
+ expiresAtLedger: input.expiresAtLedger,
3437
+ };
3438
+ }
3439
+ function derivePassageFromTransactContext(input) {
3440
+ const layout = input.layout ?? { publicNInputs: 1, publicNOutputs: 1 };
3441
+ const nonce = BigInt(input.nonce ?? 0);
3442
+ const publicSignalHash = hashPublicSignalBytes(input.publicSignalsBytes, nonce);
3443
+ const publicLegContextHash = hashPublicLegContext(layout, input.publicLegContext);
3444
+ const zkLayout = layoutForKnownNonce(nonce);
3445
+ const passageId = ciphertextsInPublicSignals(zkLayout)
3446
+ ? derivePassageIdV2(input.owner, nonce, publicSignalHash, publicLegContextHash)
3447
+ : derivePassageId(input.owner, nonce, publicSignalHash, publicLegContextHash, hashCiphertextBytes(input.ciphertextBytes ?? Buffer.alloc(0)));
3448
+ return {
3449
+ publicSignalHash,
3450
+ publicLegContextHash,
3451
+ passageId,
3452
+ };
3453
+ }
3454
+ function hashCiphertextBytes(ciphertextBytes) {
3455
+ const buffer = typeof ciphertextBytes === 'string'
3456
+ ? Buffer.from(ciphertextBytes.replace(/^0x/i, ''), 'hex')
3457
+ : ciphertextBytes;
3458
+ return sha256Hex(buffer);
3459
+ }
3460
+ function zeroBindingTagsInPublicSignals(publicSignalsBytes, zkConfigNonce = 0n) {
3461
+ const layout = layoutForKnownNonce(zkConfigNonce);
3462
+ if (ciphertextsInPublicSignals(layout)) {
3463
+ return publicSignalsBuffer(publicSignalsBytes);
3464
+ }
3465
+ const parsed = parsePublicSignalsBytes(publicSignalsBytes, zkConfigNonce);
3466
+ const zero = Buffer.alloc(FIELD_BYTES);
3467
+ const auditStart = indexAuditTags(layout);
3468
+ for (let slot = 0; slot < layout.nAuditSlots; slot += 1) {
3469
+ parsed.fields[auditStart + slot] = Buffer.from(zero);
3470
+ }
3471
+ const outputStart = indexOutputNoteTags(layout);
3472
+ for (let note = 0; note < layout.nOuts; note += 1) {
3473
+ parsed.fields[outputStart + note] = Buffer.from(zero);
3474
+ }
3475
+ return encodePublicSignalsBytes(parsed.fields, parsed.hasLengthPrefix);
3476
+ }
3477
+ function spliceBindingTagsIntoPublicSignals(parameters) {
3478
+ const layout = layoutForKnownNonce(parameters.zkConfigNonce);
3479
+ const parsed = parsePublicSignalsBytes(parameters.publicSignalsBytes, parameters.zkConfigNonce);
3480
+ const auditStart = indexAuditTags(layout);
3481
+ for (let slot = 0; slot < layout.nAuditSlots; slot += 1) {
3482
+ const tag = parameters.auditTags[slot];
3483
+ if (tag !== undefined) {
3484
+ parsed.fields[auditStart + slot] = fieldElementBuffer(tag);
3485
+ }
3486
+ }
3487
+ const outputStart = indexOutputNoteTags(layout);
3488
+ for (let note = 0; note < layout.nOuts; note += 1) {
3489
+ const tag = parameters.outputNoteTags[note];
3490
+ if (tag !== undefined) {
3491
+ parsed.fields[outputStart + note] = fieldElementBuffer(tag);
3492
+ }
3493
+ }
3494
+ return encodePublicSignalsBytes(parsed.fields, parsed.hasLengthPrefix);
3495
+ }
3496
+ function fieldElementBuffer(value) {
3497
+ const trimmed = value.trim().replace(/^0x/i, '');
3498
+ const asBigint = /^[0-9]+$/.test(trimmed)
3499
+ ? BigInt(trimmed)
3500
+ : BigInt(`0x${trimmed}`);
3501
+ const buf = Buffer.alloc(FIELD_BYTES);
3502
+ let remaining = asBigint;
3503
+ for (let index = FIELD_BYTES - 1; index >= 0; index -= 1) {
3504
+ buf[index] = Number(remaining & 0xffn);
3505
+ remaining >>= 8n;
3506
+ }
3507
+ return buf;
3508
+ }
3509
+ async function inspectKytPassage(backendUrl, request) {
3510
+ const nonce = BigInt(request.zkConfigNonce ?? 0);
3511
+ const body = {
3512
+ ...request,
3513
+ publicSignalsBytes: zeroBindingTagsInPublicSignals(request.publicSignalsBytes, nonce).toString('hex'),
3514
+ };
3515
+ const response = await fetch(`${backendUrl.replace(/\/$/, '')}/api/kyt/passages/inspect`, {
3516
+ method: 'POST',
3517
+ headers: { 'content-type': 'application/json' },
3518
+ body: JSON.stringify(body),
3519
+ });
3520
+ if (!response.ok) {
3521
+ throw new Error(`KYT inspect failed: ${response.status} ${await response.text()}`);
3522
+ }
3523
+ const payload = await response.json();
3524
+ if (payload.status !== 'approved') {
3525
+ throw new Error(`KYT inspect rejected: ${JSON.stringify(payload)}`);
3526
+ }
3527
+ return payload;
3528
+ }
3529
+ function signatureBase64ToBytes(signature) {
3530
+ const value = signature.trim();
3531
+ if (/^(0x)?[0-9a-fA-F]{128}$/.test(value)) {
3532
+ return Buffer.from(value.replace(/^0x/i, ''), 'hex');
3533
+ }
3534
+ return Buffer.from(value, 'base64');
3535
+ }
3536
+
3537
+ var kytPassage = /*#__PURE__*/Object.freeze({
3538
+ __proto__: null,
3539
+ KYT_PASSAGE_AUTH_DOMAIN: KYT_PASSAGE_AUTH_DOMAIN,
3540
+ NOTE_AUDIT_LEN: NOTE_AUDIT_LEN,
3541
+ NOTE_AUDIT_PLAINTEXT_LEN: NOTE_AUDIT_PLAINTEXT_LEN,
3542
+ PASSAGE_ID_DOMAIN: PASSAGE_ID_DOMAIN,
3543
+ PASSAGE_ID_DOMAIN_V1: PASSAGE_ID_DOMAIN_V1,
3544
+ PASSAGE_ID_DOMAIN_V2: PASSAGE_ID_DOMAIN_V2,
3545
+ PUBLIC_LEG_CONTEXT_DOMAIN: PUBLIC_LEG_CONTEXT_DOMAIN,
3546
+ TOTAL_PUBLIC_SIGNALS: TOTAL_PUBLIC_SIGNALS,
3547
+ addressToCanonicalXdr: addressToCanonicalXdr,
3548
+ buildKytPassageAuthorization: buildKytPassageAuthorization,
3549
+ derivePassageFromTransactContext: derivePassageFromTransactContext,
3550
+ derivePassageId: derivePassageId,
3551
+ derivePassageIdV1: derivePassageIdV1,
3552
+ derivePassageIdV2: derivePassageIdV2,
3553
+ hashCiphertextBytes: hashCiphertextBytes,
3554
+ hashPublicLegContext: hashPublicLegContext,
3555
+ hashPublicSignalBytes: hashPublicSignalBytes,
3556
+ inspectKytPassage: inspectKytPassage,
3557
+ signatureBase64ToBytes: signatureBase64ToBytes,
3558
+ spliceBindingTagsIntoPublicSignals: spliceBindingTagsIntoPublicSignals,
3559
+ zeroAddressSentinelBuffer: zeroAddressSentinelBuffer,
3560
+ zeroBindingTagsInPublicSignals: zeroBindingTagsInPublicSignals
3561
+ });
3562
+
3563
+ function addressToScVal(address) {
3564
+ return nativeToScVal(address, { type: 'address' });
3565
+ }
3566
+ function passageIdHexToScVal(passageIdHex) {
3567
+ const bytes = Buffer.from(passageIdHex.replace(/^0x/, ''), 'hex');
3568
+ return xdr.ScVal.scvBytes(bytes);
3569
+ }
3570
+ function signatureToScVal(signature) {
3571
+ return xdr.ScVal.scvBytes(signature);
3572
+ }
3573
+ function kytAuthorizationOptionToScVal(authorization) {
3574
+ if (authorization === null || authorization === undefined) {
3575
+ return xdr.ScVal.scvVoid();
3576
+ }
3577
+ return nativeToScVal({
3578
+ expiration_ledger: authorization.expirationLedger,
3579
+ signature: authorization.signature,
3580
+ });
3581
+ }
3582
+ function registerPassageOperation(kytRegistryId, passageId, expiresAtLedger, signature) {
3583
+ return Operation.invokeContractFunction({
3584
+ contract: kytRegistryId,
3585
+ function: 'register_passage',
3586
+ args: [
3587
+ passageIdHexToScVal(passageId),
3588
+ xdr.ScVal.scvU32(expiresAtLedger),
3589
+ signatureToScVal(signatureBase64ToBytes(signature)),
3590
+ ],
3591
+ });
3592
+ }
3593
+ function poolTransactOperation(params) {
3594
+ return Operation.invokeContractFunction({
3595
+ contract: params.poolContract,
3596
+ function: 'transact',
3597
+ args: [
3598
+ addressToScVal(params.owner),
3599
+ nativeToScVal(params.nonce, { type: 'u64' }),
3600
+ xdr.ScVal.scvBytes(params.proofBytes),
3601
+ xdr.ScVal.scvBytes(params.publicSignalsBytes),
3602
+ xdr.ScVal.scvBytes(params.ciphertextBytes ?? Buffer.alloc(0)),
3603
+ kytAuthorizationOptionToScVal(params.kytAuthorization),
3604
+ ],
3605
+ });
3606
+ }
3607
+ function helperSubmitWithPassageOperation(helperContractId, params, passageId, expiresAtLedger, signature) {
3608
+ return Operation.invokeContractFunction({
3609
+ contract: helperContractId,
3610
+ function: 'submit_with_passage',
3611
+ args: [
3612
+ addressToScVal(params.owner),
3613
+ nativeToScVal(params.nonce, { type: 'u64' }),
3614
+ xdr.ScVal.scvBytes(params.proofBytes),
3615
+ xdr.ScVal.scvBytes(params.publicSignalsBytes),
3616
+ passageIdHexToScVal(passageId),
3617
+ xdr.ScVal.scvU32(expiresAtLedger),
3618
+ signatureToScVal(signatureBase64ToBytes(signature)),
3619
+ ],
3620
+ });
3621
+ }
3622
+ async function submitTransaction(params) {
3623
+ const server = new rpc.Server(params.rpcUrl);
3624
+ const sourceAccount = await server.getAccount(params.source.publicKey());
3625
+ let builder = new TransactionBuilder(sourceAccount, {
3626
+ fee: params.fee,
3627
+ networkPassphrase: params.networkPassphrase,
3628
+ });
3629
+ for (const operation of params.operations) {
3630
+ builder = builder.addOperation(operation);
3631
+ }
3632
+ const tx = builder.setTimeout(300).build();
3633
+ const prepared = params.allowNonRootAuth
3634
+ ? await prepareTransactionAllowingNonRootAuth(server, params.rpcUrl, tx, params.source, params.networkPassphrase)
3635
+ : await server.prepareTransaction(tx);
3636
+ prepared.sign(params.source);
3637
+ const result = await server.sendTransaction(prepared);
3638
+ const status = String(result.status);
3639
+ if (status !== 'PENDING' && status !== 'SUCCESS') {
3640
+ throw new Error(`transaction submit failed: ${status}`);
3641
+ }
3642
+ await waitForTransaction(server, result.hash);
3643
+ return result.hash;
3644
+ }
3645
+ async function prepareTransactionAllowingNonRootAuth(server, rpcUrl, tx, source, networkPassphrase) {
3646
+ const recording = await simulateTransactionRecordingNonRoot(rpcUrl, tx.toXDR());
3647
+ const validUntilLedgerSeq = recording.latestLedger + 1000;
3648
+ const signedAuth = await Promise.all(recording.auth.map((entry) => {
3649
+ if (entry.credentials().switch()
3650
+ === xdr.SorobanCredentialsType.sorobanCredentialsSourceAccount()) {
3651
+ return entry;
3652
+ }
3653
+ return authorizeEntry(entry, source, validUntilLedgerSeq, networkPassphrase);
3654
+ }));
3655
+ const invokeOp = tx.operations[0];
3656
+ if (tx.operations.length !== 1 || invokeOp.type !== 'invokeHostFunction') {
3657
+ throw new Error('Soroban transactions must contain exactly one invokeHostFunction operation');
3658
+ }
3659
+ const sourceAccount = await server.getAccount(source.publicKey());
3660
+ const signedTx = new TransactionBuilder(sourceAccount, {
3661
+ fee: tx.fee,
3662
+ networkPassphrase,
3663
+ })
3664
+ .addOperation(Operation.invokeHostFunction({
3665
+ func: invokeOp.func,
3666
+ auth: signedAuth,
3667
+ source: invokeOp.source,
3668
+ }))
3669
+ .setTimeout(300)
3670
+ .build();
3671
+ const enforcedSimulation = await server.simulateTransaction(signedTx);
3672
+ if (rpc.Api.isSimulationError(enforcedSimulation)) {
3673
+ throw new Error(`signed authorization simulation failed: ${enforcedSimulation.error}`);
3674
+ }
3675
+ return rpc.assembleTransaction(signedTx, enforcedSimulation).build();
3676
+ }
3677
+ async function simulateTransactionRecordingNonRoot(rpcUrl, transactionXdr) {
3678
+ const response = await fetch(rpcUrl, {
3679
+ method: 'POST',
3680
+ headers: { 'content-type': 'application/json' },
3681
+ body: JSON.stringify({
3682
+ jsonrpc: '2.0',
3683
+ id: 1,
3684
+ method: 'simulateTransaction',
3685
+ params: {
3686
+ transaction: transactionXdr,
3687
+ authMode: 'record_allow_nonroot',
3688
+ },
3689
+ }),
3690
+ });
3691
+ const body = await response.json();
3692
+ if (!response.ok || body.error) {
3693
+ throw new Error(`transaction simulation failed: ${body.error?.message ?? response.statusText}`);
3694
+ }
3695
+ if (!body.result) {
3696
+ throw new Error('transaction simulation failed: missing RPC result');
3697
+ }
3698
+ if (body.result.error) {
3699
+ throw new Error(`transaction simulation failed: ${body.result.error}`);
3700
+ }
3701
+ const latestLedger = Number(body.result.latestLedger);
3702
+ if (!Number.isFinite(latestLedger)) {
3703
+ throw new Error('transaction simulation failed: missing latest ledger');
3704
+ }
3705
+ return {
3706
+ latestLedger,
3707
+ auth: (body.result.results?.[0]?.auth ?? []).map((entry) => xdr.SorobanAuthorizationEntry.fromXDR(entry, 'base64')),
3708
+ };
3709
+ }
3710
+ async function waitForTransaction(server, hash) {
3711
+ for (let attempt = 0; attempt < 60; attempt++) {
3712
+ const result = await server.getTransaction(hash);
3713
+ const status = String(result.status);
3714
+ if (status === 'SUCCESS') {
3715
+ return;
3716
+ }
3717
+ if (status === 'FAILED') {
3718
+ throw new Error(`transaction failed: ${hash}`);
3719
+ }
3720
+ await new Promise((resolve) => setTimeout(resolve, 1000));
3721
+ }
3722
+ throw new Error(`transaction did not confirm in time: ${hash}`);
3723
+ }
3724
+ function planKytSubmit(registerFirst, helperAvailable = false) {
3725
+ if (registerFirst) {
3726
+ if (helperAvailable) {
3727
+ return {
3728
+ atomic: true,
3729
+ operations: ['helper.submit_with_passage'],
3730
+ };
3731
+ }
3732
+ return {
3733
+ atomic: false,
3734
+ operations: ['register_passage', 'pool.transact'],
3735
+ };
3736
+ }
3737
+ return {
3738
+ atomic: true,
3739
+ operations: ['pool.transact'],
3740
+ };
3741
+ }
3742
+ async function registerKytPassage(params) {
3743
+ const derivation = derivePassageFromTransactContext({
3744
+ owner: params.owner,
3745
+ nonce: params.nonce,
3746
+ publicSignalsBytes: params.publicSignalsBytes,
3747
+ ciphertextBytes: params.ciphertextBytes,
3748
+ publicLegContext: params.publicLegContext,
3749
+ });
3750
+ await submitTransaction({
3751
+ source: params.source,
3752
+ networkPassphrase: params.networkPassphrase,
3753
+ rpcUrl: params.rpcUrl,
3754
+ fee: '1000000',
3755
+ operations: [
3756
+ registerPassageOperation(params.kytRegistryId, derivation.passageId, params.expiresAtLedger, params.signature),
3757
+ ],
3758
+ });
3759
+ return derivation.passageId;
3760
+ }
3761
+ async function submitPoolTransact(params) {
3762
+ return submitTransaction({
3763
+ source: params.source,
3764
+ networkPassphrase: params.networkPassphrase,
3765
+ rpcUrl: params.rpcUrl,
3766
+ fee: '10000000',
3767
+ operations: [poolTransactOperation(params)],
3768
+ });
3769
+ }
3770
+ async function submitApprovedKytPassage(params) {
3771
+ if (params.source.publicKey() !== params.owner) {
3772
+ throw new Error('KYT submit source keypair must match pool transact owner');
3773
+ }
3774
+ return submitTransaction({
3775
+ source: params.source,
3776
+ networkPassphrase: params.networkPassphrase,
3777
+ rpcUrl: params.rpcUrl,
3778
+ fee: '12000000',
3779
+ allowNonRootAuth: true,
3780
+ operations: [
3781
+ helperSubmitWithPassageOperation(params.kytSubmitHelperId, params, params.passageId, params.expiresAtLedger, params.signature),
3782
+ ],
3783
+ });
3784
+ }
3785
+ async function submitWithKytPassage(params) {
3786
+ const inspect = params.inspectFn
3787
+ ?? (async (request) => {
3788
+ const { inspectKytPassage } = await Promise.resolve().then(function () { return kytPassage; });
3789
+ const approved = await inspectKytPassage('', request);
3790
+ return approved;
3791
+ });
3792
+ const approved = await inspect(params.inspectRequest);
3793
+ const derivation = derivePassageFromTransactContext({
3794
+ owner: params.owner,
3795
+ nonce: params.nonce,
3796
+ publicSignalsBytes: params.publicSignalsBytes,
3797
+ ciphertextBytes: params.ciphertextBytes,
3798
+ publicLegContext: params.publicLegContext,
3799
+ });
3800
+ if (approved.passageId.replace(/^0x/, '') !== derivation.passageId) {
3801
+ throw new Error('KYT approval passageId does not match local transaction context');
3802
+ }
3803
+ if (params.kytSubmitHelperId) {
3804
+ return submitApprovedKytPassage({
3805
+ source: params.source,
3806
+ networkPassphrase: params.networkPassphrase,
3807
+ rpcUrl: params.rpcUrl,
3808
+ poolContract: params.poolContract,
3809
+ owner: params.owner,
3810
+ nonce: params.nonce,
3811
+ proofBytes: params.proofBytes,
3812
+ publicSignalsBytes: params.publicSignalsBytes,
3813
+ kytSubmitHelperId: params.kytSubmitHelperId,
3814
+ passageId: derivation.passageId,
3815
+ expiresAtLedger: approved.expiresAtLedger,
3816
+ signature: approved.signature,
3817
+ });
3818
+ }
3819
+ await submitTransaction({
3820
+ source: params.source,
3821
+ networkPassphrase: params.networkPassphrase,
3822
+ rpcUrl: params.rpcUrl,
3823
+ fee: '1000000',
3824
+ operations: [
3825
+ registerPassageOperation(params.kytRegistryId, derivation.passageId, approved.expiresAtLedger, approved.signature),
3826
+ ],
3827
+ });
3828
+ return submitPoolTransact(params);
3829
+ }
3830
+ function localSignKytPassageAuthorization(secretSeed, authorization) {
3831
+ const signer = Keypair.fromSecret(secretSeed);
3832
+ const sig = signer.sign(Buffer.from(authorization.authorizationHash, 'hex'));
3833
+ return sig.toString('base64');
3834
+ }
3835
+
3836
+ const SCALAR_HEX_LENGTH = 64;
3837
+ const OUT_OF_RANGE_MESSAGE = 'derived escrow hash is outside BabyJub subgroup; retry nonce';
3838
+ function hexFromCanonicalScalar(value) {
3839
+ return value.toString(16).padStart(SCALAR_HEX_LENGTH, '0');
3840
+ }
3841
+ function assertCanonicalBabyJubScalar(scalar) {
3842
+ if (!(scalar > 0n && scalar < BABYJUB_SUBGROUP_ORDER)) {
3843
+ throw new Error(OUT_OF_RANGE_MESSAGE);
3844
+ }
3845
+ }
3846
+ async function derivedEscrowKey(nonce, recipientHi, recipientLo) {
3847
+ const wasm = await loadWasm();
3848
+ const out = wasm.derivedEscrowKey(nonce.toString(), recipientHi.toString(), recipientLo.toString());
3849
+ const scalar = BigInt(`0x${out.scalarHex}`);
3850
+ assertCanonicalBabyJubScalar(scalar);
3851
+ return {
3852
+ scalarHex: hexFromCanonicalScalar(scalar),
3853
+ pointXHex: out.pointXHex,
3854
+ pointYHex: out.pointYHex,
3855
+ };
3856
+ }
3857
+ async function sampleDerivedEscrowKey(recipientHi, recipientLo, startNonce = 1n, window = 1024n) {
3858
+ for (let offset = 0n; offset < window; offset += 1n) {
3859
+ const nonce = startNonce + offset;
3860
+ try {
3861
+ const key = await derivedEscrowKey(nonce, recipientHi, recipientLo);
3862
+ return { nonce, key };
3863
+ }
3864
+ catch (error) {
3865
+ const message = error instanceof Error ? error.message : String(error);
3866
+ if (!message.includes('outside BabyJub subgroup')) {
3867
+ throw error;
3868
+ }
3869
+ }
3870
+ }
3871
+ throw new Error(OUT_OF_RANGE_MESSAGE);
3872
+ }
3873
+
3874
+ export { BABYJUB_SUBGROUP_ORDER, BINDING_ZK_NONCE, BN254_BABYJUB_SCALAR_MAX_EXCLUSIVE, BN254_SCALAR_MOD, BundledZkCircuit, COIN_VALUE_STROOPS, COMMITMENT_V2_ZK_NONCE, DECODED_EPHEMERAL_HRP, DEFAULT_APPLICATION_ID, DEFAULT_STEALTH_SIGN_NONCE, DEFAULT_ZK_CIRCUITS, DEFAULT_ZK_CONFIG_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, LEGACY_ZK_NONCE, NOTE_AUDIT_LEN$2 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, SIX_BY_SIX_BINDING_ZK_NONCE, SIX_BY_SIX_ZK_NONCE, SPEND_SCALAR_DOMAIN_TAG, STEALTH_ADDRESS_HRP, TOTAL_PUBLIC_SIGNALS, TRANSACTION_N_AUDIT_SLOTS, TRANSACTION_N_INS, TRANSACTION_N_OUTS, TRANSACTION_TREE_DEPTH, ZK_ARTIFACT_GITHUB_REPO, ZK_SDK_PACKAGE_VERSION, addressToCanonicalXdr, auditEphemeralPublicKeyCount, buildKytPassageAuthorization, buildStealthAddressSignMessage, buildTransactionWitnessInput, buildUniformAuditParams, bundledCircuitFileNames, canonicalBabyJubScalarFromInteger, ciphertextFieldCount, ciphertextsInPublicSignals, circuitProfileFromName, circuitProfileFromNonce, coordHexToDecimal, decodeCiphertextBlob, decodeDecodedEphemeralKey, decodeDepositorSharedSecretPreimage, decodeStealthAddress, decryptOutputNoteEvent, defaultZkArtifactBaseUrl, derivePassageFromTransactContext, derivePassageId, derivePassageIdV1, derivePassageIdV2, derivedEscrowKey, ed25519PubkeyPayloadHexToWithdrawFrDecimals, encodeCiphertextBlob, encodeDecodedEphemeralKey, encodeDepositorSharedSecretPreimage, encodeStealthAddress, encodeTransactionCiphertextBlob, encryptNoteAuditSlot, encryptOutputNoteForDeposit, encryptTransactionCiphertextBlob, generateRandomScalarHex32, generateWitness, hashCiphertextBytes, hashPublicLegContext, hashPublicSignalBytes, indexAuditTags, indexOutputNoteTags, inspectKytPassage, layoutForKnownNonce, layoutFromCircuitConfig, localSignKytPassageAuthorization, padDepositSlots, padPublicLegs, padWithdrawSlots, planKytSubmit, poseidonMacTag, privKeyScalarDecimalFromStellarSignature, randomFrDecimal, randomFrDecimal253, recipientPublicKeysDecimalFromStealthAddress, registerKytPassage, resolveAuditPublicKeyFromEnv, resolveDepositsForWitness, resolveSlotApplicationIds, resolveSpendScalarSchemaVersion, resolveTransactionAuditParams, resolveZkCircuitConfig, sampleDerivedEscrowKey, scalarHexToFrDecimal, secretFromDepositEphemeralScalarDecimal, sharedSecretFromDepositorPreimage, sharedSecretFromRecipientPreimage, sixBySixBindingLayout, sixBySixLayout, spendScalarHexFromStellarSignature, spliceBindingTagsIntoPublicSignals, splitCiphertextBlob, standardBindingLayout, standardLayout, stateRootIndex, stellarContractAddressToAssetFrDecimals, submitApprovedKytPassage, submitPoolTransact, submitWithKytPassage, totalPublicSignals, withApplicationIdOnDeposit, withApplicationIdOnWithdraw, withdrawObjectFromMerkleWitness, zeroAddressSentinelBuffer, zeroBindingTagsInPublicSignals };
3875
+ //# sourceMappingURL=index.mjs.map