@orbinum/sdk 1.0.0 → 1.0.1
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/index.d.mts +12 -4
- package/dist/index.d.ts +12 -4
- package/dist/index.js +36 -13
- package/dist/index.mjs +36 -13
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -1809,12 +1809,15 @@ declare class PrivacyKeyManager {
|
|
|
1809
1809
|
* Exports a shareable privacy address encoding the owner public key and
|
|
1810
1810
|
* viewing PUBLIC key of the currently loaded identity.
|
|
1811
1811
|
*
|
|
1812
|
-
* Format: `
|
|
1812
|
+
* Format: `orbpriv2:{ownerPk_hex}:{viewingPublicKey_hex}:{checksum}`
|
|
1813
1813
|
*
|
|
1814
1814
|
* The recipient uses this address so the sender can:
|
|
1815
1815
|
* 1. Embed `ownerPk` in the note commitment (Poseidon4 input).
|
|
1816
1816
|
* 2. Encrypt the memo via ECDH with the recipient's `viewingPublicKey`.
|
|
1817
1817
|
*
|
|
1818
|
+
* The trailing checksum (see `privacyAddressChecksum`) makes a corrupted
|
|
1819
|
+
* paste fail to decode rather than pay into an unspendable note.
|
|
1820
|
+
*
|
|
1818
1821
|
* SECURITY: Only the viewing PUBLIC key is embedded — the viewing secret key
|
|
1819
1822
|
* (used for decryption) is never exported. Holders of this address cannot
|
|
1820
1823
|
* decrypt the recipient's notes.
|
|
@@ -1823,9 +1826,14 @@ declare class PrivacyKeyManager {
|
|
|
1823
1826
|
*/
|
|
1824
1827
|
encodePrivacyAddress(): string;
|
|
1825
1828
|
/**
|
|
1826
|
-
* Decode a privacy address
|
|
1827
|
-
*
|
|
1828
|
-
*
|
|
1829
|
+
* Decode a privacy address into `{ ownerPkHex, viewingPublicKeyHex }`, or
|
|
1830
|
+
* `null` if it does not parse.
|
|
1831
|
+
*
|
|
1832
|
+
* Accepts both:
|
|
1833
|
+
* - `orbpriv2:{ownerPk}:{ivk}:{checksum}` — checksum verified; a mismatch
|
|
1834
|
+
* (corrupted paste) returns null.
|
|
1835
|
+
* - `orbpriv1:{ownerPk}:{ivk}` — legacy, no checksum. Still read so addresses
|
|
1836
|
+
* shared before v2 keep resolving; only v2 is emitted.
|
|
1829
1837
|
*/
|
|
1830
1838
|
static decodePrivacyAddress(address: string): {
|
|
1831
1839
|
ownerPkHex: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -1809,12 +1809,15 @@ declare class PrivacyKeyManager {
|
|
|
1809
1809
|
* Exports a shareable privacy address encoding the owner public key and
|
|
1810
1810
|
* viewing PUBLIC key of the currently loaded identity.
|
|
1811
1811
|
*
|
|
1812
|
-
* Format: `
|
|
1812
|
+
* Format: `orbpriv2:{ownerPk_hex}:{viewingPublicKey_hex}:{checksum}`
|
|
1813
1813
|
*
|
|
1814
1814
|
* The recipient uses this address so the sender can:
|
|
1815
1815
|
* 1. Embed `ownerPk` in the note commitment (Poseidon4 input).
|
|
1816
1816
|
* 2. Encrypt the memo via ECDH with the recipient's `viewingPublicKey`.
|
|
1817
1817
|
*
|
|
1818
|
+
* The trailing checksum (see `privacyAddressChecksum`) makes a corrupted
|
|
1819
|
+
* paste fail to decode rather than pay into an unspendable note.
|
|
1820
|
+
*
|
|
1818
1821
|
* SECURITY: Only the viewing PUBLIC key is embedded — the viewing secret key
|
|
1819
1822
|
* (used for decryption) is never exported. Holders of this address cannot
|
|
1820
1823
|
* decrypt the recipient's notes.
|
|
@@ -1823,9 +1826,14 @@ declare class PrivacyKeyManager {
|
|
|
1823
1826
|
*/
|
|
1824
1827
|
encodePrivacyAddress(): string;
|
|
1825
1828
|
/**
|
|
1826
|
-
* Decode a privacy address
|
|
1827
|
-
*
|
|
1828
|
-
*
|
|
1829
|
+
* Decode a privacy address into `{ ownerPkHex, viewingPublicKeyHex }`, or
|
|
1830
|
+
* `null` if it does not parse.
|
|
1831
|
+
*
|
|
1832
|
+
* Accepts both:
|
|
1833
|
+
* - `orbpriv2:{ownerPk}:{ivk}:{checksum}` — checksum verified; a mismatch
|
|
1834
|
+
* (corrupted paste) returns null.
|
|
1835
|
+
* - `orbpriv1:{ownerPk}:{ivk}` — legacy, no checksum. Still read so addresses
|
|
1836
|
+
* shared before v2 keep resolving; only v2 is emitted.
|
|
1829
1837
|
*/
|
|
1830
1838
|
static decodePrivacyAddress(address: string): {
|
|
1831
1839
|
ownerPkHex: string;
|
package/dist/index.js
CHANGED
|
@@ -1574,6 +1574,12 @@ function deriveOwnerPk(spendingKey) {
|
|
|
1574
1574
|
}
|
|
1575
1575
|
|
|
1576
1576
|
// src/protocol/keys/PrivacyKeyManager.ts
|
|
1577
|
+
var import_sha26 = require("@noble/hashes/sha2.js");
|
|
1578
|
+
function privacyAddressChecksum(ownerPkHex, ivkHex) {
|
|
1579
|
+
const body = `orbpriv2:${ownerPkHex}:${ivkHex}`;
|
|
1580
|
+
const digest = (0, import_sha26.sha256)(new TextEncoder().encode(body));
|
|
1581
|
+
return toHex(digest.slice(0, 4)).slice(2);
|
|
1582
|
+
}
|
|
1577
1583
|
var PrivacyKeyManager = class {
|
|
1578
1584
|
_state = {
|
|
1579
1585
|
spendingKey: null,
|
|
@@ -1683,12 +1689,15 @@ var PrivacyKeyManager = class {
|
|
|
1683
1689
|
* Exports a shareable privacy address encoding the owner public key and
|
|
1684
1690
|
* viewing PUBLIC key of the currently loaded identity.
|
|
1685
1691
|
*
|
|
1686
|
-
* Format: `
|
|
1692
|
+
* Format: `orbpriv2:{ownerPk_hex}:{viewingPublicKey_hex}:{checksum}`
|
|
1687
1693
|
*
|
|
1688
1694
|
* The recipient uses this address so the sender can:
|
|
1689
1695
|
* 1. Embed `ownerPk` in the note commitment (Poseidon4 input).
|
|
1690
1696
|
* 2. Encrypt the memo via ECDH with the recipient's `viewingPublicKey`.
|
|
1691
1697
|
*
|
|
1698
|
+
* The trailing checksum (see `privacyAddressChecksum`) makes a corrupted
|
|
1699
|
+
* paste fail to decode rather than pay into an unspendable note.
|
|
1700
|
+
*
|
|
1692
1701
|
* SECURITY: Only the viewing PUBLIC key is embedded — the viewing secret key
|
|
1693
1702
|
* (used for decryption) is never exported. Holders of this address cannot
|
|
1694
1703
|
* decrypt the recipient's notes.
|
|
@@ -1700,21 +1709,35 @@ var PrivacyKeyManager = class {
|
|
|
1700
1709
|
const ivkPacked = this.getViewingPublicKeyPacked();
|
|
1701
1710
|
const ownerPkHex = scalarToHex(ownerPk);
|
|
1702
1711
|
const ivkHex = toHex(ivkPacked);
|
|
1703
|
-
|
|
1712
|
+
const checksum = privacyAddressChecksum(ownerPkHex, ivkHex);
|
|
1713
|
+
return `orbpriv2:${ownerPkHex}:${ivkHex}:${checksum}`;
|
|
1704
1714
|
}
|
|
1705
1715
|
/**
|
|
1706
|
-
* Decode a privacy address
|
|
1707
|
-
*
|
|
1708
|
-
*
|
|
1716
|
+
* Decode a privacy address into `{ ownerPkHex, viewingPublicKeyHex }`, or
|
|
1717
|
+
* `null` if it does not parse.
|
|
1718
|
+
*
|
|
1719
|
+
* Accepts both:
|
|
1720
|
+
* - `orbpriv2:{ownerPk}:{ivk}:{checksum}` — checksum verified; a mismatch
|
|
1721
|
+
* (corrupted paste) returns null.
|
|
1722
|
+
* - `orbpriv1:{ownerPk}:{ivk}` — legacy, no checksum. Still read so addresses
|
|
1723
|
+
* shared before v2 keep resolving; only v2 is emitted.
|
|
1709
1724
|
*/
|
|
1710
1725
|
static decodePrivacyAddress(address) {
|
|
1711
|
-
if (!address.startsWith("orbpriv1:")) return null;
|
|
1712
1726
|
const parts = address.split(":");
|
|
1713
|
-
if (parts
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1727
|
+
if (parts[0] === "orbpriv2") {
|
|
1728
|
+
if (parts.length !== 4) return null;
|
|
1729
|
+
const [, ownerPkHex, viewingPublicKeyHex, checksum] = parts;
|
|
1730
|
+
if (!ownerPkHex || !viewingPublicKeyHex || !checksum) return null;
|
|
1731
|
+
if (privacyAddressChecksum(ownerPkHex, viewingPublicKeyHex) !== checksum) return null;
|
|
1732
|
+
return { ownerPkHex, viewingPublicKeyHex };
|
|
1733
|
+
}
|
|
1734
|
+
if (parts[0] === "orbpriv1") {
|
|
1735
|
+
if (parts.length !== 3) return null;
|
|
1736
|
+
const [, ownerPkHex, viewingPublicKeyHex] = parts;
|
|
1737
|
+
if (!ownerPkHex || !viewingPublicKeyHex) return null;
|
|
1738
|
+
return { ownerPkHex, viewingPublicKeyHex };
|
|
1739
|
+
}
|
|
1740
|
+
return null;
|
|
1718
1741
|
}
|
|
1719
1742
|
/**
|
|
1720
1743
|
* Load keys from a cached "mk:0x{masterBytes_hex}" string produced by exportHex().
|
|
@@ -1740,7 +1763,7 @@ var PrivacyKeyManager = class {
|
|
|
1740
1763
|
|
|
1741
1764
|
// src/protocol/keys/spendingKeyDerivation.ts
|
|
1742
1765
|
var import_hkdf3 = require("@noble/hashes/hkdf.js");
|
|
1743
|
-
var
|
|
1766
|
+
var import_sha27 = require("@noble/hashes/sha2.js");
|
|
1744
1767
|
var MIN_SIGNATURE_BYTES = 32;
|
|
1745
1768
|
var MIN_DISTINCT_BYTES = 8;
|
|
1746
1769
|
function assertUsableSignature(sigBytes) {
|
|
@@ -1762,7 +1785,7 @@ async function deriveMasterKeyBytes(signatureHex, chainId, address) {
|
|
|
1762
1785
|
const info = new TextEncoder().encode(
|
|
1763
1786
|
`orbinum-sk-${KEY_VERSION}:${chainId}:${canonicalAccountId(address)}`
|
|
1764
1787
|
);
|
|
1765
|
-
return (0, import_hkdf3.hkdf)(
|
|
1788
|
+
return (0, import_hkdf3.hkdf)(import_sha27.sha256, sigBytes, new Uint8Array(0), info, 32);
|
|
1766
1789
|
}
|
|
1767
1790
|
async function deriveSpendingKeyFromSignature(signatureHex, chainId, address) {
|
|
1768
1791
|
return deriveSpendingKeyFromMaster(await deriveMasterKeyBytes(signatureHex, chainId, address));
|
package/dist/index.mjs
CHANGED
|
@@ -463,6 +463,12 @@ ${canonicalAccountId(address)}`;
|
|
|
463
463
|
}
|
|
464
464
|
|
|
465
465
|
// src/protocol/keys/PrivacyKeyManager.ts
|
|
466
|
+
import { sha256 } from "@noble/hashes/sha2.js";
|
|
467
|
+
function privacyAddressChecksum(ownerPkHex, ivkHex) {
|
|
468
|
+
const body = `orbpriv2:${ownerPkHex}:${ivkHex}`;
|
|
469
|
+
const digest = sha256(new TextEncoder().encode(body));
|
|
470
|
+
return toHex(digest.slice(0, 4)).slice(2);
|
|
471
|
+
}
|
|
466
472
|
var PrivacyKeyManager = class {
|
|
467
473
|
_state = {
|
|
468
474
|
spendingKey: null,
|
|
@@ -572,12 +578,15 @@ var PrivacyKeyManager = class {
|
|
|
572
578
|
* Exports a shareable privacy address encoding the owner public key and
|
|
573
579
|
* viewing PUBLIC key of the currently loaded identity.
|
|
574
580
|
*
|
|
575
|
-
* Format: `
|
|
581
|
+
* Format: `orbpriv2:{ownerPk_hex}:{viewingPublicKey_hex}:{checksum}`
|
|
576
582
|
*
|
|
577
583
|
* The recipient uses this address so the sender can:
|
|
578
584
|
* 1. Embed `ownerPk` in the note commitment (Poseidon4 input).
|
|
579
585
|
* 2. Encrypt the memo via ECDH with the recipient's `viewingPublicKey`.
|
|
580
586
|
*
|
|
587
|
+
* The trailing checksum (see `privacyAddressChecksum`) makes a corrupted
|
|
588
|
+
* paste fail to decode rather than pay into an unspendable note.
|
|
589
|
+
*
|
|
581
590
|
* SECURITY: Only the viewing PUBLIC key is embedded — the viewing secret key
|
|
582
591
|
* (used for decryption) is never exported. Holders of this address cannot
|
|
583
592
|
* decrypt the recipient's notes.
|
|
@@ -589,21 +598,35 @@ var PrivacyKeyManager = class {
|
|
|
589
598
|
const ivkPacked = this.getViewingPublicKeyPacked();
|
|
590
599
|
const ownerPkHex = scalarToHex(ownerPk);
|
|
591
600
|
const ivkHex = toHex(ivkPacked);
|
|
592
|
-
|
|
601
|
+
const checksum = privacyAddressChecksum(ownerPkHex, ivkHex);
|
|
602
|
+
return `orbpriv2:${ownerPkHex}:${ivkHex}:${checksum}`;
|
|
593
603
|
}
|
|
594
604
|
/**
|
|
595
|
-
* Decode a privacy address
|
|
596
|
-
*
|
|
597
|
-
*
|
|
605
|
+
* Decode a privacy address into `{ ownerPkHex, viewingPublicKeyHex }`, or
|
|
606
|
+
* `null` if it does not parse.
|
|
607
|
+
*
|
|
608
|
+
* Accepts both:
|
|
609
|
+
* - `orbpriv2:{ownerPk}:{ivk}:{checksum}` — checksum verified; a mismatch
|
|
610
|
+
* (corrupted paste) returns null.
|
|
611
|
+
* - `orbpriv1:{ownerPk}:{ivk}` — legacy, no checksum. Still read so addresses
|
|
612
|
+
* shared before v2 keep resolving; only v2 is emitted.
|
|
598
613
|
*/
|
|
599
614
|
static decodePrivacyAddress(address) {
|
|
600
|
-
if (!address.startsWith("orbpriv1:")) return null;
|
|
601
615
|
const parts = address.split(":");
|
|
602
|
-
if (parts
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
616
|
+
if (parts[0] === "orbpriv2") {
|
|
617
|
+
if (parts.length !== 4) return null;
|
|
618
|
+
const [, ownerPkHex, viewingPublicKeyHex, checksum] = parts;
|
|
619
|
+
if (!ownerPkHex || !viewingPublicKeyHex || !checksum) return null;
|
|
620
|
+
if (privacyAddressChecksum(ownerPkHex, viewingPublicKeyHex) !== checksum) return null;
|
|
621
|
+
return { ownerPkHex, viewingPublicKeyHex };
|
|
622
|
+
}
|
|
623
|
+
if (parts[0] === "orbpriv1") {
|
|
624
|
+
if (parts.length !== 3) return null;
|
|
625
|
+
const [, ownerPkHex, viewingPublicKeyHex] = parts;
|
|
626
|
+
if (!ownerPkHex || !viewingPublicKeyHex) return null;
|
|
627
|
+
return { ownerPkHex, viewingPublicKeyHex };
|
|
628
|
+
}
|
|
629
|
+
return null;
|
|
607
630
|
}
|
|
608
631
|
/**
|
|
609
632
|
* Load keys from a cached "mk:0x{masterBytes_hex}" string produced by exportHex().
|
|
@@ -629,7 +652,7 @@ var PrivacyKeyManager = class {
|
|
|
629
652
|
|
|
630
653
|
// src/protocol/keys/spendingKeyDerivation.ts
|
|
631
654
|
import { hkdf } from "@noble/hashes/hkdf.js";
|
|
632
|
-
import { sha256 } from "@noble/hashes/sha2.js";
|
|
655
|
+
import { sha256 as sha2562 } from "@noble/hashes/sha2.js";
|
|
633
656
|
var MIN_SIGNATURE_BYTES = 32;
|
|
634
657
|
var MIN_DISTINCT_BYTES = 8;
|
|
635
658
|
function assertUsableSignature(sigBytes) {
|
|
@@ -651,7 +674,7 @@ async function deriveMasterKeyBytes(signatureHex, chainId, address) {
|
|
|
651
674
|
const info = new TextEncoder().encode(
|
|
652
675
|
`orbinum-sk-${KEY_VERSION}:${chainId}:${canonicalAccountId(address)}`
|
|
653
676
|
);
|
|
654
|
-
return hkdf(
|
|
677
|
+
return hkdf(sha2562, sigBytes, new Uint8Array(0), info, 32);
|
|
655
678
|
}
|
|
656
679
|
async function deriveSpendingKeyFromSignature(signatureHex, chainId, address) {
|
|
657
680
|
return deriveSpendingKeyFromMaster(await deriveMasterKeyBytes(signatureHex, chainId, address));
|