@orbinum/sdk 1.4.0 → 2.0.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.
@@ -33,6 +33,9 @@ function fastMulPoint(point, scalar) {
33
33
  }
34
34
 
35
35
  // src/foundation/encoding/hex.ts
36
+ function isHexOfLength(value, byteLen) {
37
+ return typeof value === "string" && new RegExp(`^0x[0-9a-fA-F]{${byteLen * 2}}$`).test(value);
38
+ }
36
39
  function toHex(bytes) {
37
40
  return "0x" + Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
38
41
  }
@@ -41,11 +44,12 @@ function fromHex(hex) {
41
44
  if (clean.length % 2 !== 0) {
42
45
  throw new Error(`Invalid hex string \u2014 odd length: "${hex}"`);
43
46
  }
47
+ if (!/^[0-9a-fA-F]*$/.test(clean)) {
48
+ throw new Error("Invalid hex string \u2014 non-hex characters");
49
+ }
44
50
  const bytes = new Uint8Array(clean.length / 2);
45
51
  for (let i = 0; i < bytes.length; i++) {
46
- const byte = parseInt(clean.slice(i * 2, i * 2 + 2), 16);
47
- if (isNaN(byte)) throw new Error(`Invalid hex character at position ${i * 2}`);
48
- bytes[i] = byte;
52
+ bytes[i] = parseInt(clean.slice(i * 2, i * 2 + 2), 16);
49
53
  }
50
54
  return bytes;
51
55
  }
@@ -63,7 +67,13 @@ function scalarToHex(value) {
63
67
  }
64
68
 
65
69
  // src/foundation/encoding/bytes.ts
70
+ function assert32ByteRange(n, fn) {
71
+ if (n < 0n || n >= 1n << 256n) {
72
+ throw new Error(`${fn}: value does not fit in 32 bytes: ${n}`);
73
+ }
74
+ }
66
75
  function bigintTo32Le(n) {
76
+ assert32ByteRange(n, "bigintTo32Le");
67
77
  const buf = new Uint8Array(32);
68
78
  let v = n;
69
79
  for (let i = 0; i < 32; i++) {
@@ -80,6 +90,7 @@ function bytesToBigintLE(bytes) {
80
90
  return result;
81
91
  }
82
92
  function bigintTo32Be(n) {
93
+ assert32ByteRange(n, "bigintTo32Be");
83
94
  const buf = new Uint8Array(32);
84
95
  let v = n;
85
96
  for (let i = 31; i >= 0 && v > 0n; i--) {
@@ -89,6 +100,7 @@ function bigintTo32Be(n) {
89
100
  return buf;
90
101
  }
91
102
  function bigintTo32LeArr(n) {
103
+ assert32ByteRange(n, "bigintTo32LeArr");
92
104
  const out = new Array(32).fill(0);
93
105
  let v = n;
94
106
  for (let i = 0; i < 32; i++) {
@@ -119,7 +131,7 @@ import { sha256 } from "@noble/hashes/sha2.js";
119
131
  var KEY_DOMAIN = new TextEncoder().encode("orbinum-note-encryption-v1");
120
132
  var VIEW_TAG_DOMAIN = new TextEncoder().encode("orbinum-view-tag-v1");
121
133
  var MEMO_PLAINTEXT_SIZE = 120;
122
- function serializeMemo(value, ownerPk, blinding, assetId, counterpartyPk, circuitVersion) {
134
+ function serializeMemo(value, ownerPk, blinding, assetId, sourcePk, circuitVersion) {
123
135
  const buf = new Uint8Array(MEMO_PLAINTEXT_SIZE);
124
136
  const view = new DataView(buf.buffer);
125
137
  view.setBigUint64(0, value & 0xffffffffffffffffn, true);
@@ -127,7 +139,7 @@ function serializeMemo(value, ownerPk, blinding, assetId, counterpartyPk, circui
127
139
  buf.set(ownerPk.slice(0, 32), 16);
128
140
  buf.set(blinding.slice(0, 32), 48);
129
141
  view.setUint32(80, assetId >>> 0, true);
130
- buf.set(counterpartyPk.slice(0, 32), 84);
142
+ buf.set(sourcePk.slice(0, 32), 84);
131
143
  view.setUint32(116, circuitVersion >>> 0, true);
132
144
  return buf;
133
145
  }
@@ -165,9 +177,9 @@ function parsePlaintext(nonce, ciphertextWithMac, encKey) {
165
177
  const ownerPk = bytesToBigintLE(plaintext.slice(16, 48));
166
178
  const blinding = bytesToBigintLE(plaintext.slice(48, 80));
167
179
  const assetId = BigInt(view.getUint32(80, true));
168
- const counterpartyPk = bytesToBigintLE(plaintext.slice(84, 116));
180
+ const sourcePk = bytesToBigintLE(plaintext.slice(84, 116));
169
181
  const circuitVersion = view.getUint32(116, true);
170
- return { value, ownerPk, blinding, assetId, counterpartyPk, circuitVersion };
182
+ return { value, ownerPk, blinding, assetId, sourcePk, circuitVersion };
171
183
  } catch {
172
184
  return null;
173
185
  }
@@ -185,19 +197,19 @@ var EncryptedMemo = {
185
197
  * (from PrivacyKeyManager.getViewingPublicKeyPacked() or
186
198
  * decoded from a privacy address).
187
199
  * Pass `new Uint8Array(32)` (all zeros) for a publicly-readable memo.
188
- * @param counterpartyPk 32-byte counterparty BJJ Ax. Default: all zeros.
200
+ * @param sourcePk 32-byte counterparty BJJ Ax. Default: all zeros.
189
201
  * @param circuitVersion ZK circuit version the note is spent under. Default: 0.
190
202
  * @param ephSkOverride 32-byte ephemeral secret key (stealth coordination). Optional.
191
203
  * @returns 180-byte encrypted memo: nonce(12) || ciphertext+MAC(136) || ephPk(32).
192
204
  */
193
- encrypt(value, ownerPk, blinding, assetId, commitment, recipientIvkPacked, counterpartyPk = new Uint8Array(32), circuitVersion = 0, ephSkOverride) {
205
+ encrypt(value, ownerPk, blinding, assetId, commitment, recipientIvkPacked, sourcePk = new Uint8Array(32), circuitVersion = 0, ephSkOverride) {
194
206
  const nonce = randomBytes(NONCE_SIZE);
195
207
  const plaintext = serializeMemo(
196
208
  value,
197
209
  ownerPk,
198
210
  blinding,
199
211
  assetId,
200
- counterpartyPk,
212
+ sourcePk,
201
213
  circuitVersion
202
214
  );
203
215
  const isZeroKey = recipientIvkPacked.every((b) => b === 0);
@@ -510,14 +522,14 @@ var NoteBuilder = class {
510
522
  const ownerPk = input.ownerPk ?? 0n;
511
523
  const blinding = input.blinding ?? BigInt(Date.now());
512
524
  const spendingKey = input.spendingKey ?? 0n;
513
- const counterpartyPk = input.counterpartyPk ?? 0n;
525
+ const sourcePk = input.sourcePk ?? 0n;
514
526
  const circuitVersion = input.circuitVersion ?? CURRENT_CIRCUIT_VERSION;
515
527
  const useStealth = input.viewingPublicKey !== void 0 && input.recipientOwnerPk !== void 0;
516
528
  let memo;
517
529
  if (useStealth) {
518
530
  const recipientOwnerPk = input.recipientOwnerPk;
519
531
  const recipientIvkPacked = input.viewingPublicKey;
520
- const ephSk = randomBytes3(32);
532
+ const ephSk = input.ephSkOverride ?? randomBytes3(32);
521
533
  const ivkPackedBigint = bytesToBigintLE(recipientIvkPacked);
522
534
  const ivkPoint = unpackPoint2(ivkPackedBigint);
523
535
  if (!ivkPoint)
@@ -545,7 +557,7 @@ var NoteBuilder = class {
545
557
  Number(assetId),
546
558
  stealthCommitmentBytes,
547
559
  recipientIvkPacked,
548
- bigintTo32Le(counterpartyPk),
560
+ bigintTo32Le(sourcePk),
549
561
  circuitVersion,
550
562
  ephSk
551
563
  )
@@ -587,7 +599,7 @@ var NoteBuilder = class {
587
599
  commitmentHex: toHex(commitmentBytes2),
588
600
  nullifierHex: toHex(nullifierBytes2),
589
601
  memo,
590
- counterpartyPk,
602
+ sourcePk,
591
603
  ...ovkBlob ? { ovkBlob } : {}
592
604
  };
593
605
  }
@@ -603,7 +615,7 @@ var NoteBuilder = class {
603
615
  Number(assetId),
604
616
  commitmentBytes,
605
617
  input.viewingPublicKey,
606
- bigintTo32Le(counterpartyPk),
618
+ bigintTo32Le(sourcePk),
607
619
  circuitVersion,
608
620
  input.ephSkOverride
609
621
  )
@@ -626,7 +638,7 @@ var NoteBuilder = class {
626
638
  commitmentHex: toHex(commitmentBytes),
627
639
  nullifierHex: toHex(nullifierBytes),
628
640
  memo,
629
- counterpartyPk
641
+ sourcePk
630
642
  };
631
643
  }
632
644
  /**
@@ -638,10 +650,10 @@ var NoteBuilder = class {
638
650
  * @param note The ZkNote whose fields populate the plaintext.
639
651
  * @param recipientIvkPacked 32-byte LE packed BJJ viewing public key of the recipient.
640
652
  * Pass `new Uint8Array(32)` (default) for a public/dummy memo.
641
- * @param counterpartyPk 32-byte counterparty BabyJubJub Ax.
653
+ * @param sourcePk 32-byte counterparty BabyJubJub Ax.
642
654
  * Pass `new Uint8Array(32)` (default) for no counterparty.
643
655
  */
644
- static buildMemo(note, recipientIvkPacked, counterpartyPk) {
656
+ static buildMemo(note, recipientIvkPacked, sourcePk) {
645
657
  return EncryptedMemo.encrypt(
646
658
  note.value,
647
659
  bigintTo32Le(note.ownerPk),
@@ -649,7 +661,7 @@ var NoteBuilder = class {
649
661
  Number(note.assetId),
650
662
  bigintTo32Le(note.commitment),
651
663
  recipientIvkPacked ?? new Uint8Array(32),
652
- counterpartyPk ?? bigintTo32Le(note.counterpartyPk ?? 0n),
664
+ sourcePk ?? bigintTo32Le(note.sourcePk ?? 0n),
653
665
  note.circuitVersion
654
666
  );
655
667
  }
@@ -808,7 +820,7 @@ function tryDecryptNoteVerbose(commitment, viewingSecretKey, spendingKey, ownOwn
808
820
  commitmentHex: toHex(bigintTo32Le(recomputed)),
809
821
  nullifierHex: toHex(bigintTo32Le(nullifier)),
810
822
  memo: Array.from(memoBytes),
811
- counterpartyPk: plaintext.counterpartyPk
823
+ sourcePk: plaintext.sourcePk
812
824
  }
813
825
  };
814
826
  }
@@ -842,10 +854,19 @@ function tryRecoverOutgoing(hint, ovk, opts) {
842
854
  assetId: plaintext.assetId,
843
855
  recipientStealthPk: plaintext.ownerPk,
844
856
  blinding: plaintext.blinding,
845
- counterpartyPk: plaintext.counterpartyPk,
857
+ sourcePk: plaintext.sourcePk,
846
858
  circuitVersion: plaintext.circuitVersion
847
859
  };
848
860
  }
861
+ function collectOutgoingFacts(hint) {
862
+ if (!isHexOfLength(hint.commitmentHex, 32)) return null;
863
+ if (!isHexOfLength(hint.encryptedMemo, ENCRYPTED_MEMO_SIZE)) return null;
864
+ return {
865
+ commitmentHex: hint.commitmentHex,
866
+ ...isValidLeafIndex(hint.leafIndex) ? { leafIndex: hint.leafIndex } : {},
867
+ encryptedMemo: hint.encryptedMemo
868
+ };
869
+ }
849
870
 
850
871
  // src/protocol/note/NoteDisclosure.ts
851
872
  import { poseidon4 as poseidon43 } from "poseidon-lite";
@@ -1300,6 +1321,7 @@ function createDecryptPool(options) {
1300
1321
  }
1301
1322
 
1302
1323
  export {
1324
+ isHexOfLength,
1303
1325
  toHex,
1304
1326
  fromHex,
1305
1327
  ensureHexPrefix,
@@ -1333,13 +1355,6 @@ export {
1333
1355
  sealOutgoingBlob,
1334
1356
  openOutgoingBlob,
1335
1357
  randomOutgoingBlob,
1336
- deriveSelfEphSk,
1337
- selfEphWindow,
1338
- derivePairwiseSharedSecret,
1339
- derivePairwiseEphSk,
1340
- pairwiseEphWindow,
1341
- CURRENT_CIRCUIT_VERSION,
1342
- NoteBuilder,
1343
1358
  LEAVES_PER_TREE,
1344
1359
  isValidLeafIndex,
1345
1360
  treeIdOf,
@@ -1347,12 +1362,20 @@ export {
1347
1362
  canPairWith,
1348
1363
  selectNotes,
1349
1364
  buildDummyTransferInput,
1365
+ deriveSelfEphSk,
1366
+ selfEphWindow,
1367
+ derivePairwiseSharedSecret,
1368
+ derivePairwiseEphSk,
1369
+ pairwiseEphWindow,
1370
+ CURRENT_CIRCUIT_VERSION,
1371
+ NoteBuilder,
1350
1372
  computeNullifier,
1351
1373
  commitmentHexOf,
1352
1374
  computeNoteCommitment,
1353
1375
  tryDecryptNote,
1354
1376
  tryDecryptNoteVerbose,
1355
1377
  tryRecoverOutgoing,
1378
+ collectOutgoingFacts,
1356
1379
  createNoteDisclosureKey,
1357
1380
  decodeNoteDisclosureKey,
1358
1381
  KEY_VERSION,
@@ -36,7 +36,7 @@ type DecryptedMemo = {
36
36
  /** Asset ID of the note. */
37
37
  assetId: bigint;
38
38
  /** Counterparty BabyJubJub Ax coordinate. Zero for shield/unshield notes. */
39
- counterpartyPk: bigint;
39
+ sourcePk: bigint;
40
40
  /** ZK circuit version the note is spent under, recovered from the memo plaintext. */
41
41
  circuitVersion: number;
42
42
  };
@@ -66,14 +66,21 @@ type NoteInput = {
66
66
  */
67
67
  recipientOwnerPk?: bigint;
68
68
  /** Counterparty BabyJubJub Ax coordinate. Zero for shield/unshield notes. Default 0n. */
69
- counterpartyPk?: bigint;
69
+ sourcePk?: bigint;
70
70
  /** Circuit version to stamp on the note. Defaults to `CURRENT_CIRCUIT_VERSION`. */
71
71
  circuitVersion?: number;
72
72
  /**
73
- * 32-byte ephemeral secret for the memo ECDH. Self-notes pass a
74
- * deterministic one (deriveSelfEphSk) so a cold restore recognizes them by
75
- * ephPk equality with no trial ECDH. Ignored on the stealth path (it
76
- * generates its own coordinated ephSk). Default: random.
73
+ * 32-byte ephemeral secret for the memo ECDH. Default: random.
74
+ *
75
+ * Two callers supply one, and both do it so the RECIPIENT can predict the
76
+ * published ephPk and match it by table lookup instead of one trial ECDH per
77
+ * pool hint: self-notes pass `deriveSelfEphSk`, and a payment to a known
78
+ * counterparty passes `derivePairwiseEphSk`.
79
+ *
80
+ * Honoured on the stealth path too, where the same ephSk drives both the
81
+ * memo encryption and the stealth-owner derivation. Passing one is a promise
82
+ * that the value is unique — reusing it republishes an ephPk and links the
83
+ * two notes in public.
77
84
  */
78
85
  ephSkOverride?: Uint8Array;
79
86
  /**
@@ -135,7 +142,7 @@ type ZkNote = {
135
142
  */
136
143
  memo: number[];
137
144
  /** Counterparty BabyJubJub Ax coordinate. Zero for shield/unshield notes. */
138
- counterpartyPk: bigint;
145
+ sourcePk: bigint;
139
146
  /**
140
147
  * 56-byte outgoing-viewing-key blob (per-note in the domain object; becomes a
141
148
  * per-transaction field at submit, see the OVK plan §4.1). Present only on a
@@ -166,10 +173,36 @@ type OutgoingNoteRecord = {
166
173
  * recomputes the commitment — needed to rebuild a payment slip for the note. */
167
174
  blinding: bigint;
168
175
  /** Counterparty BabyJubJub Ax coordinate stamped in the memo. */
169
- counterpartyPk: bigint;
176
+ sourcePk: bigint;
170
177
  /** Circuit version the sent note was created under. */
171
178
  circuitVersion: number;
172
179
  };
180
+ /**
181
+ * What a sender can still say about a note they sent, using only public data.
182
+ *
183
+ * No decryption and no key: the memo travels verbatim, exactly as published.
184
+ * The point is to FORWARD it to the recipient inside a fresh payment slip, not
185
+ * to read it — the recipient opens it with their own viewing key as always.
186
+ *
187
+ * That is what makes a slip recoverable after a lost device. What is NOT
188
+ * recoverable this way is the amount and the recipient, which live inside the
189
+ * sealed memo: a sender restoring from a seed alone gets working slips, not
190
+ * their outgoing history.
191
+ */
192
+ type NoteFacts = {
193
+ /** 0x-prefixed 32-byte LE commitment hex of the recipient output. */
194
+ commitmentHex: string;
195
+ /** Global Merkle leaf index, when known. */
196
+ leafIndex?: number;
197
+ /**
198
+ * The note's 180-byte encrypted memo, 0x-prefixed, exactly as published.
199
+ *
200
+ * Carried verbatim, never decrypted here — the sender has no key for it.
201
+ * Handing it back to the recipient inside a fresh slip is what re-issuing a
202
+ * slip means.
203
+ */
204
+ encryptedMemo: string;
205
+ };
173
206
 
174
207
  /**
175
208
  * What crosses the worker boundary.
@@ -390,4 +423,4 @@ declare function createMainThreadPool(): DecryptPool;
390
423
 
391
424
  declare function createWorkerPool(factory: WorkerFactory, size: number): DecryptPool;
392
425
 
393
- export { CURRENT_CIRCUIT_VERSION as C, type DecryptedMemo as D, EMPTY_BATCH_RESULT as E, type KnownEphEntry as K, MAX_WORKERS as M, type NoteInput as N, type OutgoingNoteRecord as O, PAIRWISE_EPH_WINDOW as P, type ScanCommitment as S, WORKER_CRASHED as W, type ZkNote as Z, type DecryptPool as a, type ScanKeys as b, DECRYPT_YIELD_EVERY as c, type DecryptBatchResult as d, type DecryptRequest as e, type KnownEphWindow as f, type MatchSource as g, type MerkleTreeInfo as h, SELF_EPH_WINDOW as i, type WorkerFactory as j, type WorkerLike as k, type WorkerMessage as l, clearKnownEphWindow as m, createDecryptPool as n, createMainThreadPool as o, createWorkerPool as p, decryptHintBatch as q, getKnownEphWindow as r };
426
+ export { CURRENT_CIRCUIT_VERSION as C, type DecryptedMemo as D, EMPTY_BATCH_RESULT as E, type KnownEphEntry as K, MAX_WORKERS as M, type NoteInput as N, type OutgoingNoteRecord as O, PAIRWISE_EPH_WINDOW as P, type ScanCommitment as S, WORKER_CRASHED as W, type ZkNote as Z, type NoteFacts as a, type DecryptPool as b, type ScanKeys as c, DECRYPT_YIELD_EVERY as d, type DecryptBatchResult as e, type DecryptRequest as f, type KnownEphWindow as g, type MatchSource as h, type MerkleTreeInfo as i, SELF_EPH_WINDOW as j, type WorkerFactory as k, type WorkerLike as l, type WorkerMessage as m, clearKnownEphWindow as n, createDecryptPool as o, createMainThreadPool as p, createWorkerPool as q, decryptHintBatch as r, getKnownEphWindow as s };
@@ -36,7 +36,7 @@ type DecryptedMemo = {
36
36
  /** Asset ID of the note. */
37
37
  assetId: bigint;
38
38
  /** Counterparty BabyJubJub Ax coordinate. Zero for shield/unshield notes. */
39
- counterpartyPk: bigint;
39
+ sourcePk: bigint;
40
40
  /** ZK circuit version the note is spent under, recovered from the memo plaintext. */
41
41
  circuitVersion: number;
42
42
  };
@@ -66,14 +66,21 @@ type NoteInput = {
66
66
  */
67
67
  recipientOwnerPk?: bigint;
68
68
  /** Counterparty BabyJubJub Ax coordinate. Zero for shield/unshield notes. Default 0n. */
69
- counterpartyPk?: bigint;
69
+ sourcePk?: bigint;
70
70
  /** Circuit version to stamp on the note. Defaults to `CURRENT_CIRCUIT_VERSION`. */
71
71
  circuitVersion?: number;
72
72
  /**
73
- * 32-byte ephemeral secret for the memo ECDH. Self-notes pass a
74
- * deterministic one (deriveSelfEphSk) so a cold restore recognizes them by
75
- * ephPk equality with no trial ECDH. Ignored on the stealth path (it
76
- * generates its own coordinated ephSk). Default: random.
73
+ * 32-byte ephemeral secret for the memo ECDH. Default: random.
74
+ *
75
+ * Two callers supply one, and both do it so the RECIPIENT can predict the
76
+ * published ephPk and match it by table lookup instead of one trial ECDH per
77
+ * pool hint: self-notes pass `deriveSelfEphSk`, and a payment to a known
78
+ * counterparty passes `derivePairwiseEphSk`.
79
+ *
80
+ * Honoured on the stealth path too, where the same ephSk drives both the
81
+ * memo encryption and the stealth-owner derivation. Passing one is a promise
82
+ * that the value is unique — reusing it republishes an ephPk and links the
83
+ * two notes in public.
77
84
  */
78
85
  ephSkOverride?: Uint8Array;
79
86
  /**
@@ -135,7 +142,7 @@ type ZkNote = {
135
142
  */
136
143
  memo: number[];
137
144
  /** Counterparty BabyJubJub Ax coordinate. Zero for shield/unshield notes. */
138
- counterpartyPk: bigint;
145
+ sourcePk: bigint;
139
146
  /**
140
147
  * 56-byte outgoing-viewing-key blob (per-note in the domain object; becomes a
141
148
  * per-transaction field at submit, see the OVK plan §4.1). Present only on a
@@ -166,10 +173,36 @@ type OutgoingNoteRecord = {
166
173
  * recomputes the commitment — needed to rebuild a payment slip for the note. */
167
174
  blinding: bigint;
168
175
  /** Counterparty BabyJubJub Ax coordinate stamped in the memo. */
169
- counterpartyPk: bigint;
176
+ sourcePk: bigint;
170
177
  /** Circuit version the sent note was created under. */
171
178
  circuitVersion: number;
172
179
  };
180
+ /**
181
+ * What a sender can still say about a note they sent, using only public data.
182
+ *
183
+ * No decryption and no key: the memo travels verbatim, exactly as published.
184
+ * The point is to FORWARD it to the recipient inside a fresh payment slip, not
185
+ * to read it — the recipient opens it with their own viewing key as always.
186
+ *
187
+ * That is what makes a slip recoverable after a lost device. What is NOT
188
+ * recoverable this way is the amount and the recipient, which live inside the
189
+ * sealed memo: a sender restoring from a seed alone gets working slips, not
190
+ * their outgoing history.
191
+ */
192
+ type NoteFacts = {
193
+ /** 0x-prefixed 32-byte LE commitment hex of the recipient output. */
194
+ commitmentHex: string;
195
+ /** Global Merkle leaf index, when known. */
196
+ leafIndex?: number;
197
+ /**
198
+ * The note's 180-byte encrypted memo, 0x-prefixed, exactly as published.
199
+ *
200
+ * Carried verbatim, never decrypted here — the sender has no key for it.
201
+ * Handing it back to the recipient inside a fresh slip is what re-issuing a
202
+ * slip means.
203
+ */
204
+ encryptedMemo: string;
205
+ };
173
206
 
174
207
  /**
175
208
  * What crosses the worker boundary.
@@ -390,4 +423,4 @@ declare function createMainThreadPool(): DecryptPool;
390
423
 
391
424
  declare function createWorkerPool(factory: WorkerFactory, size: number): DecryptPool;
392
425
 
393
- export { CURRENT_CIRCUIT_VERSION as C, type DecryptedMemo as D, EMPTY_BATCH_RESULT as E, type KnownEphEntry as K, MAX_WORKERS as M, type NoteInput as N, type OutgoingNoteRecord as O, PAIRWISE_EPH_WINDOW as P, type ScanCommitment as S, WORKER_CRASHED as W, type ZkNote as Z, type DecryptPool as a, type ScanKeys as b, DECRYPT_YIELD_EVERY as c, type DecryptBatchResult as d, type DecryptRequest as e, type KnownEphWindow as f, type MatchSource as g, type MerkleTreeInfo as h, SELF_EPH_WINDOW as i, type WorkerFactory as j, type WorkerLike as k, type WorkerMessage as l, clearKnownEphWindow as m, createDecryptPool as n, createMainThreadPool as o, createWorkerPool as p, decryptHintBatch as q, getKnownEphWindow as r };
426
+ export { CURRENT_CIRCUIT_VERSION as C, type DecryptedMemo as D, EMPTY_BATCH_RESULT as E, type KnownEphEntry as K, MAX_WORKERS as M, type NoteInput as N, type OutgoingNoteRecord as O, PAIRWISE_EPH_WINDOW as P, type ScanCommitment as S, WORKER_CRASHED as W, type ZkNote as Z, type NoteFacts as a, type DecryptPool as b, type ScanKeys as c, DECRYPT_YIELD_EVERY as d, type DecryptBatchResult as e, type DecryptRequest as f, type KnownEphWindow as g, type MatchSource as h, type MerkleTreeInfo as i, SELF_EPH_WINDOW as j, type WorkerFactory as k, type WorkerLike as l, type WorkerMessage as m, clearKnownEphWindow as n, createDecryptPool as o, createMainThreadPool as p, createWorkerPool as q, decryptHintBatch as r, getKnownEphWindow as s };