@hula-privacy/mixer 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,17 +1,10 @@
1
1
  {
2
2
  "name": "@hula-privacy/mixer",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "Hula Privacy Protocol SDK - Complete toolkit for private transactions on Solana",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
7
7
  "types": "dist/index.d.ts",
8
- "exports": {
9
- ".": {
10
- "import": "./dist/index.mjs",
11
- "require": "./dist/index.js",
12
- "types": "./dist/index.d.ts"
13
- }
14
- },
15
8
  "scripts": {
16
9
  "build": "tsup src/index.ts --format cjs,esm --dts",
17
10
  "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
package/src/api.ts CHANGED
@@ -155,7 +155,11 @@ export class RelayerClient {
155
155
  const leaves = await this.getAllLeavesForTree(treeIndex);
156
156
  // Sort by leafIndex to ensure correct order
157
157
  leaves.sort((a, b) => a.leafIndex - b.leafIndex);
158
- return leaves.map(l => BigInt(l.commitment));
158
+ // Handle hex strings with or without 0x prefix
159
+ return leaves.map(l => {
160
+ const commitment = l.commitment.startsWith("0x") ? l.commitment : `0x${l.commitment}`;
161
+ return BigInt(commitment);
162
+ });
159
163
  }
160
164
 
161
165
  // ============================================================================
package/src/crypto.ts CHANGED
@@ -179,21 +179,28 @@ export function deriveSpendingKeyFromSignature(signature: Uint8Array): bigint {
179
179
  * Encrypt a note for a recipient
180
180
  *
181
181
  * The note contains the UTXO data needed for the recipient to claim it.
182
+ * Optimized for size:
183
+ * - mintTokenAddress: only first 8 bytes (can match on-chain by prefix)
184
+ * - leafIndex: omitted (recipient can query relayer with commitment)
182
185
  */
183
186
  export function encryptNote(
184
187
  noteData: {
185
188
  value: bigint;
186
189
  mintTokenAddress: bigint;
187
190
  secret: bigint;
188
- leafIndex: number;
191
+ leafIndex?: number; // Optional, omitted to save space
189
192
  },
190
193
  recipientEncryptionPubKey: Uint8Array
191
194
  ): EncryptedNote {
195
+ // Use only first 8 bytes of mintTokenAddress to save space
196
+ // Recipient can match this prefix against known mints
197
+ const mintPrefix = noteData.mintTokenAddress.toString(16).padStart(64, "0").slice(0, 16);
198
+
192
199
  const payload = {
193
- value: noteData.value.toString(),
194
- mintTokenAddress: noteData.mintTokenAddress.toString(),
195
- secret: noteData.secret.toString(),
196
- leafIndex: noteData.leafIndex,
200
+ v: noteData.value.toString(), // value
201
+ m: mintPrefix, // mint (first 8 bytes as hex)
202
+ s: noteData.secret.toString(), // secret
203
+ // leafIndex omitted - recipient queries relayer with computed commitment
197
204
  };
198
205
 
199
206
  const message = new TextEncoder().encode(JSON.stringify(payload));
@@ -218,11 +225,13 @@ export function encryptNote(
218
225
  * Decrypt an encrypted note
219
226
  *
220
227
  * Returns null if decryption fails (not intended for this recipient)
228
+ * Note: leafIndex is not included in encrypted notes to save space.
229
+ * The recipient should query the relayer with the computed commitment.
221
230
  */
222
231
  export function decryptNote(
223
232
  encryptedNote: EncryptedNote,
224
233
  encryptionSecretKey: Uint8Array
225
- ): { value: bigint; mintTokenAddress: bigint; secret: bigint; leafIndex: number } | null {
234
+ ): { value: bigint; mintPrefix: string; secret: bigint } | null {
226
235
  try {
227
236
  const decrypted = nacl.box.open(
228
237
  encryptedNote.ciphertext,
@@ -234,12 +243,23 @@ export function decryptNote(
234
243
  if (!decrypted) return null;
235
244
 
236
245
  const noteData = JSON.parse(new TextDecoder().decode(decrypted));
237
- return {
238
- value: BigInt(noteData.value),
239
- mintTokenAddress: BigInt(noteData.mintTokenAddress),
240
- secret: BigInt(noteData.secret),
241
- leafIndex: noteData.leafIndex,
242
- };
246
+
247
+ // Handle both old format (full data) and new format (compact)
248
+ if (noteData.v !== undefined) {
249
+ // New compact format
250
+ return {
251
+ value: BigInt(noteData.v),
252
+ mintPrefix: noteData.m, // First 8 bytes as hex string
253
+ secret: BigInt(noteData.s),
254
+ };
255
+ } else {
256
+ // Legacy format (full mintTokenAddress)
257
+ return {
258
+ value: BigInt(noteData.value),
259
+ mintPrefix: BigInt(noteData.mintTokenAddress).toString(16).padStart(64, "0").slice(0, 16),
260
+ secret: BigInt(noteData.secret),
261
+ };
262
+ }
243
263
  } catch {
244
264
  return null;
245
265
  }