@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
@@ -0,0 +1,202 @@
1
+ import { AddressLookupTableAccount, Connection, PublicKey, VersionedTransaction } from "@solana/web3.js";
2
+ import type { TransactionProofBuilder, TransactionProofStruct } from "../proof.js";
3
+ import type { CompactNoteCipher } from "../compactNote.js";
4
+ /**
5
+ * Who owns the resulting note. Both halves are required and neither is derived
6
+ * from the other:
7
+ *
8
+ * - `veiloPublicKey` is the Poseidon field element bound into the output
9
+ * commitment. It is the **spending** authority.
10
+ * - `noteViewingKey` is the Ed25519 wallet key the compact cipher is encrypted
11
+ * to. It is the **detection** authority.
12
+ *
13
+ * If these two belong to different people, the note is *spendable but
14
+ * invisible*: the owner can never find it, so the funds are effectively gone.
15
+ * Nothing on-chain and nothing in this type can detect that — which is why
16
+ * `resolveShieldOwner()` exists and why hand-constructing this requires an
17
+ * explicit acknowledgement.
18
+ *
19
+ * See veilo-browser-extension/.../privateStealthWallet.ts:403-415 for the
20
+ * production comment describing this failure mode.
21
+ */
22
+ export type ShieldOwner = {
23
+ veiloPublicKey: bigint;
24
+ noteViewingKey: PublicKey;
25
+ /**
26
+ * Set automatically by {@link resolveShieldOwner}, which fetches both halves
27
+ * from a single relayer response and can therefore guarantee they match.
28
+ *
29
+ * Hand-built owners must set this explicitly — it is the only mechanism
30
+ * standing between an integration mistake and silent fund loss.
31
+ */
32
+ acknowledgeOwnerInvariant?: true;
33
+ };
34
+ /**
35
+ * Who signs and pays. Public key only — the SDK never receives a secret key.
36
+ *
37
+ * The signer is unavoidably the fee payer, the funding source, and the payer of
38
+ * ~0.00192 SOL of nullifier-marker rent (the program hardcodes
39
+ * `payer = relayer` on both marker accounts). A wallet with no SOL cannot
40
+ * shield through this path regardless of who submits the transaction.
41
+ */
42
+ export type ShieldSigner = {
43
+ publicKey: PublicKey;
44
+ /**
45
+ * Source token account for SPL shields. Defaults to the signer's canonical
46
+ * ATA. Must be owned by `publicKey` with no delegate set.
47
+ */
48
+ tokenAccount?: PublicKey;
49
+ };
50
+ /** Where the target tree and its root come from. */
51
+ export interface TreeSource {
52
+ getDepositTarget(mint: PublicKey): Promise<DepositTarget>;
53
+ }
54
+ export type DepositTarget = {
55
+ /** Always 0 — the tree whose root the dummy inputs nominally prove against. */
56
+ inputTreeId: number;
57
+ /** 32-byte root, read from that tree's on-chain root history. */
58
+ inputRoot: Uint8Array;
59
+ /** Tree the new commitments are appended to. */
60
+ outputTreeId: number;
61
+ /** `nextIndex` at build time. A prediction — see `predictedLeafIndex`. */
62
+ outputNextIndex: number;
63
+ };
64
+ /** Where the address lookup table comes from. */
65
+ export interface AltSource {
66
+ resolve(ctx: {
67
+ connection: Connection;
68
+ mint: PublicKey;
69
+ outputTreeId: number;
70
+ programId: PublicKey;
71
+ }): Promise<AddressLookupTableAccount>;
72
+ }
73
+ /**
74
+ * Caching for values that are stable across builds (the ALT account, rent
75
+ * exemption minimums, pool config).
76
+ *
77
+ * Deliberately an interface: the three production deposit implementations
78
+ * differ on exactly this axis — `localStorage`, `chrome.storage`, and
79
+ * `AsyncStorage` — and none of them belongs in a published SDK.
80
+ */
81
+ export interface ShieldCachePort {
82
+ get<T>(key: string): Promise<T | undefined>;
83
+ set<T>(key: string, value: T, ttlMs?: number): Promise<void>;
84
+ }
85
+ export type PreflightOptions = {
86
+ /** Skip the SPL token-account inspection (owner, delegate, balance). */
87
+ skipTokenAccount?: boolean;
88
+ /** Skip the signer balance check. */
89
+ skipBalance?: boolean;
90
+ /** Skip pool state checks (paused, min/max, tree capacity). */
91
+ skipPoolState?: boolean;
92
+ };
93
+ export type ShieldParams = {
94
+ connection: Connection;
95
+ /** Net amount to shield, in base units. No fee is taken on deposits. */
96
+ amount: bigint;
97
+ /** Defaults to native SOL. */
98
+ mint?: PublicKey;
99
+ owner: ShieldOwner;
100
+ signer: ShieldSigner;
101
+ /** Proof generation. `createTransactionProver(artifacts)` satisfies this. */
102
+ prover: TransactionProofBuilder;
103
+ treeSource?: TreeSource;
104
+ alt?: AltSource;
105
+ cache?: ShieldCachePort;
106
+ programId?: PublicKey;
107
+ computeUnitLimit?: number;
108
+ /** Set to 0 to omit the priority-fee instruction entirely. */
109
+ computeUnitPriceMicroLamports?: number;
110
+ deadlineSeconds?: number;
111
+ /** Supply to avoid an RPC round-trip; otherwise fetched just before compiling. */
112
+ blockhash?: {
113
+ blockhash: string;
114
+ lastValidBlockHeight: number;
115
+ };
116
+ preflight?: boolean | PreflightOptions;
117
+ };
118
+ /**
119
+ * The recoverable secret material for the note this shield creates.
120
+ *
121
+ * SECRET. Anyone holding this can locate the note. It must never be persisted
122
+ * server-side in the clear or transmitted alongside {@link ShieldProofCache},
123
+ * which is deliberately public.
124
+ */
125
+ export type ShieldNote = {
126
+ commitment: Uint8Array;
127
+ blinding: bigint;
128
+ amount: bigint;
129
+ ownerVeiloPublicKey: bigint;
130
+ mint: PublicKey;
131
+ treeId: number;
132
+ compact: CompactNoteCipher;
133
+ };
134
+ /**
135
+ * Everything needed to re-assemble the transaction with a fresh blockhash.
136
+ *
137
+ * PUBLIC and JSON-serializable by construction: it carries no blinding, no
138
+ * private key, and no note plaintext. A platform can build server-side, ship
139
+ * this to a client for signature, and rebuild in a different process without
140
+ * ever moving a secret.
141
+ */
142
+ export type ShieldProofCache = {
143
+ version: 1;
144
+ programId: string;
145
+ mint: string;
146
+ signer: string;
147
+ altAddress: string;
148
+ inputTreeId: number;
149
+ outputTreeId: number;
150
+ root: string;
151
+ publicAmount: string;
152
+ extData: {
153
+ recipient: string;
154
+ relayer: string;
155
+ fee: string;
156
+ refund: string;
157
+ claimant: string;
158
+ };
159
+ extDataHash: string;
160
+ inputNullifiers: [string, string];
161
+ outputCommitments: [string, string];
162
+ proof: TransactionProofStruct;
163
+ noteCiphers: {
164
+ note0EphemeralKey: string;
165
+ note0Encrypted: string;
166
+ note0ViewTag: number;
167
+ note1EphemeralKey: string;
168
+ note1Encrypted: string;
169
+ note1ViewTag: number;
170
+ };
171
+ /** Resolved instruction accounts, keyed by IDL account name. */
172
+ accounts: Record<string, string>;
173
+ computeUnitLimit: number;
174
+ };
175
+ export type ShieldQuote = {
176
+ /** Serialized size including the signature. Must be <= 1232. */
177
+ serializedSize: number;
178
+ computeUnitLimit: number;
179
+ computeUnitPriceMicroLamports: number;
180
+ estimatedFeeLamports: bigint;
181
+ /** Nullifier-marker rent, permanently burned by the signer. */
182
+ estimatedRentLamports: bigint;
183
+ };
184
+ export type ShieldResult = {
185
+ /** UNSIGNED. The caller signs and submits — this SDK never broadcasts. */
186
+ transaction: VersionedTransaction;
187
+ blockhash: string;
188
+ lastValidBlockHeight: number;
189
+ deadline: bigint;
190
+ note: ShieldNote;
191
+ /**
192
+ * Leaf index the output commitment is *expected* to land at.
193
+ *
194
+ * A prediction, read before submission. Under concurrent deposits into the
195
+ * same tree it will be wrong. Use `finalizeShield()` to read the authoritative
196
+ * index from the confirmed transaction's `CommitmentEvent` before persisting
197
+ * anything that depends on it.
198
+ */
199
+ predictedLeafIndex: number;
200
+ quote: ShieldQuote;
201
+ proofCache: ShieldProofCache;
202
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -182,6 +182,26 @@ export type DecryptedNote = {
182
182
  mintAddress?: string;
183
183
  treeId: number;
184
184
  };
185
+ /** Derive 32-byte encryption key from a shared secret using SHA-512 truncated.
186
+ * Must match the production "sha256" helper which uses nacl.hash (SHA-512) [0:32].
187
+ *
188
+ * DO NOT "fix" this to real SHA-256. The name in the sibling implementations
189
+ * (`sha256ForNotes`) is a misnomer, but the bytes are load-bearing: changing the
190
+ * KDF makes every historical note undecryptable.
191
+ *
192
+ * @internal Exported for `compactNote.ts`. Not part of the stable public API. */
193
+ export declare function kdfSHA512_256(secret: Uint8Array): Uint8Array;
194
+ /** Convert an Ed25519 private seed (32 bytes) to an X25519 scalar.
195
+ * Equivalent to ed2curve.convertSecretKey(seed).
196
+ *
197
+ * @internal Exported for `compactNote.ts`. Not part of the stable public API. */
198
+ export declare function ed25519SeedToX25519Private(seed: Uint8Array): Uint8Array;
199
+ /** Convert an Ed25519 compressed public key (32 bytes) to X25519.
200
+ * Equivalent to ed2curve.convertPublicKey(pubkey).
201
+ * Edwards y-coord → Montgomery u via: u = (1 + y) / (1 - y) (mod p).
202
+ *
203
+ * @internal Exported for `compactNote.ts`. Not part of the stable public API. */
204
+ export declare function ed25519PublicKeyToX25519(pubkey: Uint8Array): Uint8Array;
185
205
  /**
186
206
  * Encrypt a UTXO note for a recipient identified by their Solana wallet public key.
187
207
  * Produces a blob the relayer will store and serve via POST /notes/save.
package/dist/cjs/utxo.js CHANGED
@@ -17,13 +17,16 @@ exports.inputUTXOToCircuitFormat = inputUTXOToCircuitFormat;
17
17
  exports.deriveEncryptionKeypair = deriveEncryptionKeypair;
18
18
  exports.encryptUTXONote = encryptUTXONote;
19
19
  exports.decryptUTXONote = decryptUTXONote;
20
+ exports.kdfSHA512_256 = kdfSHA512_256;
21
+ exports.ed25519SeedToX25519Private = ed25519SeedToX25519Private;
22
+ exports.ed25519PublicKeyToX25519 = ed25519PublicKeyToX25519;
20
23
  exports.encryptBlindMailboxNote = encryptBlindMailboxNote;
21
24
  exports.decryptBlindMailboxNote = decryptBlindMailboxNote;
22
25
  exports.fetchAndDecryptNotes = fetchAndDecryptNotes;
23
- const crypto_1 = require("crypto");
26
+ const random_js_1 = require("./random.js");
24
27
  const tweetnacl_1 = __importDefault(require("tweetnacl"));
25
28
  const sha256_1 = require("@noble/hashes/sha256");
26
- const poseidon_1 = require("./poseidon");
29
+ const poseidon_js_1 = require("./poseidon.js");
27
30
  // -----------------------------------------------------------------------------
28
31
  // Keypair Functions
29
32
  // -----------------------------------------------------------------------------
@@ -33,8 +36,8 @@ const poseidon_1 = require("./poseidon");
33
36
  * Public key is derived via Poseidon: pubkey = Poseidon(privateKey)
34
37
  */
35
38
  function generateKeypair() {
36
- const privateKeyBytes = new Uint8Array((0, crypto_1.randomBytes)(32));
37
- const privateKey = (0, poseidon_1.bytesToBigIntBE)(privateKeyBytes) % poseidon_1.BN254_FR_MODULUS;
39
+ const privateKeyBytes = new Uint8Array((0, random_js_1.randomBytes)(32));
40
+ const privateKey = (0, poseidon_js_1.bytesToBigIntBE)(privateKeyBytes) % poseidon_js_1.BN254_FR_MODULUS;
38
41
  const publicKey = derivePublicKey(privateKey);
39
42
  return { privateKey, publicKey };
40
43
  }
@@ -43,15 +46,15 @@ function generateKeypair() {
43
46
  * Matches circuit's Keypair template: publicKey = Poseidon(privateKey)
44
47
  */
45
48
  function derivePublicKey(privateKey) {
46
- return (0, poseidon_1.poseidon1)(privateKey);
49
+ return (0, poseidon_js_1.poseidon1)(privateKey);
47
50
  }
48
51
  /**
49
52
  * Create keypair from a known private key.
50
53
  */
51
54
  function keypairFromPrivateKey(privateKey) {
52
55
  return {
53
- privateKey: privateKey % poseidon_1.BN254_FR_MODULUS,
54
- publicKey: derivePublicKey(privateKey % poseidon_1.BN254_FR_MODULUS),
56
+ privateKey: privateKey % poseidon_js_1.BN254_FR_MODULUS,
57
+ publicKey: derivePublicKey(privateKey % poseidon_js_1.BN254_FR_MODULUS),
55
58
  };
56
59
  }
57
60
  // -----------------------------------------------------------------------------
@@ -63,20 +66,20 @@ function keypairFromPrivateKey(privateKey) {
63
66
  * commitment = Poseidon(amount, pubkey, blinding, mintAddress)
64
67
  */
65
68
  function commitUTXO(utxo) {
66
- const commitment = (0, poseidon_1.poseidon4)(utxo.amount, utxo.pubkey, utxo.blinding, utxo.mintAddress);
67
- return (0, poseidon_1.bigIntToBytesBE)(commitment);
69
+ const commitment = (0, poseidon_js_1.poseidon4)(utxo.amount, utxo.pubkey, utxo.blinding, utxo.mintAddress);
70
+ return (0, poseidon_js_1.bigIntToBytesBE)(commitment);
68
71
  }
69
72
  /**
70
73
  * Create a random UTXO with the given parameters.
71
74
  */
72
75
  function createUTXO(params) {
73
- const blindingBytes = new Uint8Array((0, crypto_1.randomBytes)(32));
74
- const blinding = (0, poseidon_1.bytesToBigIntBE)(blindingBytes) % poseidon_1.BN254_FR_MODULUS;
76
+ const blindingBytes = new Uint8Array((0, random_js_1.randomBytes)(32));
77
+ const blinding = (0, poseidon_js_1.bytesToBigIntBE)(blindingBytes) % poseidon_js_1.BN254_FR_MODULUS;
75
78
  const utxo = {
76
79
  amount: params.amount,
77
80
  pubkey: params.pubkey,
78
81
  blinding,
79
- mintAddress: (0, poseidon_1.pubkeyToField)(params.mintAddress),
82
+ mintAddress: (0, poseidon_js_1.pubkeyToField)(params.mintAddress),
80
83
  };
81
84
  const commitment = commitUTXO(utxo);
82
85
  return {
@@ -130,7 +133,7 @@ function createOwnedZeroUTXO(privateKey, mintAddress) {
130
133
  * signature = Poseidon(privateKey, commitment, pathIndex)
131
134
  */
132
135
  function computeSignature(privateKey, commitment, pathIndex) {
133
- return (0, poseidon_1.poseidon3)(privateKey, commitment, pathIndex);
136
+ return (0, poseidon_js_1.poseidon3)(privateKey, commitment, pathIndex);
134
137
  }
135
138
  /**
136
139
  * Derive nullifier for a UTXO.
@@ -141,11 +144,11 @@ function computeSignature(privateKey, commitment, pathIndex) {
141
144
  * The signature-based nullifier ensures only the private key holder can spend.
142
145
  */
143
146
  function deriveNullifier(utxo, pathIndex, privateKey) {
144
- const commitment = (0, poseidon_1.bytesToBigIntBE)(utxo.commitment) % poseidon_1.BN254_FR_MODULUS;
145
- const pathIndexField = BigInt(pathIndex) % poseidon_1.BN254_FR_MODULUS;
147
+ const commitment = (0, poseidon_js_1.bytesToBigIntBE)(utxo.commitment) % poseidon_js_1.BN254_FR_MODULUS;
148
+ const pathIndexField = BigInt(pathIndex) % poseidon_js_1.BN254_FR_MODULUS;
146
149
  const signature = computeSignature(privateKey, commitment, pathIndexField);
147
- const nullifier = (0, poseidon_1.poseidon3)(commitment, pathIndexField, signature);
148
- return (0, poseidon_1.bigIntToBytesBE)(nullifier);
150
+ const nullifier = (0, poseidon_js_1.poseidon3)(commitment, pathIndexField, signature);
151
+ return (0, poseidon_js_1.bigIntToBytesBE)(nullifier);
149
152
  }
150
153
  /**
151
154
  * Convert InputUTXO to the format expected by the circuit.
@@ -155,7 +158,7 @@ function inputUTXOToCircuitFormat(input) {
155
158
  amount: input.amount,
156
159
  pubkey: input.pubkey,
157
160
  blinding: input.blinding,
158
- pathElements: input.pathElements.map((e) => (0, poseidon_1.bytesToBigIntBE)(e) % poseidon_1.BN254_FR_MODULUS),
161
+ pathElements: input.pathElements.map((e) => (0, poseidon_js_1.bytesToBigIntBE)(e) % poseidon_js_1.BN254_FR_MODULUS),
159
162
  pathIndex: input.pathIndex,
160
163
  privateKey: input.privateKey,
161
164
  };
@@ -165,7 +168,7 @@ function inputUTXOToCircuitFormat(input) {
165
168
  * The keypair is deterministic: same privateKey always yields the same pair.
166
169
  */
167
170
  function deriveEncryptionKeypair(privateKey) {
168
- const seed = (0, sha256_1.sha256)((0, poseidon_1.bigIntToBytesBE)(privateKey));
171
+ const seed = (0, sha256_1.sha256)((0, poseidon_js_1.bigIntToBytesBE)(privateKey));
169
172
  return tweetnacl_1.default.box.keyPair.fromSecretKey(seed);
170
173
  }
171
174
  /**
@@ -189,8 +192,8 @@ function encryptUTXONote(utxo, recipientEncPubkey) {
189
192
  }
190
193
  const plaintext = new Uint8Array(72);
191
194
  plaintext.set(amountBuf, 0);
192
- plaintext.set((0, poseidon_1.bigIntToBytesBE)(utxo.blinding), 8);
193
- plaintext.set((0, poseidon_1.bigIntToBytesBE)(utxo.privateKey), 40);
195
+ plaintext.set((0, poseidon_js_1.bigIntToBytesBE)(utxo.blinding), 8);
196
+ plaintext.set((0, poseidon_js_1.bigIntToBytesBE)(utxo.privateKey), 40);
194
197
  const sharedKey = tweetnacl_1.default.box.before(recipientEncPubkey, ephemeral.secretKey);
195
198
  const ciphertext = tweetnacl_1.default.box.after(plaintext, nonce, sharedKey);
196
199
  return { nonce, ciphertext, senderEphemeralPubkey: ephemeral.publicKey };
@@ -209,14 +212,14 @@ function decryptUTXONote(note, recipientPrivateKey, commitment, mintAddress) {
209
212
  let amount = 0n;
210
213
  for (let i = 7; i >= 0; i--)
211
214
  amount = (amount << 8n) | BigInt(plaintext[i]);
212
- const blinding = (0, poseidon_1.bytesToBigIntBE)(plaintext.slice(8, 40)) % poseidon_1.BN254_FR_MODULUS;
213
- const privateKey = (0, poseidon_1.bytesToBigIntBE)(plaintext.slice(40, 72)) % poseidon_1.BN254_FR_MODULUS;
215
+ const blinding = (0, poseidon_js_1.bytesToBigIntBE)(plaintext.slice(8, 40)) % poseidon_js_1.BN254_FR_MODULUS;
216
+ const privateKey = (0, poseidon_js_1.bytesToBigIntBE)(plaintext.slice(40, 72)) % poseidon_js_1.BN254_FR_MODULUS;
214
217
  const pubkey = derivePublicKey(privateKey);
215
218
  const utxo = {
216
219
  amount,
217
220
  pubkey,
218
221
  blinding,
219
- mintAddress: (0, poseidon_1.pubkeyToField)(mintAddress),
222
+ mintAddress: (0, poseidon_js_1.pubkeyToField)(mintAddress),
220
223
  };
221
224
  const expectedCommitment = commitUTXO(utxo);
222
225
  if (!expectedCommitment.every((b, i) => b === commitment[i]))
@@ -225,12 +228,20 @@ function decryptUTXONote(note, recipientPrivateKey, commitment, mintAddress) {
225
228
  }
226
229
  // -- Internal crypto helpers (no extra dependencies) --------------------------
227
230
  /** Derive 32-byte encryption key from a shared secret using SHA-512 truncated.
228
- * Must match the production "sha256" helper which uses nacl.hash (SHA-512) [0:32]. */
231
+ * Must match the production "sha256" helper which uses nacl.hash (SHA-512) [0:32].
232
+ *
233
+ * DO NOT "fix" this to real SHA-256. The name in the sibling implementations
234
+ * (`sha256ForNotes`) is a misnomer, but the bytes are load-bearing: changing the
235
+ * KDF makes every historical note undecryptable.
236
+ *
237
+ * @internal Exported for `compactNote.ts`. Not part of the stable public API. */
229
238
  function kdfSHA512_256(secret) {
230
239
  return tweetnacl_1.default.hash(secret).slice(0, 32);
231
240
  }
232
241
  /** Convert an Ed25519 private seed (32 bytes) to an X25519 scalar.
233
- * Equivalent to ed2curve.convertSecretKey(seed). */
242
+ * Equivalent to ed2curve.convertSecretKey(seed).
243
+ *
244
+ * @internal Exported for `compactNote.ts`. Not part of the stable public API. */
234
245
  function ed25519SeedToX25519Private(seed) {
235
246
  const h = tweetnacl_1.default.hash(seed); // SHA-512
236
247
  const scalar = h.slice(0, 32);
@@ -253,7 +264,9 @@ function modpow25519(b, e) {
253
264
  }
254
265
  /** Convert an Ed25519 compressed public key (32 bytes) to X25519.
255
266
  * Equivalent to ed2curve.convertPublicKey(pubkey).
256
- * Edwards y-coord → Montgomery u via: u = (1 + y) / (1 - y) (mod p). */
267
+ * Edwards y-coord → Montgomery u via: u = (1 + y) / (1 - y) (mod p).
268
+ *
269
+ * @internal Exported for `compactNote.ts`. Not part of the stable public API. */
257
270
  function ed25519PublicKeyToX25519(pubkey) {
258
271
  const pk = new Uint8Array(pubkey);
259
272
  pk[31] &= 0x7f; // clear sign bit to get y as LE integer
@@ -284,7 +297,7 @@ function ed25519PublicKeyToX25519(pubkey) {
284
297
  */
285
298
  function encryptBlindMailboxNote(recipientWalletPubkey, noteData) {
286
299
  // 1. Generate ephemeral Ed25519 keypair seed
287
- const ephemeralSeed = (0, crypto_1.randomBytes)(32);
300
+ const ephemeralSeed = (0, random_js_1.randomBytes)(32);
288
301
  // Ed25519 public key stored by relayer; dapp recovers X25519 via ed2curve.convertPublicKey()
289
302
  const ephemeralEdPublicKey = tweetnacl_1.default.sign.keyPair.fromSeed(new Uint8Array(ephemeralSeed)).publicKey;
290
303
  // X25519 scalar (ed2curve.convertSecretKey equivalent)