@unicitylabs/sphere-sdk 0.5.8 → 0.6.0-dev.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.
@@ -668,114 +668,6 @@ var oidNist = (suffix) => ({
668
668
  oid: Uint8Array.from([6, 9, 96, 134, 72, 1, 101, 3, 4, 2, suffix])
669
669
  });
670
670
 
671
- // node_modules/@noble/hashes/hmac.js
672
- var _HMAC = class {
673
- oHash;
674
- iHash;
675
- blockLen;
676
- outputLen;
677
- finished = false;
678
- destroyed = false;
679
- constructor(hash, key) {
680
- ahash(hash);
681
- abytes(key, void 0, "key");
682
- this.iHash = hash.create();
683
- if (typeof this.iHash.update !== "function")
684
- throw new Error("Expected instance of class which extends utils.Hash");
685
- this.blockLen = this.iHash.blockLen;
686
- this.outputLen = this.iHash.outputLen;
687
- const blockLen = this.blockLen;
688
- const pad = new Uint8Array(blockLen);
689
- pad.set(key.length > blockLen ? hash.create().update(key).digest() : key);
690
- for (let i = 0; i < pad.length; i++)
691
- pad[i] ^= 54;
692
- this.iHash.update(pad);
693
- this.oHash = hash.create();
694
- for (let i = 0; i < pad.length; i++)
695
- pad[i] ^= 54 ^ 92;
696
- this.oHash.update(pad);
697
- clean(pad);
698
- }
699
- update(buf) {
700
- aexists(this);
701
- this.iHash.update(buf);
702
- return this;
703
- }
704
- digestInto(out) {
705
- aexists(this);
706
- abytes(out, this.outputLen, "output");
707
- this.finished = true;
708
- this.iHash.digestInto(out);
709
- this.oHash.update(out);
710
- this.oHash.digestInto(out);
711
- this.destroy();
712
- }
713
- digest() {
714
- const out = new Uint8Array(this.oHash.outputLen);
715
- this.digestInto(out);
716
- return out;
717
- }
718
- _cloneInto(to) {
719
- to ||= Object.create(Object.getPrototypeOf(this), {});
720
- const { oHash, iHash, finished, destroyed, blockLen, outputLen } = this;
721
- to = to;
722
- to.finished = finished;
723
- to.destroyed = destroyed;
724
- to.blockLen = blockLen;
725
- to.outputLen = outputLen;
726
- to.oHash = oHash._cloneInto(to.oHash);
727
- to.iHash = iHash._cloneInto(to.iHash);
728
- return to;
729
- }
730
- clone() {
731
- return this._cloneInto();
732
- }
733
- destroy() {
734
- this.destroyed = true;
735
- this.oHash.destroy();
736
- this.iHash.destroy();
737
- }
738
- };
739
- var hmac = (hash, key, message) => new _HMAC(hash, key).update(message).digest();
740
- hmac.create = (hash, key) => new _HMAC(hash, key);
741
-
742
- // node_modules/@noble/hashes/hkdf.js
743
- function extract(hash, ikm, salt) {
744
- ahash(hash);
745
- if (salt === void 0)
746
- salt = new Uint8Array(hash.outputLen);
747
- return hmac(hash, salt, ikm);
748
- }
749
- var HKDF_COUNTER = /* @__PURE__ */ Uint8Array.of(0);
750
- var EMPTY_BUFFER = /* @__PURE__ */ Uint8Array.of();
751
- function expand(hash, prk, info, length = 32) {
752
- ahash(hash);
753
- anumber(length, "length");
754
- const olen = hash.outputLen;
755
- if (length > 255 * olen)
756
- throw new Error("Length must be <= 255*HashLen");
757
- const blocks = Math.ceil(length / olen);
758
- if (info === void 0)
759
- info = EMPTY_BUFFER;
760
- else
761
- abytes(info, void 0, "info");
762
- const okm = new Uint8Array(blocks * olen);
763
- const HMAC = hmac.create(hash, prk);
764
- const HMACTmp = HMAC._cloneInto();
765
- const T = new Uint8Array(HMAC.outputLen);
766
- for (let counter = 0; counter < blocks; counter++) {
767
- HKDF_COUNTER[0] = counter + 1;
768
- HMACTmp.update(counter === 0 ? EMPTY_BUFFER : T).update(info).update(HKDF_COUNTER).digestInto(T);
769
- okm.set(T, olen * counter);
770
- HMAC._cloneInto(HMACTmp);
771
- }
772
- HMAC.destroy();
773
- HMACTmp.destroy();
774
- clean(T, HKDF_COUNTER);
775
- return okm.slice(0, length);
776
- }
777
- var hkdf = (hash, ikm, salt, info, length) => expand(hash, extract(hash, ikm, salt), info, length);
778
-
779
671
  // node_modules/@noble/hashes/_md.js
780
672
  function Chi(a, b, c) {
781
673
  return a & b ^ ~a & c;
@@ -1047,141 +939,13 @@ import {
1047
939
  NIP44,
1048
940
  Event as NostrEventClass,
1049
941
  EventKinds,
1050
- hashNametag,
942
+ decryptNametag,
1051
943
  NostrClient,
1052
944
  Filter,
1053
945
  isChatMessage,
1054
946
  isReadReceipt
1055
947
  } from "@unicitylabs/nostr-js-sdk";
1056
948
 
1057
- // core/crypto.ts
1058
- import * as bip39 from "bip39";
1059
- import CryptoJS from "crypto-js";
1060
- import elliptic from "elliptic";
1061
-
1062
- // core/errors.ts
1063
- var SphereError = class extends Error {
1064
- code;
1065
- cause;
1066
- constructor(message, code, cause) {
1067
- super(message);
1068
- this.name = "SphereError";
1069
- this.code = code;
1070
- this.cause = cause;
1071
- }
1072
- };
1073
-
1074
- // core/bech32.ts
1075
- var CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
1076
- var GENERATOR = [996825010, 642813549, 513874426, 1027748829, 705979059];
1077
- function convertBits(data, fromBits, toBits, pad) {
1078
- let acc = 0;
1079
- let bits = 0;
1080
- const ret = [];
1081
- const maxv = (1 << toBits) - 1;
1082
- for (let i = 0; i < data.length; i++) {
1083
- const value = data[i];
1084
- if (value < 0 || value >> fromBits !== 0) return null;
1085
- acc = acc << fromBits | value;
1086
- bits += fromBits;
1087
- while (bits >= toBits) {
1088
- bits -= toBits;
1089
- ret.push(acc >> bits & maxv);
1090
- }
1091
- }
1092
- if (pad) {
1093
- if (bits > 0) {
1094
- ret.push(acc << toBits - bits & maxv);
1095
- }
1096
- } else if (bits >= fromBits || acc << toBits - bits & maxv) {
1097
- return null;
1098
- }
1099
- return ret;
1100
- }
1101
- function hrpExpand(hrp) {
1102
- const ret = [];
1103
- for (let i = 0; i < hrp.length; i++) ret.push(hrp.charCodeAt(i) >> 5);
1104
- ret.push(0);
1105
- for (let i = 0; i < hrp.length; i++) ret.push(hrp.charCodeAt(i) & 31);
1106
- return ret;
1107
- }
1108
- function bech32Polymod(values) {
1109
- let chk = 1;
1110
- for (let p = 0; p < values.length; p++) {
1111
- const top = chk >> 25;
1112
- chk = (chk & 33554431) << 5 ^ values[p];
1113
- for (let i = 0; i < 5; i++) {
1114
- if (top >> i & 1) chk ^= GENERATOR[i];
1115
- }
1116
- }
1117
- return chk;
1118
- }
1119
- function bech32Checksum(hrp, data) {
1120
- const values = hrpExpand(hrp).concat(data).concat([0, 0, 0, 0, 0, 0]);
1121
- const mod = bech32Polymod(values) ^ 1;
1122
- const ret = [];
1123
- for (let p = 0; p < 6; p++) {
1124
- ret.push(mod >> 5 * (5 - p) & 31);
1125
- }
1126
- return ret;
1127
- }
1128
- function encodeBech32(hrp, version, program) {
1129
- if (version < 0 || version > 16) {
1130
- throw new SphereError("Invalid witness version", "VALIDATION_ERROR");
1131
- }
1132
- const converted = convertBits(Array.from(program), 8, 5, true);
1133
- if (!converted) {
1134
- throw new SphereError("Failed to convert bits", "VALIDATION_ERROR");
1135
- }
1136
- const data = [version].concat(converted);
1137
- const checksum = bech32Checksum(hrp, data);
1138
- const combined = data.concat(checksum);
1139
- let out = hrp + "1";
1140
- for (let i = 0; i < combined.length; i++) {
1141
- out += CHARSET[combined[i]];
1142
- }
1143
- return out;
1144
- }
1145
-
1146
- // core/crypto.ts
1147
- var ec = new elliptic.ec("secp256k1");
1148
- var CURVE_ORDER = BigInt(
1149
- "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"
1150
- );
1151
- function getPublicKey(privateKey, compressed = true) {
1152
- const keyPair = ec.keyFromPrivate(privateKey, "hex");
1153
- return keyPair.getPublic(compressed, "hex");
1154
- }
1155
- function sha2562(data, inputEncoding = "hex") {
1156
- const parsed = inputEncoding === "hex" ? CryptoJS.enc.Hex.parse(data) : CryptoJS.enc.Utf8.parse(data);
1157
- return CryptoJS.SHA256(parsed).toString();
1158
- }
1159
- function ripemd160(data, inputEncoding = "hex") {
1160
- const parsed = inputEncoding === "hex" ? CryptoJS.enc.Hex.parse(data) : CryptoJS.enc.Utf8.parse(data);
1161
- return CryptoJS.RIPEMD160(parsed).toString();
1162
- }
1163
- function hash160(data) {
1164
- const sha = sha2562(data, "hex");
1165
- return ripemd160(sha, "hex");
1166
- }
1167
- function hash160ToBytes(hash160Hex) {
1168
- const matches = hash160Hex.match(/../g);
1169
- if (!matches) return new Uint8Array(0);
1170
- return Uint8Array.from(matches.map((x) => parseInt(x, 16)));
1171
- }
1172
- function publicKeyToAddress(publicKey, prefix = "alpha", witnessVersion = 0) {
1173
- const pubKeyHash = hash160(publicKey);
1174
- const programBytes = hash160ToBytes(pubKeyHash);
1175
- return encodeBech32(prefix, witnessVersion, programBytes);
1176
- }
1177
- function hexToBytes2(hex) {
1178
- const matches = hex.match(/../g);
1179
- if (!matches) {
1180
- return new Uint8Array(0);
1181
- }
1182
- return Uint8Array.from(matches.map((x) => parseInt(x, 16)));
1183
- }
1184
-
1185
949
  // core/logger.ts
1186
950
  var LOGGER_KEY = "__sphere_sdk_logger__";
1187
951
  function getState() {
@@ -1274,6 +1038,18 @@ var logger = {
1274
1038
  }
1275
1039
  };
1276
1040
 
1041
+ // core/errors.ts
1042
+ var SphereError = class extends Error {
1043
+ code;
1044
+ cause;
1045
+ constructor(message, code, cause) {
1046
+ super(message);
1047
+ this.name = "SphereError";
1048
+ this.code = code;
1049
+ this.cause = cause;
1050
+ }
1051
+ };
1052
+
1277
1053
  // transport/websocket.ts
1278
1054
  var WebSocketReadyState = {
1279
1055
  CONNECTING: 0,
@@ -1296,63 +1072,6 @@ function defaultUUIDGenerator() {
1296
1072
  var COMPOSING_INDICATOR_KIND = 25050;
1297
1073
  var TIMESTAMP_RANDOMIZATION = 2 * 24 * 60 * 60;
1298
1074
  var EVENT_KINDS = NOSTR_EVENT_KINDS;
1299
- function hashAddressForTag(address) {
1300
- const bytes = new TextEncoder().encode("unicity:address:" + address);
1301
- return Buffer2.from(sha256(bytes)).toString("hex");
1302
- }
1303
- function deriveNametagEncryptionKey(privateKeyHex) {
1304
- const privateKeyBytes = Buffer2.from(privateKeyHex, "hex");
1305
- const saltInput = new TextEncoder().encode("sphere-nametag-salt");
1306
- const salt = sha256(saltInput);
1307
- const info = new TextEncoder().encode("nametag-encryption");
1308
- return hkdf(sha256, privateKeyBytes, salt, info, 32);
1309
- }
1310
- async function encryptNametag(nametag, privateKeyHex) {
1311
- const key = deriveNametagEncryptionKey(privateKeyHex);
1312
- const iv = crypto.getRandomValues(new Uint8Array(12));
1313
- const encoder = new TextEncoder();
1314
- const data = encoder.encode(nametag);
1315
- const cryptoKey = await crypto.subtle.importKey(
1316
- "raw",
1317
- new Uint8Array(key).buffer,
1318
- { name: "AES-GCM" },
1319
- false,
1320
- ["encrypt"]
1321
- );
1322
- const encrypted = await crypto.subtle.encrypt(
1323
- { name: "AES-GCM", iv: new Uint8Array(iv).buffer },
1324
- cryptoKey,
1325
- new Uint8Array(data).buffer
1326
- );
1327
- const combined = new Uint8Array(iv.length + encrypted.byteLength);
1328
- combined.set(iv, 0);
1329
- combined.set(new Uint8Array(encrypted), iv.length);
1330
- return Buffer2.from(combined).toString("base64");
1331
- }
1332
- async function decryptNametag(encryptedBase64, privateKeyHex) {
1333
- try {
1334
- const key = deriveNametagEncryptionKey(privateKeyHex);
1335
- const combined = Buffer2.from(encryptedBase64, "base64");
1336
- const iv = combined.slice(0, 12);
1337
- const ciphertext = combined.slice(12);
1338
- const cryptoKey = await crypto.subtle.importKey(
1339
- "raw",
1340
- new Uint8Array(key).buffer,
1341
- { name: "AES-GCM" },
1342
- false,
1343
- ["decrypt"]
1344
- );
1345
- const decrypted = await crypto.subtle.decrypt(
1346
- { name: "AES-GCM", iv: new Uint8Array(iv).buffer },
1347
- cryptoKey,
1348
- new Uint8Array(ciphertext).buffer
1349
- );
1350
- const decoder = new TextDecoder();
1351
- return decoder.decode(decrypted);
1352
- } catch {
1353
- return null;
1354
- }
1355
- }
1356
1075
  var NostrTransportProvider = class {
1357
1076
  id = "nostr";
1358
1077
  name = "Nostr Transport";
@@ -1821,138 +1540,51 @@ var NostrTransportProvider = class {
1821
1540
  }
1822
1541
  async resolveNametag(nametag) {
1823
1542
  this.ensureConnected();
1824
- const hashedNametag = hashNametag(nametag);
1825
- let events = await this.queryEvents({
1826
- kinds: [EVENT_KINDS.NAMETAG_BINDING],
1827
- "#t": [hashedNametag],
1828
- limit: 1
1829
- });
1830
- if (events.length === 0) {
1831
- events = await this.queryEvents({
1832
- kinds: [EVENT_KINDS.NAMETAG_BINDING],
1833
- "#d": [hashedNametag],
1834
- limit: 1
1835
- });
1836
- }
1837
- if (events.length === 0) return null;
1838
- const bindingEvent = events[0];
1839
- if (bindingEvent.pubkey) {
1840
- return bindingEvent.pubkey;
1841
- }
1842
- const pubkeyTag = bindingEvent.tags.find((t) => t[0] === "p");
1843
- if (pubkeyTag?.[1]) return pubkeyTag[1];
1844
- return null;
1543
+ return this.nostrClient.queryPubkeyByNametag(nametag);
1845
1544
  }
1846
1545
  async resolveNametagInfo(nametag) {
1847
1546
  this.ensureConnected();
1848
- const hashedNametag = hashNametag(nametag);
1849
- let events = await this.queryEvents({
1850
- kinds: [EVENT_KINDS.NAMETAG_BINDING],
1851
- "#t": [hashedNametag],
1852
- limit: 1
1853
- });
1854
- if (events.length === 0) {
1855
- events = await this.queryEvents({
1856
- kinds: [EVENT_KINDS.NAMETAG_BINDING],
1857
- "#d": [hashedNametag],
1858
- limit: 1
1859
- });
1860
- }
1861
- if (events.length === 0) {
1547
+ const binding = await this.nostrClient.queryBindingByNametag(nametag);
1548
+ if (!binding) {
1862
1549
  logger.debug("Nostr", `resolveNametagInfo: no binding events found for Unicity ID "${nametag}"`);
1863
1550
  return null;
1864
1551
  }
1865
- const bindingEvent = events[0];
1866
- try {
1867
- const content = JSON.parse(bindingEvent.content);
1868
- const { ProxyAddress } = await import("@unicitylabs/state-transition-sdk/lib/address/ProxyAddress");
1869
- const proxyAddr = await ProxyAddress.fromNameTag(nametag);
1870
- const proxyAddress = proxyAddr.toString();
1871
- if (content.public_key && content.l1_address) {
1872
- return {
1873
- nametag,
1874
- transportPubkey: bindingEvent.pubkey,
1875
- chainPubkey: content.public_key,
1876
- l1Address: content.l1_address,
1877
- directAddress: content.direct_address || "",
1878
- proxyAddress,
1879
- timestamp: bindingEvent.created_at * 1e3
1880
- };
1881
- }
1882
- logger.debug("Nostr", "Legacy nametag event without extended fields:", nametag);
1883
- const pubkeyTag = bindingEvent.tags.find((t) => t[0] === "pubkey");
1884
- const l1Tag = bindingEvent.tags.find((t) => t[0] === "l1");
1885
- if (pubkeyTag?.[1] && l1Tag?.[1]) {
1886
- return {
1887
- nametag,
1888
- transportPubkey: bindingEvent.pubkey,
1889
- chainPubkey: pubkeyTag[1],
1890
- l1Address: l1Tag[1],
1891
- directAddress: "",
1892
- proxyAddress,
1893
- timestamp: bindingEvent.created_at * 1e3
1894
- };
1895
- }
1896
- return {
1897
- nametag,
1898
- transportPubkey: bindingEvent.pubkey,
1899
- chainPubkey: "",
1900
- // Cannot derive from 32-byte Nostr pubkey
1901
- l1Address: "",
1902
- // Cannot derive without 33-byte pubkey
1903
- directAddress: "",
1904
- proxyAddress,
1905
- timestamp: bindingEvent.created_at * 1e3
1906
- };
1907
- } catch {
1908
- const { ProxyAddress } = await import("@unicitylabs/state-transition-sdk/lib/address/ProxyAddress");
1909
- const proxyAddr = await ProxyAddress.fromNameTag(nametag);
1910
- return {
1911
- nametag,
1912
- transportPubkey: bindingEvent.pubkey,
1913
- chainPubkey: "",
1914
- l1Address: "",
1915
- directAddress: "",
1916
- proxyAddress: proxyAddr.toString(),
1917
- timestamp: bindingEvent.created_at * 1e3
1918
- };
1919
- }
1552
+ return this.bindingInfoToPeerInfo(binding, nametag);
1920
1553
  }
1921
1554
  /**
1922
1555
  * Resolve a DIRECT://, PROXY://, or L1 address to full peer info.
1923
- * Performs reverse lookup: hash(address) query '#t' tag → parse binding event.
1924
- * Works with both new identity binding events and legacy nametag binding events.
1556
+ * Performs reverse lookup via nostr-js-sdk with first-seen-wins anti-hijacking.
1925
1557
  */
1926
1558
  async resolveAddressInfo(address) {
1927
1559
  this.ensureConnected();
1928
- const addressHash = hashAddressForTag(address);
1929
- const events = await this.queryEvents({
1930
- kinds: [EVENT_KINDS.NAMETAG_BINDING],
1931
- "#t": [addressHash],
1932
- limit: 1
1933
- });
1934
- if (events.length === 0) return null;
1935
- const bindingEvent = events[0];
1936
- try {
1937
- const content = JSON.parse(bindingEvent.content);
1938
- return {
1939
- nametag: content.nametag || void 0,
1940
- transportPubkey: bindingEvent.pubkey,
1941
- chainPubkey: content.public_key || "",
1942
- l1Address: content.l1_address || "",
1943
- directAddress: content.direct_address || "",
1944
- proxyAddress: content.proxy_address || void 0,
1945
- timestamp: bindingEvent.created_at * 1e3
1946
- };
1947
- } catch {
1948
- return {
1949
- transportPubkey: bindingEvent.pubkey,
1950
- chainPubkey: "",
1951
- l1Address: "",
1952
- directAddress: "",
1953
- timestamp: bindingEvent.created_at * 1e3
1954
- };
1560
+ const binding = await this.nostrClient.queryBindingByAddress(address);
1561
+ if (!binding) return null;
1562
+ return this.bindingInfoToPeerInfo(binding);
1563
+ }
1564
+ /**
1565
+ * Convert a BindingInfo (from nostr-js-sdk) to PeerInfo (sphere-sdk type).
1566
+ * Computes PROXY address from nametag if available.
1567
+ */
1568
+ async bindingInfoToPeerInfo(binding, nametag) {
1569
+ const nametagValue = nametag || binding.nametag;
1570
+ let proxyAddress = binding.proxyAddress;
1571
+ if (nametagValue && !proxyAddress) {
1572
+ try {
1573
+ const { ProxyAddress } = await import("@unicitylabs/state-transition-sdk/lib/address/ProxyAddress");
1574
+ const proxyAddr = await ProxyAddress.fromNameTag(nametagValue);
1575
+ proxyAddress = proxyAddr.toString();
1576
+ } catch {
1577
+ }
1955
1578
  }
1579
+ return {
1580
+ nametag: nametagValue,
1581
+ transportPubkey: binding.transportPubkey,
1582
+ chainPubkey: binding.publicKey || "",
1583
+ l1Address: binding.l1Address || "",
1584
+ directAddress: binding.directAddress || "",
1585
+ proxyAddress,
1586
+ timestamp: binding.timestamp
1587
+ };
1956
1588
  }
1957
1589
  /**
1958
1590
  * Resolve transport pubkey (Nostr pubkey) to full peer info.
@@ -2072,11 +1704,10 @@ var NostrTransportProvider = class {
2072
1704
  }
2073
1705
  /**
2074
1706
  * Publish identity binding event on Nostr.
2075
- * Without nametag: publishes base binding (chainPubkey, l1Address, directAddress).
2076
- * With nametag: also publishes nametag hash, proxy address, encrypted nametag for recovery.
2077
- *
2078
- * Uses kind 30078 parameterized replaceable event with d=SHA256('unicity:identity:' + nostrPubkey).
2079
- * Each HD address index has its own Nostr key → its own binding event.
1707
+ * Without nametag: publishes base binding (chainPubkey, l1Address, directAddress)
1708
+ * using a per-identity d-tag for address discovery.
1709
+ * With nametag: delegates to nostr-js-sdk's publishNametagBinding which handles
1710
+ * conflict detection (first-seen-wins), encryption, and indexed tags.
2080
1711
  *
2081
1712
  * @returns true if successful, false if nametag is taken by another pubkey
2082
1713
  */
@@ -2086,102 +1717,41 @@ var NostrTransportProvider = class {
2086
1717
  throw new SphereError("Identity not set", "NOT_INITIALIZED");
2087
1718
  }
2088
1719
  const nostrPubkey = this.getNostrPubkey();
2089
- const dTagBytes = new TextEncoder().encode("unicity:identity:" + nostrPubkey);
2090
- const dTag = Buffer2.from(sha256(dTagBytes)).toString("hex");
2091
- const contentObj = {
2092
- public_key: chainPubkey,
2093
- l1_address: l1Address,
2094
- direct_address: directAddress
2095
- };
2096
- const tags = [
2097
- ["d", dTag],
2098
- ["t", hashAddressForTag(chainPubkey)],
2099
- ["t", hashAddressForTag(directAddress)],
2100
- ["t", hashAddressForTag(l1Address)]
2101
- ];
2102
1720
  if (nametag) {
2103
- const existing = await this.resolveNametag(nametag);
2104
- if (existing && existing !== nostrPubkey) {
2105
- logger.debug("Nostr", "Unicity ID already taken:", nametag, "- owner:", existing);
2106
- return false;
2107
- }
2108
1721
  const { ProxyAddress } = await import("@unicitylabs/state-transition-sdk/lib/address/ProxyAddress");
2109
1722
  const proxyAddr = await ProxyAddress.fromNameTag(nametag);
2110
- const proxyAddress = proxyAddr.toString();
2111
- const encryptedNametag = await encryptNametag(nametag, this.identity.privateKey);
2112
- const hashedNametag = hashNametag(nametag);
2113
- contentObj.nametag = nametag;
2114
- contentObj.encrypted_nametag = encryptedNametag;
2115
- contentObj.proxy_address = proxyAddress;
2116
- tags.push(["t", hashedNametag]);
2117
- tags.push(["t", hashAddressForTag(proxyAddress)]);
2118
- }
2119
- const content = JSON.stringify(contentObj);
2120
- const event = await this.createEvent(EVENT_KINDS.NAMETAG_BINDING, content, tags);
2121
- await this.publishEvent(event);
2122
- if (nametag) {
2123
- logger.debug("Nostr", "Published identity binding with Unicity ID:", nametag, "for pubkey:", nostrPubkey.slice(0, 16) + "...");
2124
- } else {
2125
- logger.debug("Nostr", "Published identity binding (no Unicity ID) for pubkey:", nostrPubkey.slice(0, 16) + "...");
2126
- }
2127
- return true;
2128
- }
2129
- /** @deprecated Use publishIdentityBinding instead */
2130
- async publishNametag(nametag, address) {
2131
- this.ensureReady();
2132
- const hashedNametag = hashNametag(nametag);
2133
- const event = await this.createEvent(EVENT_KINDS.NAMETAG_BINDING, address, [
2134
- ["d", hashedNametag],
2135
- ["a", address]
2136
- ]);
2137
- await this.publishEvent(event);
2138
- logger.debug("Nostr", "Published Unicity ID binding:", nametag);
2139
- }
2140
- async registerNametag(nametag, _publicKey, directAddress = "") {
2141
- this.ensureReady();
2142
- if (!this.identity) {
2143
- throw new SphereError("Identity not set", "NOT_INITIALIZED");
2144
- }
2145
- const nostrPubkey = this.getNostrPubkey();
2146
- const existing = await this.resolveNametag(nametag);
2147
- logger.debug("Nostr", "registerNametag:", nametag, "existing:", existing, "myPubkey:", nostrPubkey);
2148
- if (existing && existing !== nostrPubkey) {
2149
- logger.debug("Nostr", "Unicity ID already taken:", nametag, "- owner:", existing);
2150
- return false;
1723
+ try {
1724
+ const success2 = await this.nostrClient.publishNametagBinding(
1725
+ nametag,
1726
+ nostrPubkey,
1727
+ {
1728
+ publicKey: chainPubkey,
1729
+ l1Address,
1730
+ directAddress,
1731
+ proxyAddress: proxyAddr.toString()
1732
+ }
1733
+ );
1734
+ if (success2) {
1735
+ logger.debug("Nostr", "Published identity binding with Unicity ID:", nametag, "for pubkey:", nostrPubkey.slice(0, 16) + "...");
1736
+ }
1737
+ return success2;
1738
+ } catch (error) {
1739
+ if (error instanceof Error && error.message.includes("already claimed")) {
1740
+ logger.debug("Nostr", "Unicity ID already taken:", nametag);
1741
+ return false;
1742
+ }
1743
+ throw error;
1744
+ }
2151
1745
  }
2152
- const privateKeyHex = this.identity.privateKey;
2153
- const compressedPubkey = getPublicKey(privateKeyHex, true);
2154
- const l1Address = publicKeyToAddress(compressedPubkey, "alpha");
2155
- const encryptedNametag = await encryptNametag(nametag, privateKeyHex);
2156
- const { ProxyAddress } = await import("@unicitylabs/state-transition-sdk/lib/address/ProxyAddress");
2157
- const proxyAddr = await ProxyAddress.fromNameTag(nametag);
2158
- const proxyAddress = proxyAddr.toString();
2159
- const hashedNametag = hashNametag(nametag);
2160
- const content = JSON.stringify({
2161
- nametag_hash: hashedNametag,
2162
- address: nostrPubkey,
2163
- verified: Date.now(),
2164
- // Extended fields for nametag recovery and address lookup
2165
- encrypted_nametag: encryptedNametag,
2166
- public_key: compressedPubkey,
2167
- l1_address: l1Address,
2168
- direct_address: directAddress,
2169
- proxy_address: proxyAddress
1746
+ const success = await this.nostrClient.publishIdentityBinding({
1747
+ publicKey: chainPubkey,
1748
+ l1Address,
1749
+ directAddress
2170
1750
  });
2171
- const tags = [
2172
- ["d", hashedNametag],
2173
- ["nametag", hashedNametag],
2174
- ["t", hashedNametag],
2175
- ["t", hashAddressForTag(directAddress)],
2176
- ["t", hashAddressForTag(proxyAddress)],
2177
- ["address", nostrPubkey],
2178
- ["pubkey", compressedPubkey],
2179
- ["l1", l1Address]
2180
- ];
2181
- const event = await this.createEvent(EVENT_KINDS.NAMETAG_BINDING, content, tags);
2182
- await this.publishEvent(event);
2183
- logger.debug("Nostr", "Registered Unicity ID:", nametag, "for pubkey:", nostrPubkey.slice(0, 16) + "...", "l1:", l1Address.slice(0, 12) + "...");
2184
- return true;
1751
+ if (success) {
1752
+ logger.debug("Nostr", "Published identity binding (no Unicity ID) for pubkey:", nostrPubkey.slice(0, 16) + "...");
1753
+ }
1754
+ return success;
2185
1755
  }
2186
1756
  // Track broadcast subscriptions
2187
1757
  broadcastSubscriptions = /* @__PURE__ */ new Map();
@@ -3410,6 +2980,130 @@ var InMemoryIpfsStatePersistence = class {
3410
2980
  }
3411
2981
  };
3412
2982
 
2983
+ // node_modules/@noble/hashes/hmac.js
2984
+ var _HMAC = class {
2985
+ oHash;
2986
+ iHash;
2987
+ blockLen;
2988
+ outputLen;
2989
+ finished = false;
2990
+ destroyed = false;
2991
+ constructor(hash, key) {
2992
+ ahash(hash);
2993
+ abytes(key, void 0, "key");
2994
+ this.iHash = hash.create();
2995
+ if (typeof this.iHash.update !== "function")
2996
+ throw new Error("Expected instance of class which extends utils.Hash");
2997
+ this.blockLen = this.iHash.blockLen;
2998
+ this.outputLen = this.iHash.outputLen;
2999
+ const blockLen = this.blockLen;
3000
+ const pad = new Uint8Array(blockLen);
3001
+ pad.set(key.length > blockLen ? hash.create().update(key).digest() : key);
3002
+ for (let i = 0; i < pad.length; i++)
3003
+ pad[i] ^= 54;
3004
+ this.iHash.update(pad);
3005
+ this.oHash = hash.create();
3006
+ for (let i = 0; i < pad.length; i++)
3007
+ pad[i] ^= 54 ^ 92;
3008
+ this.oHash.update(pad);
3009
+ clean(pad);
3010
+ }
3011
+ update(buf) {
3012
+ aexists(this);
3013
+ this.iHash.update(buf);
3014
+ return this;
3015
+ }
3016
+ digestInto(out) {
3017
+ aexists(this);
3018
+ abytes(out, this.outputLen, "output");
3019
+ this.finished = true;
3020
+ this.iHash.digestInto(out);
3021
+ this.oHash.update(out);
3022
+ this.oHash.digestInto(out);
3023
+ this.destroy();
3024
+ }
3025
+ digest() {
3026
+ const out = new Uint8Array(this.oHash.outputLen);
3027
+ this.digestInto(out);
3028
+ return out;
3029
+ }
3030
+ _cloneInto(to) {
3031
+ to ||= Object.create(Object.getPrototypeOf(this), {});
3032
+ const { oHash, iHash, finished, destroyed, blockLen, outputLen } = this;
3033
+ to = to;
3034
+ to.finished = finished;
3035
+ to.destroyed = destroyed;
3036
+ to.blockLen = blockLen;
3037
+ to.outputLen = outputLen;
3038
+ to.oHash = oHash._cloneInto(to.oHash);
3039
+ to.iHash = iHash._cloneInto(to.iHash);
3040
+ return to;
3041
+ }
3042
+ clone() {
3043
+ return this._cloneInto();
3044
+ }
3045
+ destroy() {
3046
+ this.destroyed = true;
3047
+ this.oHash.destroy();
3048
+ this.iHash.destroy();
3049
+ }
3050
+ };
3051
+ var hmac = (hash, key, message) => new _HMAC(hash, key).update(message).digest();
3052
+ hmac.create = (hash, key) => new _HMAC(hash, key);
3053
+
3054
+ // node_modules/@noble/hashes/hkdf.js
3055
+ function extract(hash, ikm, salt) {
3056
+ ahash(hash);
3057
+ if (salt === void 0)
3058
+ salt = new Uint8Array(hash.outputLen);
3059
+ return hmac(hash, salt, ikm);
3060
+ }
3061
+ var HKDF_COUNTER = /* @__PURE__ */ Uint8Array.of(0);
3062
+ var EMPTY_BUFFER = /* @__PURE__ */ Uint8Array.of();
3063
+ function expand(hash, prk, info, length = 32) {
3064
+ ahash(hash);
3065
+ anumber(length, "length");
3066
+ const olen = hash.outputLen;
3067
+ if (length > 255 * olen)
3068
+ throw new Error("Length must be <= 255*HashLen");
3069
+ const blocks = Math.ceil(length / olen);
3070
+ if (info === void 0)
3071
+ info = EMPTY_BUFFER;
3072
+ else
3073
+ abytes(info, void 0, "info");
3074
+ const okm = new Uint8Array(blocks * olen);
3075
+ const HMAC = hmac.create(hash, prk);
3076
+ const HMACTmp = HMAC._cloneInto();
3077
+ const T = new Uint8Array(HMAC.outputLen);
3078
+ for (let counter = 0; counter < blocks; counter++) {
3079
+ HKDF_COUNTER[0] = counter + 1;
3080
+ HMACTmp.update(counter === 0 ? EMPTY_BUFFER : T).update(info).update(HKDF_COUNTER).digestInto(T);
3081
+ okm.set(T, olen * counter);
3082
+ HMAC._cloneInto(HMACTmp);
3083
+ }
3084
+ HMAC.destroy();
3085
+ HMACTmp.destroy();
3086
+ clean(T, HKDF_COUNTER);
3087
+ return okm.slice(0, length);
3088
+ }
3089
+ var hkdf = (hash, ikm, salt, info, length) => expand(hash, extract(hash, ikm, salt), info, length);
3090
+
3091
+ // core/crypto.ts
3092
+ import * as bip39 from "bip39";
3093
+ import CryptoJS from "crypto-js";
3094
+ import elliptic from "elliptic";
3095
+ var ec = new elliptic.ec("secp256k1");
3096
+ var CURVE_ORDER = BigInt(
3097
+ "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"
3098
+ );
3099
+ function hexToBytes2(hex) {
3100
+ const matches = hex.match(/../g);
3101
+ if (!matches) {
3102
+ return new Uint8Array(0);
3103
+ }
3104
+ return Uint8Array.from(matches.map((x) => parseInt(x, 16)));
3105
+ }
3106
+
3413
3107
  // impl/shared/ipfs/ipns-key-derivation.ts
3414
3108
  var IPNS_HKDF_INFO = "ipfs-storage-ed25519-v1";
3415
3109
  var libp2pCryptoModule = null;