@orbinum/sdk 1.3.1 → 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.
- package/dist/{chunk-A2ZRMEYW.mjs → chunk-VYKKBXOE.mjs} +51 -28
- package/dist/{index-V5Z9igEN.d.mts → index-CLpM1984.d.mts} +42 -9
- package/dist/{index-V5Z9igEN.d.ts → index-CLpM1984.d.ts} +42 -9
- package/dist/index.d.mts +399 -105
- package/dist/index.d.ts +399 -105
- package/dist/index.js +595 -338
- package/dist/index.mjs +487 -257
- package/dist/wallet/worker/index.d.mts +1 -1
- package/dist/wallet/worker/index.d.ts +1 -1
- package/dist/wallet/worker/index.js +18 -11
- package/dist/wallet/worker/index.mjs +1 -1
- package/package.json +1 -1
|
@@ -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
|
-
|
|
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,
|
|
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(
|
|
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
|
|
180
|
+
const sourcePk = bytesToBigintLE(plaintext.slice(84, 116));
|
|
169
181
|
const circuitVersion = view.getUint32(116, true);
|
|
170
|
-
return { value, ownerPk, blinding, assetId,
|
|
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
|
|
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,
|
|
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
|
-
|
|
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
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 };
|