@orbinum/sdk 1.1.1 → 1.2.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-Y6LNYJAJ.mjs → chunk-A2ZRMEYW.mjs} +147 -13
- package/dist/{index-JYVjYJtf.d.mts → index-V5Z9igEN.d.mts} +41 -1
- package/dist/{index-JYVjYJtf.d.ts → index-V5Z9igEN.d.ts} +41 -1
- package/dist/index.d.mts +207 -4
- package/dist/index.d.ts +207 -4
- package/dist/index.js +323 -33
- package/dist/index.mjs +169 -12
- package/dist/wallet/worker/index.d.mts +1 -1
- package/dist/wallet/worker/index.d.ts +1 -1
- package/dist/wallet/worker/index.js +1 -0
- package/dist/wallet/worker/index.mjs +1 -1
- package/package.json +1 -1
|
@@ -342,14 +342,75 @@ var EncryptedMemo = {
|
|
|
342
342
|
}
|
|
343
343
|
};
|
|
344
344
|
|
|
345
|
-
// src/
|
|
346
|
-
import {
|
|
345
|
+
// src/protocol/memo/OutgoingBlob.ts
|
|
346
|
+
import { chacha20poly1305 as chacha20poly13052 } from "@noble/ciphers/chacha.js";
|
|
347
|
+
import { randomBytes as randomBytes2 } from "@noble/ciphers/utils.js";
|
|
347
348
|
import { hkdf } from "@noble/hashes/hkdf.js";
|
|
349
|
+
import { sha256 as sha2562 } from "@noble/hashes/sha2.js";
|
|
350
|
+
var OCK_DOMAIN = new TextEncoder().encode("orbinum-outgoing-cipher-v1");
|
|
351
|
+
var NONCE_PREFIX = new TextEncoder().encode("OVK1");
|
|
352
|
+
var NONCE_SUFFIX_SIZE = 8;
|
|
353
|
+
var SHARED_SECRET_SIZE = 32;
|
|
354
|
+
var MAC_SIZE = 16;
|
|
355
|
+
var OVK_BLOB_SIZE = NONCE_SUFFIX_SIZE + SHARED_SECRET_SIZE + MAC_SIZE;
|
|
356
|
+
function deriveOutgoingCipherKey(ovk, commitmentBytes, ephPkBytes) {
|
|
357
|
+
if (commitmentBytes.length !== 32) {
|
|
358
|
+
throw new Error(
|
|
359
|
+
`OutgoingBlob: commitmentBytes must be 32 bytes, got ${commitmentBytes.length}`
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
if (ephPkBytes.length !== 32) {
|
|
363
|
+
throw new Error(`OutgoingBlob: ephPkBytes must be 32 bytes, got ${ephPkBytes.length}`);
|
|
364
|
+
}
|
|
365
|
+
const salt = new Uint8Array(64);
|
|
366
|
+
salt.set(commitmentBytes, 0);
|
|
367
|
+
salt.set(ephPkBytes, 32);
|
|
368
|
+
return hkdf(sha2562, ovk, salt, OCK_DOMAIN, 32);
|
|
369
|
+
}
|
|
370
|
+
function buildNonce(suffix) {
|
|
371
|
+
const nonce = new Uint8Array(12);
|
|
372
|
+
nonce.set(NONCE_PREFIX, 0);
|
|
373
|
+
nonce.set(suffix, 4);
|
|
374
|
+
return nonce;
|
|
375
|
+
}
|
|
376
|
+
function sealOutgoingBlob(ovk, sharedSecret, commitmentBytes, ephPkBytes) {
|
|
377
|
+
if (sharedSecret.length !== SHARED_SECRET_SIZE) {
|
|
378
|
+
throw new Error(`OutgoingBlob: sharedSecret must be 32 bytes, got ${sharedSecret.length}`);
|
|
379
|
+
}
|
|
380
|
+
const ock = deriveOutgoingCipherKey(ovk, commitmentBytes, ephPkBytes);
|
|
381
|
+
const suffix = randomBytes2(NONCE_SUFFIX_SIZE);
|
|
382
|
+
const cipher = chacha20poly13052(ock, buildNonce(suffix));
|
|
383
|
+
const sealed = cipher.encrypt(sharedSecret);
|
|
384
|
+
const blob = new Uint8Array(OVK_BLOB_SIZE);
|
|
385
|
+
blob.set(suffix, 0);
|
|
386
|
+
blob.set(sealed, NONCE_SUFFIX_SIZE);
|
|
387
|
+
return blob;
|
|
388
|
+
}
|
|
389
|
+
function openOutgoingBlob(ovk, blob, commitmentBytes, ephPkBytes) {
|
|
390
|
+
if (blob.length !== OVK_BLOB_SIZE) return null;
|
|
391
|
+
if (commitmentBytes.length !== 32 || ephPkBytes.length !== 32) return null;
|
|
392
|
+
try {
|
|
393
|
+
const ock = deriveOutgoingCipherKey(ovk, commitmentBytes, ephPkBytes);
|
|
394
|
+
const suffix = blob.subarray(0, NONCE_SUFFIX_SIZE);
|
|
395
|
+
const sealed = blob.subarray(NONCE_SUFFIX_SIZE);
|
|
396
|
+
const cipher = chacha20poly13052(ock, buildNonce(suffix));
|
|
397
|
+
return cipher.decrypt(sealed);
|
|
398
|
+
} catch {
|
|
399
|
+
return null;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
function randomOutgoingBlob() {
|
|
403
|
+
return randomBytes2(OVK_BLOB_SIZE);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// src/foundation/crypto/stealth.ts
|
|
407
|
+
import { sha256 as sha2563 } from "@noble/hashes/sha2.js";
|
|
408
|
+
import { hkdf as hkdf2 } from "@noble/hashes/hkdf.js";
|
|
348
409
|
import { mulPointEscalar, Base8, addPoint } from "@zk-kit/baby-jubjub";
|
|
349
410
|
var STEALTH_INFO = new TextEncoder().encode("orbinum-stealth-v1");
|
|
350
411
|
function deriveStealthScalar(sharedSecret, ownerPkBigint) {
|
|
351
412
|
const salt = bigintTo32Le(ownerPkBigint);
|
|
352
|
-
const stealthBytes =
|
|
413
|
+
const stealthBytes = hkdf2(sha2563, sharedSecret, salt, STEALTH_INFO, 32);
|
|
353
414
|
return bytesToBigintLE(stealthBytes) % BABYJUB_SUBORDER || 1n;
|
|
354
415
|
}
|
|
355
416
|
function deriveStealthOwnerPk(sharedSecret, ownerPkBigint, ownerPkPoint) {
|
|
@@ -427,7 +488,7 @@ function recoverOwnerPkPoint(ax) {
|
|
|
427
488
|
|
|
428
489
|
// src/protocol/note/NoteBuilder.ts
|
|
429
490
|
import { mulPointEscalar as mulPointEscalar3, unpackPoint as unpackPoint2 } from "@zk-kit/baby-jubjub";
|
|
430
|
-
import { randomBytes as
|
|
491
|
+
import { randomBytes as randomBytes3 } from "@noble/ciphers/utils.js";
|
|
431
492
|
import { poseidon2, poseidon4 } from "poseidon-lite";
|
|
432
493
|
var NoteBuilder = class {
|
|
433
494
|
/**
|
|
@@ -456,7 +517,7 @@ var NoteBuilder = class {
|
|
|
456
517
|
if (useStealth) {
|
|
457
518
|
const recipientOwnerPk = input.recipientOwnerPk;
|
|
458
519
|
const recipientIvkPacked = input.viewingPublicKey;
|
|
459
|
-
const ephSk =
|
|
520
|
+
const ephSk = randomBytes3(32);
|
|
460
521
|
const ivkPackedBigint = bytesToBigintLE(recipientIvkPacked);
|
|
461
522
|
const ivkPoint = unpackPoint2(ivkPackedBigint);
|
|
462
523
|
if (!ivkPoint)
|
|
@@ -497,6 +558,21 @@ var NoteBuilder = class {
|
|
|
497
558
|
throw new Error(
|
|
498
559
|
`NoteBuilder.build: invariant violated \u2014 memo must be ${ENCRYPTED_MEMO_SIZE} bytes, got ${memo.length}`
|
|
499
560
|
);
|
|
561
|
+
let ovkBlob;
|
|
562
|
+
if (input.outgoingViewingKey !== void 0) {
|
|
563
|
+
const ephPkBytes = Uint8Array.from(memo.slice(148, 180));
|
|
564
|
+
const sealed = sealOutgoingBlob(
|
|
565
|
+
input.outgoingViewingKey,
|
|
566
|
+
sharedSecret,
|
|
567
|
+
stealthCommitmentBytes,
|
|
568
|
+
ephPkBytes
|
|
569
|
+
);
|
|
570
|
+
if (sealed.length !== OVK_BLOB_SIZE)
|
|
571
|
+
throw new Error(
|
|
572
|
+
`NoteBuilder.build: invariant violated \u2014 ovkBlob must be ${OVK_BLOB_SIZE} bytes, got ${sealed.length}`
|
|
573
|
+
);
|
|
574
|
+
ovkBlob = Array.from(sealed);
|
|
575
|
+
}
|
|
500
576
|
return {
|
|
501
577
|
value,
|
|
502
578
|
assetId,
|
|
@@ -511,7 +587,8 @@ var NoteBuilder = class {
|
|
|
511
587
|
commitmentHex: toHex(commitmentBytes2),
|
|
512
588
|
nullifierHex: toHex(nullifierBytes2),
|
|
513
589
|
memo,
|
|
514
|
-
counterpartyPk
|
|
590
|
+
counterpartyPk,
|
|
591
|
+
...ovkBlob ? { ovkBlob } : {}
|
|
515
592
|
};
|
|
516
593
|
}
|
|
517
594
|
const commitment = poseidon4([value, assetId, ownerPk, blinding]);
|
|
@@ -641,6 +718,18 @@ function buildDummyTransferInput(assetId) {
|
|
|
641
718
|
}
|
|
642
719
|
|
|
643
720
|
// src/protocol/note/NoteDecryptor.ts
|
|
721
|
+
function decryptAndVerifyPlaintext(memoBytes, commitmentBytes, sharedSecret, effectiveOwnerPk) {
|
|
722
|
+
const plaintext = EncryptedMemo.decryptWithSharedSecret(
|
|
723
|
+
memoBytes,
|
|
724
|
+
commitmentBytes,
|
|
725
|
+
sharedSecret
|
|
726
|
+
);
|
|
727
|
+
if (!plaintext) return null;
|
|
728
|
+
const ownerPk = effectiveOwnerPk ?? plaintext.ownerPk;
|
|
729
|
+
const recomputed = poseidon42([plaintext.value, plaintext.assetId, ownerPk, plaintext.blinding]);
|
|
730
|
+
if (recomputed !== bytesToBigintLE(commitmentBytes)) return null;
|
|
731
|
+
return plaintext;
|
|
732
|
+
}
|
|
644
733
|
function computeNullifier(commitment, spendingKey) {
|
|
645
734
|
return poseidon22([commitment, spendingKey]);
|
|
646
735
|
}
|
|
@@ -723,6 +812,40 @@ function tryDecryptNoteVerbose(commitment, viewingSecretKey, spendingKey, ownOwn
|
|
|
723
812
|
}
|
|
724
813
|
};
|
|
725
814
|
}
|
|
815
|
+
function tryRecoverOutgoing(hint, ovk, opts) {
|
|
816
|
+
if (!hint.ovkBlob || !hint.encryptedMemo) return null;
|
|
817
|
+
let commitmentBytes;
|
|
818
|
+
let memoBytes;
|
|
819
|
+
let blobBytes;
|
|
820
|
+
try {
|
|
821
|
+
commitmentBytes = fromHex(hint.commitmentHex);
|
|
822
|
+
memoBytes = fromHex(hint.encryptedMemo);
|
|
823
|
+
blobBytes = fromHex(hint.ovkBlob);
|
|
824
|
+
} catch {
|
|
825
|
+
return null;
|
|
826
|
+
}
|
|
827
|
+
if (memoBytes.length !== ENCRYPTED_MEMO_SIZE) return null;
|
|
828
|
+
if (blobBytes.length !== OVK_BLOB_SIZE) return null;
|
|
829
|
+
const ephPkBytes = memoBytes.subarray(148, 180);
|
|
830
|
+
const sharedSecret = openOutgoingBlob(ovk, blobBytes, commitmentBytes, ephPkBytes);
|
|
831
|
+
if (!sharedSecret) return null;
|
|
832
|
+
const activation = opts?.viewTagActivationLeaf;
|
|
833
|
+
if (activation !== void 0 && isValidLeafIndex(hint.leafIndex) && hint.leafIndex >= activation && !EncryptedMemo.checkViewTag(memoBytes, sharedSecret)) {
|
|
834
|
+
return null;
|
|
835
|
+
}
|
|
836
|
+
const plaintext = decryptAndVerifyPlaintext(memoBytes, commitmentBytes, sharedSecret, null);
|
|
837
|
+
if (!plaintext) return null;
|
|
838
|
+
return {
|
|
839
|
+
commitmentHex: hint.commitmentHex,
|
|
840
|
+
...isValidLeafIndex(hint.leafIndex) ? { leafIndex: hint.leafIndex } : {},
|
|
841
|
+
value: plaintext.value,
|
|
842
|
+
assetId: plaintext.assetId,
|
|
843
|
+
recipientStealthPk: plaintext.ownerPk,
|
|
844
|
+
blinding: plaintext.blinding,
|
|
845
|
+
counterpartyPk: plaintext.counterpartyPk,
|
|
846
|
+
circuitVersion: plaintext.circuitVersion
|
|
847
|
+
};
|
|
848
|
+
}
|
|
726
849
|
|
|
727
850
|
// src/protocol/note/NoteDisclosure.ts
|
|
728
851
|
import { poseidon4 as poseidon43 } from "poseidon-lite";
|
|
@@ -809,11 +932,11 @@ function decodeNoteDisclosureKey(key) {
|
|
|
809
932
|
}
|
|
810
933
|
|
|
811
934
|
// src/protocol/eph/selfEph.ts
|
|
812
|
-
import { sha256 as
|
|
935
|
+
import { sha256 as sha2564 } from "@noble/hashes/sha2.js";
|
|
813
936
|
import { packPoint as packPoint2, unpackPoint as unpackPoint3 } from "@zk-kit/baby-jubjub";
|
|
814
937
|
var SELF_EPH_DOMAIN = new TextEncoder().encode("orbinum-self-eph-v1");
|
|
815
938
|
function deriveSelfEphSk(spendingKey, index) {
|
|
816
|
-
const h =
|
|
939
|
+
const h = sha2564.create();
|
|
817
940
|
h.update(SELF_EPH_DOMAIN);
|
|
818
941
|
h.update(bigintTo32Le(spendingKey));
|
|
819
942
|
const idx = new Uint8Array(4);
|
|
@@ -839,7 +962,7 @@ function selfEphWindow(spendingKey, ivkPacked, from, count) {
|
|
|
839
962
|
}
|
|
840
963
|
|
|
841
964
|
// src/protocol/eph/pairwiseEph.ts
|
|
842
|
-
import { sha256 as
|
|
965
|
+
import { sha256 as sha2565 } from "@noble/hashes/sha2.js";
|
|
843
966
|
import { packPoint as packPoint3, unpackPoint as unpackPoint4 } from "@zk-kit/baby-jubjub";
|
|
844
967
|
var PAIRWISE_EPH_DOMAIN = new TextEncoder().encode("orbinum-pairwise-eph-v1");
|
|
845
968
|
function derivePairwiseSharedSecret(myViewingSk, theirIvkPacked) {
|
|
@@ -849,7 +972,7 @@ function derivePairwiseSharedSecret(myViewingSk, theirIvkPacked) {
|
|
|
849
972
|
return bigintTo32Le(shared[0]);
|
|
850
973
|
}
|
|
851
974
|
function derivePairwiseEphSk(pairSecret, index) {
|
|
852
|
-
const h =
|
|
975
|
+
const h = sha2565.create();
|
|
853
976
|
h.update(PAIRWISE_EPH_DOMAIN);
|
|
854
977
|
h.update(pairSecret);
|
|
855
978
|
const idx = new Uint8Array(4);
|
|
@@ -875,10 +998,11 @@ function pairwiseEphWindow(pairSecret, receiverIvkPacked, from, count) {
|
|
|
875
998
|
}
|
|
876
999
|
|
|
877
1000
|
// src/protocol/keys/PrivacyKeys.ts
|
|
878
|
-
import { hkdf as
|
|
879
|
-
import { sha256 as
|
|
1001
|
+
import { hkdf as hkdf3 } from "@noble/hashes/hkdf.js";
|
|
1002
|
+
import { sha256 as sha2566 } from "@noble/hashes/sha2.js";
|
|
880
1003
|
import { packPoint as packPoint4 } from "@zk-kit/baby-jubjub";
|
|
881
1004
|
var IVK_DOMAIN = new TextEncoder().encode("orbinum-ivk-v1");
|
|
1005
|
+
var OVK_DOMAIN = new TextEncoder().encode("orbinum-ovk-v1");
|
|
882
1006
|
var KEY_VERSION = "v2";
|
|
883
1007
|
function deriveSpendingKeyFromMaster(masterBytes) {
|
|
884
1008
|
const skBigint = BigInt(toHex(masterBytes)) % BABYJUB_SUBORDER;
|
|
@@ -886,7 +1010,7 @@ function deriveSpendingKeyFromMaster(masterBytes) {
|
|
|
886
1010
|
}
|
|
887
1011
|
function deriveViewingSecretKey(spendingKey) {
|
|
888
1012
|
const ikm = bigintTo32Le(spendingKey);
|
|
889
|
-
return
|
|
1013
|
+
return hkdf3(sha2566, ikm, void 0, IVK_DOMAIN, 32);
|
|
890
1014
|
}
|
|
891
1015
|
function deriveViewingPublicKey(ivsk) {
|
|
892
1016
|
const ivskScalar = BigInt(toHex(ivsk)) % BABYJUB_SUBORDER || 1n;
|
|
@@ -902,6 +1026,9 @@ function deriveOwnerPk(spendingKey) {
|
|
|
902
1026
|
return 0n;
|
|
903
1027
|
}
|
|
904
1028
|
}
|
|
1029
|
+
function deriveOutgoingViewingKey(masterBytes) {
|
|
1030
|
+
return hkdf3(sha2566, masterBytes, void 0, OVK_DOMAIN, 32);
|
|
1031
|
+
}
|
|
905
1032
|
|
|
906
1033
|
// src/wallet/worker/kernel/types.ts
|
|
907
1034
|
var SELF_EPH_WINDOW = 1024;
|
|
@@ -1201,6 +1328,11 @@ export {
|
|
|
1201
1328
|
ENCRYPTED_MEMO_SIZE,
|
|
1202
1329
|
bytesToBjjScalar,
|
|
1203
1330
|
EncryptedMemo,
|
|
1331
|
+
OVK_BLOB_SIZE,
|
|
1332
|
+
deriveOutgoingCipherKey,
|
|
1333
|
+
sealOutgoingBlob,
|
|
1334
|
+
openOutgoingBlob,
|
|
1335
|
+
randomOutgoingBlob,
|
|
1204
1336
|
deriveSelfEphSk,
|
|
1205
1337
|
selfEphWindow,
|
|
1206
1338
|
derivePairwiseSharedSecret,
|
|
@@ -1220,6 +1352,7 @@ export {
|
|
|
1220
1352
|
computeNoteCommitment,
|
|
1221
1353
|
tryDecryptNote,
|
|
1222
1354
|
tryDecryptNoteVerbose,
|
|
1355
|
+
tryRecoverOutgoing,
|
|
1223
1356
|
createNoteDisclosureKey,
|
|
1224
1357
|
decodeNoteDisclosureKey,
|
|
1225
1358
|
KEY_VERSION,
|
|
@@ -1227,6 +1360,7 @@ export {
|
|
|
1227
1360
|
deriveViewingSecretKey,
|
|
1228
1361
|
deriveViewingPublicKey,
|
|
1229
1362
|
deriveOwnerPk,
|
|
1363
|
+
deriveOutgoingViewingKey,
|
|
1230
1364
|
SELF_EPH_WINDOW,
|
|
1231
1365
|
PAIRWISE_EPH_WINDOW,
|
|
1232
1366
|
EMPTY_BATCH_RESULT,
|
|
@@ -76,6 +76,13 @@ type NoteInput = {
|
|
|
76
76
|
* generates its own coordinated ephSk). Default: random.
|
|
77
77
|
*/
|
|
78
78
|
ephSkOverride?: Uint8Array;
|
|
79
|
+
/**
|
|
80
|
+
* Sender's 32-byte outgoing viewing key (ovk). When present on the stealth
|
|
81
|
+
* path, `build()` seals the memo's shared secret into a 56-byte `ovkBlob` so
|
|
82
|
+
* the sender can recover this transfer after a cold restore. Absent → no blob
|
|
83
|
+
* (the app applies the ⊥ default at submit time, never the SDK).
|
|
84
|
+
*/
|
|
85
|
+
outgoingViewingKey?: Uint8Array;
|
|
79
86
|
};
|
|
80
87
|
/**
|
|
81
88
|
* Circuit version notes are created under today. A note carries its version
|
|
@@ -129,6 +136,39 @@ type ZkNote = {
|
|
|
129
136
|
memo: number[];
|
|
130
137
|
/** Counterparty BabyJubJub Ax coordinate. Zero for shield/unshield notes. */
|
|
131
138
|
counterpartyPk: bigint;
|
|
139
|
+
/**
|
|
140
|
+
* 56-byte outgoing-viewing-key blob (per-note in the domain object; becomes a
|
|
141
|
+
* per-transaction field at submit, see the OVK plan §4.1). Present only on a
|
|
142
|
+
* stealth recipient note built with an `outgoingViewingKey`. It wraps the
|
|
143
|
+
* memo's shared secret under the sender's ovk so the sender can recover the
|
|
144
|
+
* transfer; the recipient never needs it. Not persisted in the vault.
|
|
145
|
+
*/
|
|
146
|
+
ovkBlob?: number[];
|
|
147
|
+
};
|
|
148
|
+
/**
|
|
149
|
+
* A sender's record of a note they SENT, recovered via the OVK blob. Not a
|
|
150
|
+
* spendable note: it deliberately carries no `spendingKey`, no `nullifier`, no
|
|
151
|
+
* `spent` flag — the sender does not own the recipient's note, only the memory of
|
|
152
|
+
* having sent it. Used to rebuild the outgoing history after a cold restore.
|
|
153
|
+
*/
|
|
154
|
+
type OutgoingNoteRecord = {
|
|
155
|
+
/** 0x-prefixed 32-byte LE commitment hex of the recipient output. */
|
|
156
|
+
commitmentHex: string;
|
|
157
|
+
/** Global Merkle leaf index, when the hint carried one. */
|
|
158
|
+
leafIndex?: number;
|
|
159
|
+
/** Amount sent, in planck. */
|
|
160
|
+
value: bigint;
|
|
161
|
+
/** Asset ID of the sent note. */
|
|
162
|
+
assetId: bigint;
|
|
163
|
+
/** The recipient's one-time stealth owner public key (BJJ Ax). */
|
|
164
|
+
recipientStealthPk: bigint;
|
|
165
|
+
/** Blinding scalar of the recipient output. With value/assetId/stealthPk it
|
|
166
|
+
* recomputes the commitment — needed to rebuild a payment slip for the note. */
|
|
167
|
+
blinding: bigint;
|
|
168
|
+
/** Counterparty BabyJubJub Ax coordinate stamped in the memo. */
|
|
169
|
+
counterpartyPk: bigint;
|
|
170
|
+
/** Circuit version the sent note was created under. */
|
|
171
|
+
circuitVersion: number;
|
|
132
172
|
};
|
|
133
173
|
|
|
134
174
|
/**
|
|
@@ -350,4 +390,4 @@ declare function createMainThreadPool(): DecryptPool;
|
|
|
350
390
|
|
|
351
391
|
declare function createWorkerPool(factory: WorkerFactory, size: number): DecryptPool;
|
|
352
392
|
|
|
353
|
-
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, 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 };
|
|
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 };
|
|
@@ -76,6 +76,13 @@ type NoteInput = {
|
|
|
76
76
|
* generates its own coordinated ephSk). Default: random.
|
|
77
77
|
*/
|
|
78
78
|
ephSkOverride?: Uint8Array;
|
|
79
|
+
/**
|
|
80
|
+
* Sender's 32-byte outgoing viewing key (ovk). When present on the stealth
|
|
81
|
+
* path, `build()` seals the memo's shared secret into a 56-byte `ovkBlob` so
|
|
82
|
+
* the sender can recover this transfer after a cold restore. Absent → no blob
|
|
83
|
+
* (the app applies the ⊥ default at submit time, never the SDK).
|
|
84
|
+
*/
|
|
85
|
+
outgoingViewingKey?: Uint8Array;
|
|
79
86
|
};
|
|
80
87
|
/**
|
|
81
88
|
* Circuit version notes are created under today. A note carries its version
|
|
@@ -129,6 +136,39 @@ type ZkNote = {
|
|
|
129
136
|
memo: number[];
|
|
130
137
|
/** Counterparty BabyJubJub Ax coordinate. Zero for shield/unshield notes. */
|
|
131
138
|
counterpartyPk: bigint;
|
|
139
|
+
/**
|
|
140
|
+
* 56-byte outgoing-viewing-key blob (per-note in the domain object; becomes a
|
|
141
|
+
* per-transaction field at submit, see the OVK plan §4.1). Present only on a
|
|
142
|
+
* stealth recipient note built with an `outgoingViewingKey`. It wraps the
|
|
143
|
+
* memo's shared secret under the sender's ovk so the sender can recover the
|
|
144
|
+
* transfer; the recipient never needs it. Not persisted in the vault.
|
|
145
|
+
*/
|
|
146
|
+
ovkBlob?: number[];
|
|
147
|
+
};
|
|
148
|
+
/**
|
|
149
|
+
* A sender's record of a note they SENT, recovered via the OVK blob. Not a
|
|
150
|
+
* spendable note: it deliberately carries no `spendingKey`, no `nullifier`, no
|
|
151
|
+
* `spent` flag — the sender does not own the recipient's note, only the memory of
|
|
152
|
+
* having sent it. Used to rebuild the outgoing history after a cold restore.
|
|
153
|
+
*/
|
|
154
|
+
type OutgoingNoteRecord = {
|
|
155
|
+
/** 0x-prefixed 32-byte LE commitment hex of the recipient output. */
|
|
156
|
+
commitmentHex: string;
|
|
157
|
+
/** Global Merkle leaf index, when the hint carried one. */
|
|
158
|
+
leafIndex?: number;
|
|
159
|
+
/** Amount sent, in planck. */
|
|
160
|
+
value: bigint;
|
|
161
|
+
/** Asset ID of the sent note. */
|
|
162
|
+
assetId: bigint;
|
|
163
|
+
/** The recipient's one-time stealth owner public key (BJJ Ax). */
|
|
164
|
+
recipientStealthPk: bigint;
|
|
165
|
+
/** Blinding scalar of the recipient output. With value/assetId/stealthPk it
|
|
166
|
+
* recomputes the commitment — needed to rebuild a payment slip for the note. */
|
|
167
|
+
blinding: bigint;
|
|
168
|
+
/** Counterparty BabyJubJub Ax coordinate stamped in the memo. */
|
|
169
|
+
counterpartyPk: bigint;
|
|
170
|
+
/** Circuit version the sent note was created under. */
|
|
171
|
+
circuitVersion: number;
|
|
132
172
|
};
|
|
133
173
|
|
|
134
174
|
/**
|
|
@@ -350,4 +390,4 @@ declare function createMainThreadPool(): DecryptPool;
|
|
|
350
390
|
|
|
351
391
|
declare function createWorkerPool(factory: WorkerFactory, size: number): DecryptPool;
|
|
352
392
|
|
|
353
|
-
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, 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 };
|
|
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 };
|