@veilo/sdk-core 0.3.3 → 0.4.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 (195) hide show
  1. package/README.md +42 -3
  2. package/SHIELD_INTEGRATION.md +143 -0
  3. package/config.d.ts +2 -0
  4. package/config.js +4 -0
  5. package/dist/cjs/client.d.ts +5 -5
  6. package/dist/cjs/client.js +79 -42
  7. package/dist/cjs/compactNote.d.ts +107 -0
  8. package/dist/cjs/compactNote.js +167 -0
  9. package/dist/cjs/events.d.ts +1 -1
  10. package/dist/cjs/events.js +2 -2
  11. package/dist/cjs/idl/privacy_pool.d.ts +5 -0
  12. package/dist/cjs/idl/privacy_pool.js +15218 -0
  13. package/dist/cjs/index.d.ts +16 -13
  14. package/dist/cjs/index.js +40 -30
  15. package/dist/cjs/merkle.d.ts +13 -0
  16. package/dist/cjs/merkle.js +31 -8
  17. package/dist/cjs/program.d.ts +11 -0
  18. package/dist/cjs/program.js +26 -3
  19. package/dist/cjs/proof.d.ts +1 -1
  20. package/dist/cjs/proof.js +37 -37
  21. package/dist/cjs/prover.d.ts +1 -1
  22. package/dist/cjs/prover.js +2 -2
  23. package/dist/cjs/random.d.ts +16 -0
  24. package/dist/cjs/random.js +28 -0
  25. package/dist/cjs/relayer.d.ts +27 -4
  26. package/dist/cjs/relayer.js +16 -5
  27. package/dist/cjs/shield/alt.d.ts +87 -0
  28. package/dist/cjs/shield/alt.js +194 -0
  29. package/dist/cjs/shield/computeBudget.d.ts +61 -0
  30. package/dist/cjs/shield/computeBudget.js +64 -0
  31. package/dist/cjs/shield/errors.d.ts +58 -0
  32. package/dist/cjs/shield/errors.js +121 -0
  33. package/dist/cjs/shield/finalize.d.ts +45 -0
  34. package/dist/cjs/shield/finalize.js +119 -0
  35. package/dist/cjs/shield/index.d.ts +35 -0
  36. package/dist/cjs/shield/index.js +68 -0
  37. package/dist/cjs/shield/ix.d.ts +54 -0
  38. package/dist/cjs/shield/ix.js +119 -0
  39. package/dist/cjs/shield/owner.d.ts +36 -0
  40. package/dist/cjs/shield/owner.js +126 -0
  41. package/dist/cjs/shield/ports.d.ts +43 -0
  42. package/dist/cjs/shield/ports.js +153 -0
  43. package/dist/cjs/shield/preflight.d.ts +30 -0
  44. package/dist/cjs/shield/preflight.js +154 -0
  45. package/dist/cjs/shield/shield.d.ts +68 -0
  46. package/dist/cjs/shield/shield.js +499 -0
  47. package/dist/cjs/shield/types.d.ts +202 -0
  48. package/dist/cjs/shield/types.js +2 -0
  49. package/dist/cjs/utxo.d.ts +20 -0
  50. package/dist/cjs/utxo.js +41 -28
  51. package/dist/esm/client.d.ts +407 -0
  52. package/dist/esm/client.js +9 -5
  53. package/dist/esm/compactNote.d.ts +107 -0
  54. package/dist/esm/compactNote.js +156 -0
  55. package/dist/esm/config.d.ts +82 -0
  56. package/dist/esm/events.d.ts +77 -0
  57. package/dist/esm/events.js +1 -1
  58. package/dist/esm/idl/privacy_pool.d.ts +5 -0
  59. package/dist/esm/idl/privacy_pool.js +15216 -0
  60. package/dist/esm/index.d.ts +16 -0
  61. package/dist/esm/index.js +18 -11
  62. package/dist/esm/merkle.d.ts +77 -0
  63. package/dist/esm/merkle.js +23 -1
  64. package/dist/esm/package.json +1 -0
  65. package/dist/esm/poseidon.d.ts +29 -0
  66. package/dist/esm/program.d.ts +37 -0
  67. package/dist/esm/program.js +23 -1
  68. package/dist/esm/proof.d.ts +183 -0
  69. package/dist/esm/proof.js +2 -2
  70. package/dist/esm/prover.d.ts +54 -0
  71. package/dist/esm/prover.js +1 -1
  72. package/dist/esm/random.d.ts +16 -0
  73. package/dist/esm/random.js +21 -0
  74. package/dist/esm/relayer.d.ts +318 -0
  75. package/dist/esm/relayer.js +16 -5
  76. package/dist/esm/retry.d.ts +32 -0
  77. package/dist/esm/shield/alt.d.ts +87 -0
  78. package/dist/esm/shield/alt.js +186 -0
  79. package/dist/esm/shield/computeBudget.d.ts +61 -0
  80. package/dist/esm/shield/computeBudget.js +61 -0
  81. package/dist/esm/shield/errors.d.ts +58 -0
  82. package/dist/esm/shield/errors.js +115 -0
  83. package/dist/esm/shield/finalize.d.ts +45 -0
  84. package/dist/esm/shield/finalize.js +83 -0
  85. package/dist/esm/shield/index.d.ts +35 -0
  86. package/dist/esm/shield/index.js +32 -0
  87. package/dist/esm/shield/ix.d.ts +54 -0
  88. package/dist/esm/shield/ix.js +82 -0
  89. package/dist/esm/shield/owner.d.ts +36 -0
  90. package/dist/esm/shield/owner.js +122 -0
  91. package/dist/esm/shield/ports.d.ts +43 -0
  92. package/dist/esm/shield/ports.js +147 -0
  93. package/dist/esm/shield/preflight.d.ts +30 -0
  94. package/dist/esm/shield/preflight.js +151 -0
  95. package/dist/esm/shield/shield.d.ts +68 -0
  96. package/dist/esm/shield/shield.js +492 -0
  97. package/dist/esm/shield/types.d.ts +202 -0
  98. package/dist/esm/shield/types.js +1 -0
  99. package/dist/esm/utxo.d.ts +235 -0
  100. package/dist/esm/utxo.js +18 -8
  101. package/dist/src/client.d.ts +407 -0
  102. package/dist/src/client.js +951 -0
  103. package/dist/src/compactNote.d.ts +107 -0
  104. package/dist/src/compactNote.js +167 -0
  105. package/dist/src/config.d.ts +82 -0
  106. package/dist/src/config.js +57 -0
  107. package/dist/src/events.d.ts +77 -0
  108. package/dist/src/events.js +167 -0
  109. package/dist/src/idl/privacy_pool.d.ts +5 -0
  110. package/dist/src/idl/privacy_pool.js +15218 -0
  111. package/dist/src/index.d.ts +16 -0
  112. package/dist/src/index.js +67 -0
  113. package/dist/src/merkle.d.ts +77 -0
  114. package/dist/src/merkle.js +156 -0
  115. package/dist/src/poseidon.d.ts +29 -0
  116. package/dist/src/poseidon.js +100 -0
  117. package/dist/src/program.d.ts +37 -0
  118. package/dist/src/program.js +61 -0
  119. package/dist/src/proof.d.ts +183 -0
  120. package/dist/src/proof.js +292 -0
  121. package/dist/src/prover.d.ts +54 -0
  122. package/dist/src/prover.js +112 -0
  123. package/dist/src/random.d.ts +16 -0
  124. package/dist/src/random.js +28 -0
  125. package/dist/src/relayer.d.ts +318 -0
  126. package/dist/src/relayer.js +257 -0
  127. package/dist/src/retry.d.ts +32 -0
  128. package/dist/src/retry.js +75 -0
  129. package/dist/src/shield/alt.d.ts +87 -0
  130. package/dist/src/shield/alt.js +194 -0
  131. package/dist/src/shield/computeBudget.d.ts +61 -0
  132. package/dist/src/shield/computeBudget.js +64 -0
  133. package/dist/src/shield/errors.d.ts +58 -0
  134. package/dist/src/shield/errors.js +121 -0
  135. package/dist/src/shield/finalize.d.ts +45 -0
  136. package/dist/src/shield/finalize.js +119 -0
  137. package/dist/src/shield/index.d.ts +35 -0
  138. package/dist/src/shield/index.js +68 -0
  139. package/dist/src/shield/ix.d.ts +54 -0
  140. package/dist/src/shield/ix.js +119 -0
  141. package/dist/src/shield/owner.d.ts +36 -0
  142. package/dist/src/shield/owner.js +126 -0
  143. package/dist/src/shield/ports.d.ts +43 -0
  144. package/dist/src/shield/ports.js +153 -0
  145. package/dist/src/shield/preflight.d.ts +30 -0
  146. package/dist/src/shield/preflight.js +154 -0
  147. package/dist/src/shield/shield.d.ts +68 -0
  148. package/dist/src/shield/shield.js +499 -0
  149. package/dist/src/shield/types.d.ts +202 -0
  150. package/dist/src/shield/types.js +2 -0
  151. package/dist/src/utxo.d.ts +235 -0
  152. package/dist/src/utxo.js +407 -0
  153. package/dist/tests/compact-note.test.d.ts +1 -0
  154. package/dist/tests/compact-note.test.js +173 -0
  155. package/dist/tests/config.test.d.ts +1 -0
  156. package/dist/tests/config.test.js +102 -0
  157. package/dist/tests/edge-cases.test.d.ts +1 -0
  158. package/dist/tests/edge-cases.test.js +220 -0
  159. package/dist/tests/encryption.test.d.ts +1 -0
  160. package/dist/tests/encryption.test.js +215 -0
  161. package/dist/tests/events.test.d.ts +1 -0
  162. package/dist/tests/events.test.js +78 -0
  163. package/dist/tests/multi-tree.test.d.ts +1 -0
  164. package/dist/tests/multi-tree.test.js +405 -0
  165. package/dist/tests/pda.test.d.ts +1 -0
  166. package/dist/tests/pda.test.js +229 -0
  167. package/dist/tests/poseidon-builder-parity.test.d.ts +1 -0
  168. package/dist/tests/poseidon-builder-parity.test.js +72 -0
  169. package/dist/tests/poseidon.test.d.ts +1 -0
  170. package/dist/tests/poseidon.test.js +142 -0
  171. package/dist/tests/proof.test.d.ts +1 -0
  172. package/dist/tests/proof.test.js +296 -0
  173. package/dist/tests/relayer.test.d.ts +1 -0
  174. package/dist/tests/relayer.test.js +271 -0
  175. package/dist/tests/sdk.integration.test.d.ts +1 -0
  176. package/dist/tests/sdk.integration.test.js +330 -0
  177. package/dist/tests/shield-owner.test.d.ts +1 -0
  178. package/dist/tests/shield-owner.test.js +89 -0
  179. package/dist/tests/shield-preflight.test.d.ts +1 -0
  180. package/dist/tests/shield-preflight.test.js +87 -0
  181. package/dist/tests/shield-realproof.test.d.ts +1 -0
  182. package/dist/tests/shield-realproof.test.js +272 -0
  183. package/dist/tests/shield.test.d.ts +1 -0
  184. package/dist/tests/shield.test.js +403 -0
  185. package/dist/tests/utxo.test.d.ts +1 -0
  186. package/dist/tests/utxo.test.js +140 -0
  187. package/package.json +69 -11
  188. package/poseidon.d.ts +2 -0
  189. package/poseidon.js +4 -0
  190. package/proof.d.ts +2 -0
  191. package/proof.js +4 -0
  192. package/prover.d.ts +2 -0
  193. package/prover.js +4 -0
  194. package/shield.d.ts +2 -0
  195. package/shield.js +4 -0
package/README.md CHANGED
@@ -410,13 +410,49 @@ const signature: string = await transact({
410
410
  publicAmount: 0n,
411
411
  inputNullifiers: [nullifier1, nullifier2],
412
412
  outputCommitments: [output1.commitment, output2.commitment],
413
- extData: { recipient, relayer: relayerPubkey, fee: 0n, refund: 0n },
413
+ extData: { recipient, relayer: relayerPubkey, fee: 0n, refund: 0n, claimant },
414
414
  proof,
415
415
  });
416
416
  ```
417
417
 
418
418
  ---
419
419
 
420
+ #### Wallet-agnostic shielding
421
+
422
+ `shield()` builds an unsigned v0 deposit transaction for any Solana wallet to
423
+ sign. The signer funds the deposit, while the resulting private note can belong
424
+ to a different Veilo user. The SDK never receives a wallet secret key and never
425
+ broadcasts on the caller's behalf.
426
+
427
+ ```ts
428
+ import {
429
+ createTransactionProver,
430
+ resolveShieldOwner,
431
+ shield,
432
+ } from "@veilo/sdk-core";
433
+
434
+ const owner = await resolveShieldOwner({ username: "alice" });
435
+ const result = await shield({
436
+ connection,
437
+ amount: 5_000_000n,
438
+ mint: USDC_MINT,
439
+ owner,
440
+ signer: { publicKey: wallet.publicKey },
441
+ prover: createTransactionProver({ wasmPath, zkeyPath }),
442
+ });
443
+
444
+ const signed = await wallet.signTransaction(result.transaction);
445
+ const signature = await connection.sendRawTransaction(signed.serialize());
446
+ ```
447
+
448
+ Use `rebuild()` if the blockhash or deadline expires, and call
449
+ `finalizeShield()` after confirmation to obtain the authoritative Merkle leaf
450
+ index. See [SHIELD_INTEGRATION.md](./SHIELD_INTEGRATION.md) for the complete
451
+ build → sign → submit → finalize flow, retry rules, owner-key invariant, and
452
+ fee/rent requirements.
453
+
454
+ ---
455
+
420
456
  ### 4.8 Private Swaps
421
457
 
422
458
  Cross-pool private swaps via Jupiter/Raydium. For native SOL source pools the SDK automatically composes the required `fund_native_source` + `transact_swap` instructions into a single atomic transaction.
@@ -452,7 +488,7 @@ const signature: string = await transactSwap({
452
488
  },
453
489
  swapAmount: 1_000_000_000n,
454
490
  swapData: jupiterInstructionBytes, // Buffer
455
- extData: { recipient, relayer: relayerPubkey, fee, refund: 0n },
491
+ extData: { recipient, relayer: relayerPubkey, fee, refund: 0n, claimant },
456
492
  sourceVaultTokenAccount,
457
493
  sourceMintAccount,
458
494
  destVaultTokenAccount,
@@ -542,7 +578,7 @@ import {
542
578
  const circuitInputs: TransactionCircuitInputs = prepareTransactionInputs({
543
579
  root: tree.root(),
544
580
  publicAmount: 1_000_000_000n,
545
- extData: { recipient, relayer: relayerPubkey, fee: 0n, refund: 0n },
581
+ extData: { recipient, relayer: relayerPubkey, fee: 0n, refund: 0n, claimant },
546
582
  mintAddress: NATIVE_SOL_MINT,
547
583
  inputs: [input1, input2],
548
584
  outputs: [output1, output2],
@@ -563,6 +599,7 @@ const extDataHash = computeExtDataHash({
563
599
  relayer,
564
600
  fee: 0n,
565
601
  refund: 0n,
602
+ claimant,
566
603
  });
567
604
 
568
605
  // Compute swap param/data hashes (for swap circuit inputs)
@@ -1182,6 +1219,7 @@ await transact({
1182
1219
  relayer: relayerPubkey,
1183
1220
  fee: 0n,
1184
1221
  refund: 0n,
1222
+ claimant: claimantPubkey,
1185
1223
  },
1186
1224
  proof,
1187
1225
  });
@@ -1213,6 +1251,7 @@ const circuitInputs: TransactionCircuitInputs = prepareTransactionInputs({
1213
1251
  relayer: relayerPubkey,
1214
1252
  fee: 0n,
1215
1253
  refund: 0n,
1254
+ claimant: claimantPubkey,
1216
1255
  },
1217
1256
  mintAddress: NATIVE_SOL_MINT,
1218
1257
  inputs: [input1, input2],
@@ -0,0 +1,143 @@
1
+ # Wallet-agnostic shielding
2
+
3
+ `shield()` builds an unsigned Solana v0 transaction that moves funds from any
4
+ signing wallet into Veilo's privacy pool. The wallet that pays and the Veilo
5
+ account that owns the resulting private note are independent.
6
+
7
+ This is a build API, like Jupiter's transaction APIs. The SDK proves, encrypts,
8
+ and assembles. Your application asks its wallet to sign, submits the signed
9
+ bytes, confirms them, and handles retry.
10
+
11
+ ## Security model
12
+
13
+ - `signer.publicKey` is the transaction fee payer and public funding source.
14
+ - `owner.veiloPublicKey` controls spending the private note.
15
+ - `owner.noteViewingKey` controls detecting and decrypting the note during a
16
+ chain scan.
17
+ - The SDK never receives a signer secret key.
18
+ - The compact note cipher is embedded in the on-chain instruction, so note
19
+ recovery does not depend on a webhook or a later relayer callback.
20
+
21
+ The two owner keys must belong to the same Veilo account. If they do not, the
22
+ note is spendable but invisible to its owner. Always use `resolveShieldOwner()`;
23
+ construct an owner manually only when you can prove the pairing yourself.
24
+
25
+ ## Complete flow
26
+
27
+ ```ts
28
+ import { Connection, PublicKey } from "@solana/web3.js";
29
+ import {
30
+ createTransactionProver,
31
+ finalizeShield,
32
+ mapShieldError,
33
+ rebuild,
34
+ resolveShieldOwner,
35
+ shield,
36
+ } from "@veilo/sdk-core";
37
+
38
+ const connection = new Connection(RPC_URL, "confirmed");
39
+ const owner = await resolveShieldOwner({ username: "alice" });
40
+ const prover = createTransactionProver({
41
+ wasmPath: TRANSACTION_WASM_URL,
42
+ zkeyPath: TRANSACTION_ZKEY_URL,
43
+ });
44
+
45
+ let result = await shield({
46
+ connection,
47
+ amount: 5_000_000n, // base units
48
+ mint: new PublicKey(USDC_MINT),
49
+ owner,
50
+ signer: { publicKey: wallet.publicKey },
51
+ prover,
52
+ });
53
+
54
+ async function signAndSubmit() {
55
+ const signed = await wallet.signTransaction(result.transaction);
56
+ const signature = await connection.sendRawTransaction(signed.serialize(), {
57
+ maxRetries: 0,
58
+ });
59
+
60
+ const confirmation = await connection.confirmTransaction(
61
+ {
62
+ signature,
63
+ blockhash: result.blockhash,
64
+ lastValidBlockHeight: result.lastValidBlockHeight,
65
+ },
66
+ "confirmed",
67
+ );
68
+ if (confirmation.value.err) throw confirmation.value.err;
69
+ return signature;
70
+ }
71
+
72
+ let signature: string;
73
+ try {
74
+ signature = await signAndSubmit();
75
+ } catch (cause) {
76
+ const error = mapShieldError(cause);
77
+ if (error.retryable !== "rebuild") throw error;
78
+
79
+ // Reuses the proof and note; only the blockhash and deadline are refreshed.
80
+ result = await rebuild(result, { connection });
81
+ signature = await signAndSubmit(); // the rebuilt transaction needs a new signature
82
+ }
83
+
84
+ const finalized = await finalizeShield({
85
+ connection,
86
+ signature,
87
+ note: result.note,
88
+ owner,
89
+ commitment: "finalized",
90
+ });
91
+
92
+ console.log(finalized.leafIndex, finalized.treeId);
93
+ ```
94
+
95
+ `predictedLeafIndex` is informational only. Concurrent deposits can move the
96
+ actual index before your transaction lands. Persist `finalized.leafIndex`, which
97
+ comes from this transaction's `CommitmentEvent`.
98
+
99
+ ## Preflight and wallet UX
100
+
101
+ Preflight runs before the 10–30 second proof and checks pool limits, token
102
+ ownership and balance, ATA state, and the SOL needed by the transaction. If an
103
+ SPL token account has any delegate—even with a delegated amount of zero—the
104
+ program rejects it. `TOKEN_ACCOUNT_DELEGATED` includes a `remedy` with the
105
+ `Revoke` instruction the wallet can sign before retrying.
106
+
107
+ The wallet may describe the Veilo instruction as an unknown program. Show the
108
+ amount and destination in your own review screen before opening the wallet so
109
+ the signer can verify what it is authorizing.
110
+
111
+ ## SOL requirements
112
+
113
+ The signer pays:
114
+
115
+ - the amount itself for native SOL shields;
116
+ - the normal transaction and priority fees; and
117
+ - rent for two nullifier-marker accounts (about 0.00192 SOL at current rent).
118
+
119
+ The program fixes the marker payer to the signer. A zero-SOL wallet therefore
120
+ cannot use this path, even for an SPL token shield and even if another service
121
+ would sponsor the transaction fee. This API does not provide a gasless mode.
122
+
123
+ ## Retry decisions
124
+
125
+ Use `mapShieldError()` and branch on `retryable`:
126
+
127
+ | Error | Retry class | Action |
128
+ |---|---|---|
129
+ | `BLOCKHASH_EXPIRED`, `DEADLINE_EXPIRED` | `rebuild` | Call `rebuild()`, sign again, submit again. |
130
+ | `ROOT_STALE` | `reshield` | Call `shield()` again; a fresh proof is required. |
131
+ | `NULLIFIER_COLLISION` | `none` | Treat as already submitted and check the original signature. |
132
+ | Preflight and configuration errors | `none` | Correct the stated condition before retrying. |
133
+
134
+ `ShieldProofCache` is public and JSON-serializable. `ShieldNote` is secret. Do
135
+ not store or transmit the note in the clear, and do not bundle it with the proof
136
+ cache merely because the cache is safe to move between processes.
137
+
138
+ ## Optional mailbox delivery
139
+
140
+ `finalizeShield()` returns an encrypted `blob` suitable for `/notes/save`.
141
+ Supplying `recipientWalletPublicKey` gives faster mailbox delivery and push
142
+ notifications, but records a sender-to-recipient association at the relayer.
143
+ Omitting it keeps discovery chain-only and preserves that privacy boundary.
package/config.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ // Stub for legacy resolvers — see config.js
2
+ export * from "./dist/cjs/config.js";
package/config.js ADDED
@@ -0,0 +1,4 @@
1
+ // Stub for legacy resolvers (TypeScript moduleResolution: "node", older bundlers)
2
+ // that ignore the "exports" map. Modern resolvers use "./config" from package.json
3
+ // exports and never reach this file.
4
+ module.exports = require("./dist/cjs/config.js");
@@ -1,10 +1,10 @@
1
1
  import * as anchor from "@coral-xyz/anchor";
2
- import { Program, Idl } from "@coral-xyz/anchor";
2
+ import type { Program, Idl } from "@coral-xyz/anchor";
3
3
  import { PublicKey, Transaction, Keypair } from "@solana/web3.js";
4
- import { TransactionProofStruct, TransactionProofBuilder, ExtData } from "./proof";
5
- import { SerializedUTXO, InputUTXO } from "./utxo";
6
- import { MerkleTree } from "./merkle";
7
- import { PrivacyConfigAccount } from "./config";
4
+ import { TransactionProofStruct, TransactionProofBuilder, ExtData } from "./proof.js";
5
+ import { SerializedUTXO, InputUTXO } from "./utxo.js";
6
+ import { MerkleTree } from "./merkle.js";
7
+ import { PrivacyConfigAccount } from "./config.js";
8
8
  /**
9
9
  * Get pool PDAs for a given mint address.
10
10
  * Note: All seeds use "v3" suffix.
@@ -1,4 +1,37 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  Object.defineProperty(exports, "__esModule", { value: true });
3
36
  exports.getPoolPdas = getPoolPdas;
4
37
  exports.getNoteTreePda = getNoteTreePda;
@@ -25,13 +58,17 @@ exports.updateGlobalConfig = updateGlobalConfig;
25
58
  exports.getSwapExecutorPda = getSwapExecutorPda;
26
59
  exports.fundNativeSource = fundNativeSource;
27
60
  exports.transactSwap = transactSwap;
28
- const anchor_1 = require("@coral-xyz/anchor");
61
+ const anchor = __importStar(require("@coral-xyz/anchor"));
62
+ // Pulled off the namespace rather than named-imported. @coral-xyz/anchor is CJS
63
+ // with no `exports` map, and Node ESM's named-export detection cannot see `BN`
64
+ // (it is re-exported from bn.js), so `import { BN }` throws at runtime under ESM.
65
+ const { BN } = anchor;
29
66
  const web3_js_1 = require("@solana/web3.js");
30
67
  const spl_token_1 = require("@solana/spl-token");
31
- const proof_1 = require("./proof");
32
- const utxo_1 = require("./utxo");
33
- const config_1 = require("./config");
34
- const retry_1 = require("./retry");
68
+ const proof_js_1 = require("./proof.js");
69
+ const utxo_js_1 = require("./utxo.js");
70
+ const config_js_1 = require("./config.js");
71
+ const retry_js_1 = require("./retry.js");
35
72
  // -----------------------------------------------------------------------------
36
73
  // PDA Helpers
37
74
  // -----------------------------------------------------------------------------
@@ -282,7 +319,7 @@ async function initializePool(params) {
282
319
  const { config, vault, nullifiers } = getPoolPdas(program.programId, mintAddress);
283
320
  const noteTree = getNoteTreePda(program.programId, mintAddress, 0);
284
321
  await program.methods
285
- .initialize(feeBps, mintAddress, minDepositAmount ? new anchor_1.BN(minDepositAmount.toString()) : null, maxDepositAmount ? new anchor_1.BN(maxDepositAmount.toString()) : null, minWithdrawAmount ? new anchor_1.BN(minWithdrawAmount.toString()) : null, maxWithdrawAmount ? new anchor_1.BN(maxWithdrawAmount.toString()) : null)
322
+ .initialize(feeBps, mintAddress, minDepositAmount ? new BN(minDepositAmount.toString()) : null, maxDepositAmount ? new BN(maxDepositAmount.toString()) : null, minWithdrawAmount ? new BN(minWithdrawAmount.toString()) : null, maxWithdrawAmount ? new BN(maxWithdrawAmount.toString()) : null)
286
323
  .accounts({
287
324
  config,
288
325
  vault,
@@ -305,7 +342,7 @@ async function updatePoolConfig(params) {
305
342
  const { program, admin, mintAddress, minDepositAmount, maxDepositAmount, minWithdrawAmount, maxWithdrawAmount, feeBps, feeErrorMarginBps, minWithdrawalFee, minSwapFee, swapFeeBps, } = params;
306
343
  const { config } = getPoolPdas(program.programId, mintAddress);
307
344
  await program.methods
308
- .updatePoolConfig(mintAddress, minDepositAmount ? new anchor_1.BN(minDepositAmount.toString()) : null, maxDepositAmount ? new anchor_1.BN(maxDepositAmount.toString()) : null, minWithdrawAmount ? new anchor_1.BN(minWithdrawAmount.toString()) : null, maxWithdrawAmount ? new anchor_1.BN(maxWithdrawAmount.toString()) : null, feeBps != null ? new anchor_1.BN(feeBps) : null, minWithdrawalFee ? new anchor_1.BN(minWithdrawalFee.toString()) : null, feeErrorMarginBps != null ? new anchor_1.BN(feeErrorMarginBps) : null, minSwapFee ? new anchor_1.BN(minSwapFee.toString()) : null, swapFeeBps != null ? new anchor_1.BN(swapFeeBps) : null)
345
+ .updatePoolConfig(mintAddress, minDepositAmount ? new BN(minDepositAmount.toString()) : null, maxDepositAmount ? new BN(maxDepositAmount.toString()) : null, minWithdrawAmount ? new BN(minWithdrawAmount.toString()) : null, maxWithdrawAmount ? new BN(maxWithdrawAmount.toString()) : null, feeBps != null ? new BN(feeBps) : null, minWithdrawalFee ? new BN(minWithdrawalFee.toString()) : null, feeErrorMarginBps != null ? new BN(feeErrorMarginBps) : null, minSwapFee ? new BN(minSwapFee.toString()) : null, swapFeeBps != null ? new BN(swapFeeBps) : null)
309
346
  .accounts({
310
347
  config,
311
348
  admin: admin.publicKey,
@@ -412,8 +449,8 @@ async function transact(params) {
412
449
  // Nullifier markers are global (no tree_id) to prevent cross-tree double-spend
413
450
  const nullifierMarker0 = getNullifierMarkerPda(program.programId, mintAddress, inputNullifiers[0]);
414
451
  const nullifierMarker1 = getNullifierMarkerPda(program.programId, mintAddress, inputNullifiers[1]);
415
- const extDataHash = (0, proof_1.computeExtDataHash)(extData);
416
- const isNativeSol = mintAddress.equals(config_1.NATIVE_SOL_MINT);
452
+ const extDataHash = (0, proof_js_1.computeExtDataHash)(extData);
453
+ const isNativeSol = mintAddress.equals(config_js_1.NATIVE_SOL_MINT);
417
454
  // For SPL tokens, resolve token accounts
418
455
  let vaultTA = vaultTokenAccount;
419
456
  let userTA = userTokenAccount;
@@ -434,11 +471,11 @@ async function transact(params) {
434
471
  }
435
472
  }
436
473
  const tx = program.methods
437
- .transact(Array.from(root), inputTreeId, outputTreeId, new anchor_1.BN(publicAmount.toString()), Array.from(extDataHash), mintAddress, Array.from(inputNullifiers[0]), Array.from(inputNullifiers[1]), Array.from(outputCommitments[0]), Array.from(outputCommitments[1]), new anchor_1.BN(deadline.toString()), {
474
+ .transact(Array.from(root), inputTreeId, outputTreeId, new BN(publicAmount.toString()), Array.from(extDataHash), mintAddress, Array.from(inputNullifiers[0]), Array.from(inputNullifiers[1]), Array.from(outputCommitments[0]), Array.from(outputCommitments[1]), new BN(deadline.toString()), {
438
475
  recipient: extData.recipient,
439
476
  relayer: extData.relayer,
440
- fee: new anchor_1.BN(extData.fee.toString()),
441
- refund: new anchor_1.BN(extData.refund.toString()),
477
+ fee: new BN(extData.fee.toString()),
478
+ refund: new BN(extData.refund.toString()),
442
479
  }, {
443
480
  proofA: proof.proofA,
444
481
  proofB: proof.proofB,
@@ -463,7 +500,7 @@ async function transact(params) {
463
500
  systemProgram: web3_js_1.SystemProgram.programId,
464
501
  })
465
502
  .signers([relayer]);
466
- return (0, retry_1.withRpcRetry)(() => tx.rpc());
503
+ return (0, retry_js_1.withRpcRetry)(() => tx.rpc());
467
504
  }
468
505
  /**
469
506
  * Build an unsigned deposit {@link Transaction} for the privacy pool.
@@ -480,10 +517,10 @@ async function transact(params) {
480
517
  async function deposit(params) {
481
518
  const { program, depositor, amount, mintAddress, recipientPubkey, tree, proofBuilder, treeId = 0, extData: partialExtData, } = params;
482
519
  // Create a random keypair for the zero inputs (they don't matter since amount is 0)
483
- const zeroKeypair = (0, utxo_1.generateKeypair)();
520
+ const zeroKeypair = (0, utxo_js_1.generateKeypair)();
484
521
  // Create zero input UTXOs (for deposits, we don't spend any existing UTXOs)
485
- const zeroInput0 = (0, utxo_1.createOwnedZeroUTXO)(zeroKeypair.privateKey, mintAddress);
486
- const zeroInput1 = (0, utxo_1.createOwnedZeroUTXO)(zeroKeypair.privateKey, mintAddress);
522
+ const zeroInput0 = (0, utxo_js_1.createOwnedZeroUTXO)(zeroKeypair.privateKey, mintAddress);
523
+ const zeroInput1 = (0, utxo_js_1.createOwnedZeroUTXO)(zeroKeypair.privateKey, mintAddress);
487
524
  // The circuit skips the Merkle proof check for zero-amount inputs (amount == 0
488
525
  // causes `enabled = 0` in MerkleProofIfEnabled). So we provide a dummy path using
489
526
  // the tree's pre-computed zero chain without inserting anything into the tree.
@@ -503,12 +540,12 @@ async function deposit(params) {
503
540
  privateKey: zeroKeypair.privateKey,
504
541
  },
505
542
  ];
506
- const outputUTXO0 = (0, utxo_1.createUTXO)({
543
+ const outputUTXO0 = (0, utxo_js_1.createUTXO)({
507
544
  amount: amount,
508
545
  pubkey: recipientPubkey,
509
546
  mintAddress,
510
547
  });
511
- const outputUTXO1 = (0, utxo_1.createUTXO)({
548
+ const outputUTXO1 = (0, utxo_js_1.createUTXO)({
512
549
  amount: 0n,
513
550
  pubkey: recipientPubkey,
514
551
  mintAddress,
@@ -525,7 +562,7 @@ async function deposit(params) {
525
562
  refund: partialExtData?.refund ?? 0n,
526
563
  claimant: partialExtData?.claimant ?? web3_js_1.SystemProgram.programId,
527
564
  };
528
- const circuitInputs = (0, proof_1.prepareTransactionInputs)({
565
+ const circuitInputs = (0, proof_js_1.prepareTransactionInputs)({
529
566
  inputUTXOs,
530
567
  outputUTXOs,
531
568
  root: currentRoot,
@@ -534,7 +571,7 @@ async function deposit(params) {
534
571
  mintAddress,
535
572
  });
536
573
  const rawProof = await proofBuilder(circuitInputs);
537
- const proof = (0, proof_1.encodeSnarkjsProofToTransactionProof)(rawProof);
574
+ const proof = (0, proof_js_1.encodeSnarkjsProofToTransactionProof)(rawProof);
538
575
  // -----------------------------------------------------------------------
539
576
  // Build the transact instruction inline (duplicated from `transact()`).
540
577
  //
@@ -552,8 +589,8 @@ async function deposit(params) {
552
589
  const outputTree = getNoteTreePda(program.programId, mintAddress, treeId);
553
590
  const nullifierMarker0 = getNullifierMarkerPda(program.programId, mintAddress, circuitInputs.inputNullifiers[0]);
554
591
  const nullifierMarker1 = getNullifierMarkerPda(program.programId, mintAddress, circuitInputs.inputNullifiers[1]);
555
- const extDataHash = (0, proof_1.computeExtDataHash)(extData);
556
- const isNativeSol = mintAddress.equals(config_1.NATIVE_SOL_MINT);
592
+ const extDataHash = (0, proof_js_1.computeExtDataHash)(extData);
593
+ const isNativeSol = mintAddress.equals(config_js_1.NATIVE_SOL_MINT);
557
594
  let vaultTA;
558
595
  let userTA;
559
596
  let recipientTA;
@@ -565,12 +602,12 @@ async function deposit(params) {
565
602
  relayerTA = await (0, spl_token_1.getAssociatedTokenAddress)(mintAddress, depositorPubkey);
566
603
  }
567
604
  const builtTx = await program.methods
568
- .transact(Array.from(currentRoot), treeId, treeId, new anchor_1.BN(amount.toString()), Array.from(extDataHash), mintAddress, Array.from(circuitInputs.inputNullifiers[0]), Array.from(circuitInputs.inputNullifiers[1]), Array.from(circuitInputs.outputCommitments[0]), Array.from(circuitInputs.outputCommitments[1]), new anchor_1.BN(Math.floor(Date.now() / 1000) + 3600), // 1-hour window from build time
605
+ .transact(Array.from(currentRoot), treeId, treeId, new BN(amount.toString()), Array.from(extDataHash), mintAddress, Array.from(circuitInputs.inputNullifiers[0]), Array.from(circuitInputs.inputNullifiers[1]), Array.from(circuitInputs.outputCommitments[0]), Array.from(circuitInputs.outputCommitments[1]), new BN(Math.floor(Date.now() / 1000) + 3600), // 1-hour window from build time
569
606
  {
570
607
  recipient: extData.recipient,
571
608
  relayer: extData.relayer,
572
- fee: new anchor_1.BN(extData.fee.toString()),
573
- refund: new anchor_1.BN(extData.refund.toString()),
609
+ fee: new BN(extData.fee.toString()),
610
+ refund: new BN(extData.refund.toString()),
574
611
  }, {
575
612
  proofA: proof.proofA,
576
613
  proofB: proof.proofB,
@@ -639,12 +676,12 @@ async function withdraw(params) {
639
676
  if (changeAmount < 0n) {
640
677
  throw new Error("Insufficient input balance for withdrawal");
641
678
  }
642
- const changeUTXO = (0, utxo_1.createUTXO)({
679
+ const changeUTXO = (0, utxo_js_1.createUTXO)({
643
680
  amount: changeAmount,
644
681
  pubkey: changePubkey,
645
682
  mintAddress,
646
683
  });
647
- const zeroUTXO = (0, utxo_1.createUTXO)({
684
+ const zeroUTXO = (0, utxo_js_1.createUTXO)({
648
685
  amount: 0n,
649
686
  pubkey: changePubkey,
650
687
  mintAddress,
@@ -659,7 +696,7 @@ async function withdraw(params) {
659
696
  };
660
697
  // publicAmount is negative for withdrawals
661
698
  const publicAmount = -withdrawAmount;
662
- const circuitInputs = (0, proof_1.prepareTransactionInputs)({
699
+ const circuitInputs = (0, proof_js_1.prepareTransactionInputs)({
663
700
  inputUTXOs,
664
701
  outputUTXOs,
665
702
  root,
@@ -668,7 +705,7 @@ async function withdraw(params) {
668
705
  mintAddress,
669
706
  });
670
707
  const rawProof = await proofBuilder(circuitInputs);
671
- const proof = (0, proof_1.encodeSnarkjsProofToTransactionProof)(rawProof);
708
+ const proof = (0, proof_js_1.encodeSnarkjsProofToTransactionProof)(rawProof);
672
709
  await transact({
673
710
  program,
674
711
  relayer,
@@ -710,12 +747,12 @@ async function privateTransfer(params) {
710
747
  if (totalInput !== totalOutput) {
711
748
  throw new Error(`Balance mismatch: inputs=${totalInput}, outputs=${totalOutput}`);
712
749
  }
713
- const outputUTXO0 = (0, utxo_1.createUTXO)({
750
+ const outputUTXO0 = (0, utxo_js_1.createUTXO)({
714
751
  amount: outputAmounts[0],
715
752
  pubkey: outputPubkeys[0],
716
753
  mintAddress,
717
754
  });
718
- const outputUTXO1 = (0, utxo_1.createUTXO)({
755
+ const outputUTXO1 = (0, utxo_js_1.createUTXO)({
719
756
  amount: outputAmounts[1],
720
757
  pubkey: outputPubkeys[1],
721
758
  mintAddress,
@@ -734,7 +771,7 @@ async function privateTransfer(params) {
734
771
  };
735
772
  // publicAmount is 0 for transfers
736
773
  const publicAmount = 0n;
737
- const circuitInputs = (0, proof_1.prepareTransactionInputs)({
774
+ const circuitInputs = (0, proof_js_1.prepareTransactionInputs)({
738
775
  inputUTXOs,
739
776
  outputUTXOs,
740
777
  root,
@@ -743,7 +780,7 @@ async function privateTransfer(params) {
743
780
  mintAddress,
744
781
  });
745
782
  const rawProof = await proofBuilder(circuitInputs);
746
- const proof = (0, proof_1.encodeSnarkjsProofToTransactionProof)(rawProof);
783
+ const proof = (0, proof_js_1.encodeSnarkjsProofToTransactionProof)(rawProof);
747
784
  await transact({
748
785
  program,
749
786
  relayer,
@@ -814,7 +851,7 @@ async function fundNativeSource(params) {
814
851
  const executor = getSwapExecutorPda(program.programId, sourceMint, destMint, inputNullifier0, relayer.publicKey);
815
852
  const executorSourceToken = await (0, spl_token_1.getAssociatedTokenAddress)(spl_token_1.NATIVE_MINT, executor, true);
816
853
  return program.methods
817
- .fundNativeSource(sourceMint, destMint, Array.from(inputNullifier0), new anchor_1.BN(swapAmount.toString()))
854
+ .fundNativeSource(sourceMint, destMint, Array.from(inputNullifier0), new BN(swapAmount.toString()))
818
855
  .accounts({
819
856
  executor,
820
857
  executorSourceToken,
@@ -857,17 +894,17 @@ async function transactSwap(params) {
857
894
  proofB: proof.proofB,
858
895
  proofC: proof.proofC,
859
896
  }, Array.from(sourceRoot), sourceTreeId, sourceMint, Array.from(inputNullifiers[0]), Array.from(inputNullifiers[1]), destTreeId, destMint, Array.from(outputCommitments[0]), Array.from(outputCommitments[1]), {
860
- minAmountOut: new anchor_1.BN(swapParams.minAmountOut.toString()),
861
- deadline: new anchor_1.BN(swapParams.deadline.toString()),
897
+ minAmountOut: new BN(swapParams.minAmountOut.toString()),
898
+ deadline: new BN(swapParams.deadline.toString()),
862
899
  sourceMint: swapParams.sourceMint,
863
900
  destMint: swapParams.destMint,
864
- destAmount: new anchor_1.BN(swapParams.destAmount.toString()),
901
+ destAmount: new BN(swapParams.destAmount.toString()),
865
902
  swapDataHash: Array.from(swapParams.swapDataHash),
866
- }, new anchor_1.BN(swapAmount.toString()), swapData, {
903
+ }, new BN(swapAmount.toString()), swapData, {
867
904
  recipient: extData.recipient,
868
905
  relayer: extData.relayer,
869
- fee: new anchor_1.BN(extData.fee.toString()),
870
- refund: new anchor_1.BN(extData.refund.toString()),
906
+ fee: new BN(extData.fee.toString()),
907
+ refund: new BN(extData.refund.toString()),
871
908
  })
872
909
  .accounts({
873
910
  sourceConfig,
@@ -898,7 +935,7 @@ async function transactSwap(params) {
898
935
  .instruction();
899
936
  const provider = program.provider;
900
937
  const tx = new web3_js_1.Transaction();
901
- if (sourceMint.equals(config_1.NATIVE_SOL_MINT)) {
938
+ if (sourceMint.equals(config_js_1.NATIVE_SOL_MINT)) {
902
939
  const fundIx = await fundNativeSource({
903
940
  program,
904
941
  relayer,
@@ -910,5 +947,5 @@ async function transactSwap(params) {
910
947
  tx.add(fundIx);
911
948
  }
912
949
  tx.add(swapIx);
913
- return (0, retry_1.withRpcRetry)(() => provider.sendAndConfirm(tx, [relayer]));
950
+ return (0, retry_js_1.withRpcRetry)(() => provider.sendAndConfirm(tx, [relayer]));
914
951
  }
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Compact note ciphers — the 80-byte payload carried inside the on-chain
3
+ * `transact` instruction (`note_ciphers: Option<NoteCiphers>`) and re-emitted in
4
+ * `CommitmentEvent`.
5
+ *
6
+ * This is what makes a note recoverable from chain data alone: a recipient who
7
+ * was never told about a deposit can still find it by scanning `view_tag` and
8
+ * decrypting the blob. Without it, note delivery depends on someone calling the
9
+ * relayer, which a third-party integrator cannot be trusted to do.
10
+ *
11
+ * ## Byte-compatibility is load-bearing
12
+ *
13
+ * Four sibling implementations already exist (relayer-server, extension ×2,
14
+ * wallet-app). This is the canonical one, and it MUST agree with them byte for
15
+ * byte in both directions:
16
+ *
17
+ * - disagree on encrypt → new notes are invisible to every existing client
18
+ * - disagree on decrypt → the entire historical note corpus becomes unreadable
19
+ *
20
+ * Three details are easy to get wrong and are individually fatal:
21
+ *
22
+ * 1. The KDF is `nacl.hash(x).slice(0, 32)` — **truncated SHA-512**, despite the
23
+ * sibling helper being named `sha256ForNotes`. See `kdfSHA512_256` in utxo.ts.
24
+ * 2. The ephemeral key published on-chain is **Ed25519**; it is converted to
25
+ * X25519 only for the Diffie-Hellman. Scanners convert it back.
26
+ * 3. `viewTag` is the first byte of the hash of the **raw shared secret**, not of
27
+ * the derived key. A wrong view tag makes every note invisible to the scan
28
+ * loop, which rejects ~255/256 candidates on this byte alone.
29
+ *
30
+ * The ECDH primitives are imported from `utxo.ts` rather than reimplemented — a
31
+ * fifth independent Edwards→Montgomery implementation is exactly how the current
32
+ * drift risk between the four siblings arose.
33
+ *
34
+ * Verified against the siblings by `tests/compact-note.test.ts` (golden vectors)
35
+ * and `scripts/verify-compact-cipher-parity.mjs` (differential).
36
+ */
37
+ /** Size of the on-chain compact blob: nonce[24] || secretbox(40-byte plaintext)[56]. */
38
+ export declare const COMPACT_BLOB_LENGTH = 80;
39
+ export type CompactNoteCipher = {
40
+ /** Ed25519 ephemeral public key, published on-chain. */
41
+ ephemeralPublicKey: Uint8Array;
42
+ /** 80 bytes: nonce[24] || ciphertext[56]. */
43
+ compactBlob: Uint8Array;
44
+ /** 1-byte scan filter. */
45
+ viewTag: number;
46
+ };
47
+ /**
48
+ * Test-only determinism hook. NOT part of the public contract — it exists so
49
+ * golden vectors can pin exact bytes against the sibling implementations, which
50
+ * is the only way to prove byte-compatibility rather than assume it.
51
+ *
52
+ * @internal
53
+ */
54
+ export type CompactNoteDeterminism = {
55
+ ephemeralSeed: Uint8Array;
56
+ nonce: Uint8Array;
57
+ };
58
+ /**
59
+ * Encrypt a note's secret material to a recipient's Solana wallet key.
60
+ *
61
+ * The recipient does not need to be the signer of the transaction, or to have
62
+ * any prior relationship with the sender — this is what makes shielding to an
63
+ * arbitrary owner possible.
64
+ *
65
+ * @param recipientWalletPubkey 32-byte Ed25519 Solana wallet public key
66
+ * @param blinding 32-byte big-endian blinding factor
67
+ * @param amount note amount in base units
68
+ */
69
+ export declare function createCompactNoteCipher(recipientWalletPubkey: Uint8Array, blinding: Uint8Array, amount: bigint,
70
+ /** @internal */ __det?: CompactNoteDeterminism): CompactNoteCipher;
71
+ /**
72
+ * Recover a note's blinding and amount from an on-chain compact cipher.
73
+ *
74
+ * Returns `null` when the blob was not encrypted to this key — the expected
75
+ * outcome for the overwhelming majority of candidates during a scan, so callers
76
+ * should filter on `viewTag` first (see {@link matchesViewTag}) and only attempt
77
+ * decryption on the ~1/256 that survive.
78
+ *
79
+ * @param walletSecretKey 32-byte Ed25519 seed or 64-byte secret key
80
+ */
81
+ export declare function decryptCompactNoteCipher(walletSecretKey: Uint8Array, ephemeralPublicKey: Uint8Array, compactBlob: Uint8Array, precomputed?: {
82
+ sharedSecret?: Uint8Array;
83
+ x25519Private?: Uint8Array;
84
+ }): {
85
+ blinding: Uint8Array;
86
+ amount: bigint;
87
+ } | null;
88
+ /**
89
+ * Cheap scan filter: does this on-chain cipher plausibly belong to us?
90
+ *
91
+ * Rejects ~255/256 candidates for the cost of one scalar multiplication and one
92
+ * hash, versus a full secretbox open. Hoist `x25519Private` across a scan loop
93
+ * with {@link toX25519Private}.
94
+ */
95
+ export declare function matchesViewTag(walletSecretKey: Uint8Array, ephemeralPublicKey: Uint8Array, viewTag: number, precomputed?: {
96
+ x25519Private?: Uint8Array;
97
+ }): {
98
+ matches: boolean;
99
+ sharedSecret: Uint8Array;
100
+ };
101
+ /**
102
+ * Convert an Ed25519 wallet secret key to its X25519 scalar once, for reuse
103
+ * across a scan loop.
104
+ */
105
+ export declare function toX25519Private(walletSecretKey: Uint8Array): Uint8Array;
106
+ /** The all-zero cipher the program treats as "no note here". */
107
+ export declare function emptyNoteCipher(): CompactNoteCipher;