diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index 1c8aeee..33fdbb3 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -8,7 +8,9 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [20.x, latest] + node-version: + - 20.x + - latest steps: - uses: actions/checkout@v3 - name: Use Node.js ${{ matrix.node-version }} diff --git a/.jshintrc b/.jshintrc index 589cec4..993c9f8 100644 --- a/.jshintrc +++ b/.jshintrc @@ -1,4 +1,9 @@ { + "globals": { + "crypto": true, + "EventSource": true + }, + "module": true, "browser": true, "node": true, "esversion": 11, @@ -16,7 +21,6 @@ "plusplus": true, "undef": true, "unused": "vars", - "strict": true, "maxdepth": 4, "maxstatements": 100, "maxcomplexity": 20 diff --git a/.prettierrc.json b/.prettierrc.json index a48aa0c..eb4153b 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -1,9 +1,9 @@ { - "printWidth": 80, - "tabWidth": 2, - "singleQuote": false, "bracketSpacing": true, + "printWidth": 80, "proseWrap": "always", - "semi": true, - "trailingComma": "all" + "singleQuote": false, + "tabWidth": 2, + "trailingComma": "all", + "semi": true } diff --git a/dashhd.js b/dashhd.js index 78530fe..70626f7 100644 --- a/dashhd.js +++ b/dashhd.js @@ -1,3 +1,10 @@ +import DashKeys from "dashkeys"; + +let Crypto = globalThis.crypto; + +/** @type DashHD */ +let DashHd = {}; + /** * @typedef DashHD * @prop {HDCreate} create @@ -37,7 +44,7 @@ * @prop {HDKeyToKey} publicKeyNormalize * @prop {HDHasher} ripemd160sum * @prop {HDHasher} sha256sum - * @prop {HDHasher} sha512hmac + * @prop {HDHmac} sha512hmac * @prop {HDBase64Url} bytesToBase64Url * @prop {HDKeyToKey} toPublicKey */ @@ -68,718 +75,682 @@ * @prop {Uint8Array} chainCode * @prop {Uint8Array?} [privateKey] * @prop {Uint8Array} publicKey - */ -/** @type {DashHD} */ -//@ts-ignore -var DashHd = ("object" === typeof module && exports) || {}; -(function (window, DashHd) { - "use strict"; - - //const BUFFER_LE = true; - const BUFFER_BE = false; - const COMPRESSED = true; - - const HARDENED = true; - const PUBLIC = false; +//const BUFFER_LE = true; +const BUFFER_BE = false; +const COMPRESSED = true; - //@ts-ignore - let Crypto = globalThis.crypto; - - //@ts-ignore - /** @type {import('dashkeys').DashKeys} */ - //@ts-ignore - let DashKeys = window.DashKeys || require("dashkeys"); - - let Utils = {}; - - /** - * @param {String} base58key - * @param {Object.} [opts] - */ - Utils.decode = async function (base58key, opts) { - //@ts-ignore - return await DashKeys.decode(base58key, opts); - }; +DashHd.HARDENED = true; +DashHd.PUBLIC = false; - /** - * @param {Uint8Array} keyBytes - * @param {Object} opts - * @param {String|Uint32} [opts.version] - */ - Utils.encodeXPrv = async function (keyBytes, opts) { - let version = "xprv"; - if (opts?.version) { - if (opts.version === "tprv") { - version = opts.version; - } else { - // intended for numbers, but won't break hex strings - version = opts.version.toString(16); - version = version.padStart(8, "0"); - } - } - //@ts-ignore - return await DashKeys.encodeKey(keyBytes, { version }); - }; +let Utils = {}; - /** - * @param {Uint8Array} keyBytes - * @param {Object} opts - * @param {String|Uint32} [opts.version] - */ - Utils.encodeXPub = async function (keyBytes, opts) { - let version = "xpub"; - if (opts?.version) { - if (opts.version === "tpub") { - version = opts.version; - } else { - // intended for numbers, but won't break hex strings - version = opts.version.toString(16); - version = version.padStart(8, "0"); - } - } - //@ts-ignore - return await DashKeys.encodeKey(keyBytes, { version: version }); - }; - /** @type {HDKeyTweak} */ - Utils.privateKeyTweakAdd = async function (privateKeyCopy, tweak) { - let Secp256k1 = - //@ts-ignore - window.nobleSecp256k1 || require("@dashincubator/secp256k1"); - let p = Secp256k1.utils._normalizePrivateKey(privateKeyCopy); - let t = Secp256k1.utils._normalizePrivateKey(tweak); - return Secp256k1.utils._bigintTo32Bytes( - Secp256k1.utils.mod(p + t, Secp256k1.CURVE.n), - ); - }; +/** + * @param {String} base58key + * @param {Object.} [opts] + */ +Utils.decode = async function (base58key, opts) { + return await DashKeys.decode(base58key, opts); +}; - /** @type {HDKeyToKey} */ - Utils.publicKeyNormalize = async function (pubBytes) { - let Secp256k1 = - //@ts-ignore - window.nobleSecp256k1 || require("@dashincubator/secp256k1"); - - try { - let point = Secp256k1.Point.fromHex(pubBytes); - pubBytes = point.toRawBytes(COMPRESSED); - } catch (e) { - throw new Error("Invalid public key"); +/** + * @param {Uint8Array} keyBytes + * @param {Object} [opts] + * @param {String|Uint32} [opts.version] + */ +Utils.encodeXPrv = async function (keyBytes, opts) { + let version = "xprv"; + if (opts?.version) { + if (opts.version === "tprv") { + version = opts.version; + } else { + // intended for numbers, but won't break hex strings + version = opts.version.toString(16); + version = version.padStart(8, "0"); } + } + //@ts-expect-error - TODO DashKeys opts.version is too restrictive + return await DashKeys.encodeKey(keyBytes, { version }); +}; - return pubBytes; - }; - - /** @type {HDKeyTweak} */ - Utils.publicKeyTweakAdd = async function (publicKeyCopy, tweak) { - let Secp256k1 = - //@ts-ignore - window.nobleSecp256k1 || require("@dashincubator/secp256k1"); - - let P = Secp256k1.Point.fromHex(publicKeyCopy); - let t = Secp256k1.utils._normalizePrivateKey(tweak); - let Q = Secp256k1.Point.BASE.multiplyAndAddUnsafe(P, t, 1n); - if (!Q) { - throw new Error("Tweaked point at infinity"); +/** + * @param {Uint8Array} keyBytes + * @param {Object} [opts] + * @param {String|Uint32} [opts.version] + */ +Utils.encodeXPub = async function (keyBytes, opts) { + let version = "xpub"; + if (opts?.version) { + if (opts.version === "tpub") { + version = opts.version; + } else { + // intended for numbers, but won't break hex strings + version = opts.version.toString(16); + version = version.padStart(8, "0"); } - return Q.toRawBytes(COMPRESSED); - }; - - /** @type {HDHasher} */ - Utils.ripemd160sum = async function (bytes) { - //@ts-ignore - return await DashKeys.utils.ripemd160sum(bytes); - }; - - /** @type {HDHasher} */ - Utils.sha256sum = async function (bytes) { - let arrayBuffer = await Crypto.subtle.digest("SHA-256", bytes); - let hashBytes = new Uint8Array(arrayBuffer); - return hashBytes; - }; - - /** @type {HDHmac} */ - Utils.sha512hmac = async function (entropy, data) { - /** @type {"raw"|"pkcs8"|"spki"} */ - let format = "raw"; - let algo = { - name: "HMAC", - hash: "SHA-512", - }; - let extractable = false; - /** @type {Array} */ - let keyUsages = ["sign"]; - let hmacKey = await Crypto.subtle.importKey( - format, - entropy, - algo, - extractable, - keyUsages, - ); - let sig = await Crypto.subtle.sign("HMAC", hmacKey, data); + } + //@ts-expect-error - TODO DashKeys opts.version is too restrictive + return await DashKeys.encodeKey(keyBytes, { version: version }); +}; +/** @type {HDKeyTweak} */ +Utils.privateKeyTweakAdd = async function (privateKeyCopy, tweak) { + /** @type {import('@dashincubator/secp256k1')} */ + let Secp256k1 = + //@ts-expect-error - if it exists + globalThis.nobleSecp256k1 || (await import("@dashincubator/secp256k1")); + + let p = Secp256k1.utils._normalizePrivateKey(privateKeyCopy); + let t = Secp256k1.utils._normalizePrivateKey(tweak); + return Secp256k1.utils._bigintTo32Bytes( + Secp256k1.utils.mod(p + t, Secp256k1.CURVE.n), + ); +}; + +/** @type {HDKeyToKey} */ +Utils.publicKeyNormalize = async function (pubBytes) { + /** @type {import('@dashincubator/secp256k1')} */ + let Secp256k1 = + //@ts-expect-error - if it exists + globalThis.nobleSecp256k1 || (await import("@dashincubator/secp256k1")); + + try { + let point = Secp256k1.Point.fromHex(pubBytes); + pubBytes = point.toRawBytes(COMPRESSED); + } catch (e) { + throw new Error("Invalid public key"); + } - return new Uint8Array(sig); + return pubBytes; +}; + +/** @type {HDKeyTweak} */ +Utils.publicKeyTweakAdd = async function (publicKeyCopy, tweak) { + /** @type {import('@dashincubator/secp256k1')} */ + let Secp256k1 = + //@ts-expect-error - if it exists + globalThis.nobleSecp256k1 || (await import("@dashincubator/secp256k1")); + + let P = Secp256k1.Point.fromHex(publicKeyCopy); + let t = Secp256k1.utils._normalizePrivateKey(tweak); + let Q = Secp256k1.Point.BASE.multiplyAndAddUnsafe(P, t, 1n); + if (!Q) { + throw new Error("Tweaked point at infinity"); + } + return Q.toRawBytes(COMPRESSED); +}; + +/** @type {HDHasher} */ +Utils.ripemd160sum = async function (bytes) { + return await DashKeys.utils.ripemd160sum(bytes); +}; + +/** @type {HDHasher} */ +Utils.sha256sum = async function (bytes) { + let arrayBuffer = await Crypto.subtle.digest("SHA-256", bytes); + let hashBytes = new Uint8Array(arrayBuffer); + return hashBytes; +}; + +/** @type {HDHmac} */ +Utils.sha512hmac = async function (entropy, data) { + /** @type {"raw"|"pkcs8"|"spki"} */ + let format = "raw"; + let algo = { + name: "HMAC", + hash: "SHA-512", }; + let extractable = false; + /** @type {Array} */ + let keyUsages = ["sign"]; + let hmacKey = await Crypto.subtle.importKey( + format, + entropy, + algo, + extractable, + keyUsages, + ); + let sig = await Crypto.subtle.sign("HMAC", hmacKey, data); + + return new Uint8Array(sig); +}; + +/** @type {HDBase64Url} */ +Utils.bytesToBase64Url = function (bytes) { + let bins = []; + + for (let i = 0; i < bytes.length; i += 1) { + let b = bytes[i]; + let s = String.fromCodePoint(b); + bins.push(s); + } - /** @type {HDBase64Url} */ - Utils.bytesToBase64Url = function (bytes) { - let bins = []; - - for (let i = 0; i < bytes.length; i += 1) { - let b = bytes[i]; - let s = String.fromCodePoint(b); - bins.push(s); - } + let str = bins.join(""); + let b64 = btoa(str); + let b64url = b64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, ""); + + return b64url; +}; + +/** @type {HDSecureErase} */ +Utils.secureErase = function (buf) { + Crypto.getRandomValues(buf); +}; + +/** @type {HDKeyToKey} */ +Utils.toPublicKey = async function (privBytes) { + /** @type {import('@dashincubator/secp256k1')} */ + let Secp256k1 = + //@ts-expect-error - if it exists + globalThis.nobleSecp256k1 || (await import("@dashincubator/secp256k1")); + + return Secp256k1.getPublicKey(privBytes, COMPRESSED); +}; + +// "Bitcoin seed" +let ROOT_CHAIN = Uint8Array.from([ + // B i t c o i n " " s e e d + 0x42, 0x69, 0x74, 0x63, 0x6f, 0x69, 0x6e, 0x20, 0x73, 0x65, 0x65, 0x64, +]); +DashHd.HARDENED_OFFSET = 0x80000000; +let KEY_SIZE = 33; +let INDEXED_KEY_SIZE = 4 + KEY_SIZE; +let XKEY_SIZE = 74; +let XKEY_DEPTH = 4; // m/44'/5'/0'/<0>[/0] + +DashHd._utils = Utils; + +// Bitcoin defaults hard-coded by default. +// Use package `coininfo` for others. +DashHd.MAINNET = { private: 0x0488ade4, public: 0x0488b21e }; +DashHd.TESTNET = { private: 0x043587cf, public: 0x04358394 }; + +// Use types +DashHd.RECEIVE = 0; +DashHd.CHANGE = 1; + +/** @type HDCreate */ +DashHd.create = function ({ + versions, + depth, + parentFingerprint, + index, + chainCode, + privateKey, + publicKey, +}) { + /** @type {HDKey} */ + let hdkey = {}; + + hdkey.versions = versions ?? DashHd.MAINNET; + hdkey.depth = depth ?? 0; + hdkey.parentFingerprint = parentFingerprint ?? 0; + hdkey.index = index ?? 0; + hdkey.chainCode = chainCode; + hdkey.privateKey = privateKey; + hdkey.publicKey = publicKey; + + return hdkey; +}; + +DashHd.toAddr = async function (pubBytes, opts) { + if (pubBytes.length !== 33) { + throw new Error("expected a public key (size 1 + 32)"); + } + //@ts-expect-error - TODO DashKeys opts.version is too restrictive + return await DashKeys.encodeKey(pubBytes, opts); +}; - let str = bins.join(""); - let b64 = btoa(str); - let b64url = b64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, ""); +DashHd.toWif = async function (privBytes, opts) { + if (privBytes.length !== 32) { + throw new Error("expected a private key (size 32)"); + } + //@ts-expect-error - TODO DashKeys opts.version is too restrictive + return await DashKeys.encodeKey(privBytes, opts); +}; - return b64url; - }; +DashHd.toXPrv = async function (hdkey, opts) { + if (!hdkey?.privateKey) { + throw new Error("missing .privateKey bytes"); + } + let xprvBytes = DashHd._toXBytes(hdkey, hdkey.privateKey); + let xprv = await Utils.encodeXPrv(xprvBytes, opts); + return xprv; +}; + +// TODO - missing custom version +DashHd.toXPrvBytes = function (hdkey, opts) { + if (!hdkey?.privateKey) { + throw new Error("missing .privateKey bytes"); + } - /** @type {HDSecureErase} */ - Utils.secureErase = function (buf) { - Crypto.getRandomValues(buf); - }; + let version = opts?.version || DashHd.MAINNET.private; + + let xprvPart = DashHd._toXBytes(hdkey, hdkey.privateKey); + let xprvBytes = new Uint8Array(xprvPart.length + 4); + let xkeyDv = new DataView(xprvBytes.buffer); + xkeyDv.setUint32(0, version, BUFFER_BE); + xprvBytes.set(xprvPart, 4); + return xprvBytes; +}; + +DashHd.toXPub = async function (hdkey, opts) { + let xpubBytes = DashHd._toXBytes(hdkey, hdkey.publicKey); + let xpub = await Utils.encodeXPub(xpubBytes, opts); + return xpub; +}; + +DashHd.toXPubBytes = function (hdkey, opts) { + /** @type {Uint32} */ + let version = DashHd.MAINNET.public; + if (opts?.version) { + let [_, versionUint32] = // jshint ignore:line + _versionToTuple( + opts.version, + "xpub", + DashHd.MAINNET.public, + "tpub", + DashHd.TESTNET.public, + ); + version = versionUint32; + } - /** @type {HDKeyToKey} */ - Utils.toPublicKey = async function (privBytes) { - let Secp256k1 = - //@ts-ignore - window.nobleSecp256k1 || require("@dashincubator/secp256k1"); + let xpubPart = DashHd._toXBytes(hdkey, hdkey.publicKey); + let xpubBytes = new Uint8Array(xpubPart.length + 4); + let xkeyDv = new DataView(xpubBytes.buffer); + xkeyDv.setUint32(0, version, BUFFER_BE); + xpubBytes.set(xpubPart, 4); + return xpubBytes; +}; + +DashHd._toXBytes = function (hdkey, keyBytes) { + if (!keyBytes) { + throw new Error("missing key bytes"); + } + // version(4) is part of Base58Check (perhaps mistakenly) + // depth(1) + fingerprint(4) + index(4) + chain(32) + key(1 + 32) + let xkey = new Uint8Array(XKEY_SIZE); + let xkeyDv = new DataView(xkey.buffer); - return Secp256k1.getPublicKey(privBytes, COMPRESSED); - }; + xkeyDv.setUint8(0, hdkey.depth); - // "Bitcoin seed" - let ROOT_CHAIN = Uint8Array.from([ - // B i t c o i n " " s e e d - 0x42, 0x69, 0x74, 0x63, 0x6f, 0x69, 0x6e, 0x20, 0x73, 0x65, 0x65, 0x64, - ]); - let HARDENED_OFFSET = 0x80000000; - let KEY_SIZE = 33; - let INDEXED_KEY_SIZE = 4 + KEY_SIZE; - let XKEY_SIZE = 74; - let XKEY_DEPTH = 4; // m/44'/5'/0'/<0>[/0] - - //@ts-ignore - DashHd._utils = Utils; - - // Bitcoin defaults hard-coded by default. - // Use package `coininfo` for others. - DashHd.MAINNET = { private: 0x0488ade4, public: 0x0488b21e }; - DashHd.TESTNET = { private: 0x043587cf, public: 0x04358394 }; - - // Derivation types - DashHd.HARDENED = HARDENED; - DashHd.PUBLIC = PUBLIC; - - // Use types - DashHd.RECEIVE = 0; - DashHd.CHANGE = 1; - - DashHd.create = function ({ - versions, - depth, - parentFingerprint, - index, - chainCode, - privateKey, - publicKey, - }) { - /** @type {HDKey} */ - let hdkey = {}; - - hdkey.versions = versions ?? DashHd.MAINNET; - hdkey.depth = depth ?? 0; - hdkey.parentFingerprint = parentFingerprint ?? 0; - hdkey.index = index ?? 0; - hdkey.chainCode = chainCode; - hdkey.privateKey = privateKey; - hdkey.publicKey = publicKey; - - return hdkey; - }; + let fingerprint = 0x00000000; + if (hdkey.depth > 0) { + fingerprint = hdkey.parentFingerprint; + } + xkeyDv.setUint32(1, fingerprint, BUFFER_BE); + xkeyDv.setUint32(5, hdkey.index, BUFFER_BE); - DashHd.toAddr = async function (pubBytes, opts) { - if (pubBytes.length !== 33) { - throw new Error("expected a public key (size 1 + 32)"); - } - return await DashKeys.encodeKey(pubBytes, opts); - }; + xkey.set(hdkey.chainCode, 9); - DashHd.toWif = async function (privBytes, opts) { - if (privBytes.length !== 32) { - throw new Error("expected a private key (size 32)"); + let keyStart = 41; + let isPrivate = 32 === keyBytes.length; + if (isPrivate) { + xkey[keyStart] = 0x00; + keyStart += 1; + } + xkey.set(keyBytes, keyStart); + + return xkey; +}; + +// IMPORTANT: never allow `await` (or other async) between writing to +// and accessing these! (otherwise the data will be corrupted) +// (stored here for performance - no allocations or garbage collection) +let _indexBuffer = new Uint8Array(4); +let _indexDv = new DataView(_indexBuffer.buffer); + +DashHd.deriveChild = async function (hdkey, index, hardened = DashHd.HARDENED) { + // seed = indexedKey + let indexedKey = new Uint8Array(INDEXED_KEY_SIZE); + if (hardened) { + if (!hdkey.privateKey) { + throw new Error("Could not derive hardened child key"); } - return await DashKeys.encodeKey(privBytes, opts); - }; - - DashHd.toXPrv = async function (hdkey, opts) { - //@ts-ignore - will throw if null - let xprvBytes = DashHd._toXBytes(hdkey, hdkey.privateKey); - //@ts-ignore - wth? - let xprv = await Utils.encodeXPrv(xprvBytes, opts); - return xprv; - }; - - // TODO - missing custom version - DashHd.toXPrvBytes = function (hdkey, opts) { - /** @type {Number} */ - //@ts-ignore - let version = opts?.version || DashHd.MAINNET.private; - - //@ts-ignore - will throw if null - let xprvPart = DashHd._toXBytes(hdkey, hdkey.privateKey); - let xprvBytes = new Uint8Array(xprvPart.length + 4); - let xkeyDv = new DataView(xprvBytes.buffer); - xkeyDv.setUint32(0, version, BUFFER_BE); - xprvBytes.set(xprvPart, 4); - return xprvBytes; - }; + index += DashHd.HARDENED_OFFSET; + indexedKey.set([0], 0); + indexedKey.set(hdkey.privateKey, 1); + } else { + indexedKey.set(hdkey.publicKey, 0); + } + _indexDv.setUint32(0, index, BUFFER_BE); + indexedKey.set(_indexBuffer, KEY_SIZE); + + let chainAndKeys; + try { + chainAndKeys = await DashHd._derive(indexedKey, hdkey); + } catch (e) { + // In essence: + // if it couldn't produce a public key, just go on the next one + // + // More precisely: + // + // throw if IL >= n || (privateKey + IL) === 0 + // In case parse256(IL) >= n or ki == 0, + // one should proceed with the next value for i + + // throw if IL >= n || (g**IL + publicKey) is infinity + // In case parse256(IL) >= n or Ki is the point at infinity, + // one should proceed with the next value for i + //index += 1; // or not + throw e; + } - DashHd.toXPub = async function (hdkey, opts) { - let xpubBytes = DashHd._toXBytes(hdkey, hdkey.publicKey); - let xpub = await Utils.encodeXPub(xpubBytes, opts); - return xpub; - }; + let versions = hdkey.versions; + let depth = hdkey.depth + 1; + let parentFingerprint = await DashHd._fingerprint(hdkey.publicKey); + return Object.assign( + { + versions, + depth, + parentFingerprint, + index, + }, + chainAndKeys, + ); +}; + +DashHd._derive = async function (indexedKey, xParent) { + // seed = indexedKey + // I = hash + // IL = keyTweak + // IR = nextChainCode + let hash = await Utils.sha512hmac(xParent.chainCode, indexedKey); + let keyTweak = hash.slice(0, 32); + let hashedChainCode = hash.slice(32); + + let tweakedPrivKey; + if (xParent.privateKey) { + let priv = xParent.privateKey; + tweakedPrivKey = await Utils.privateKeyTweakAdd(priv, keyTweak); + } - DashHd.toXPubBytes = function (hdkey, opts) { - /** @type {Uint32} */ - //@ts-ignore - it's a number, I promise - let version = DashHd.MAINNET.public; - if (opts?.version) { - let [_, versionUint32] = // jshint ignore:line - _versionToTuple( - opts.version, - "xpub", - //@ts-ignore - it's a number, I promise - DashHd.MAINNET.public, - "tpub", - DashHd.TESTNET.public, - ); - version = versionUint32; - } + let pub = xParent.publicKey; + let tweakedPubkey = await Utils.publicKeyTweakAdd(pub, keyTweak); - let xpubPart = DashHd._toXBytes(hdkey, hdkey.publicKey); - let xpubBytes = new Uint8Array(xpubPart.length + 4); - let xkeyDv = new DataView(xpubBytes.buffer); - xkeyDv.setUint32(0, version, BUFFER_BE); - xpubBytes.set(xpubPart, 4); - return xpubBytes; + return { + chainCode: hashedChainCode, + privateKey: tweakedPrivKey, + publicKey: tweakedPubkey, }; +}; - DashHd._toXBytes = function (hdkey, keyBytes) { - if (!keyBytes) { - throw new Error("missing key bytes"); - } - // version(4) is part of Base58Check (perhaps mistakenly) - // depth(1) + fingerprint(4) + index(4) + chain(32) + key(1 + 32) - let xkey = new Uint8Array(XKEY_SIZE); - let xkeyDv = new DataView(xkey.buffer); - - xkeyDv.setUint8(0, hdkey.depth); +DashHd.derivePath = async function (parent, path) { + if (path === "m" || path === "M" || path === "m'" || path === "M'") { + return parent; + } - let fingerprint = 0x00000000; - if (hdkey.depth > 0) { - fingerprint = hdkey.parentFingerprint; + let entries = path.split("/"); + let child = parent; + for (let i = 0; i < entries.length; i += 1) { + let c = entries[i]; + if (i === 0) { + assert(/^[mM]{1}/.test(c), 'Path must start with "m" or "M"'); + continue; } - xkeyDv.setUint32(1, fingerprint, BUFFER_BE); - xkeyDv.setUint32(5, hdkey.index, BUFFER_BE); - xkey.set(hdkey.chainCode, 9); + let hardened = c.length > 1 && c[c.length - 1] === "'"; + let childIndex = parseInt(c, 10); // & (HARDENED_OFFSET - 1) + assert(childIndex < DashHd.HARDENED_OFFSET, "Invalid index"); - let keyStart = 41; - let isPrivate = 32 === keyBytes.length; - if (isPrivate) { - xkey[keyStart] = 0x00; - keyStart += 1; - } - xkey.set(keyBytes, keyStart); - - return xkey; - }; + child = await DashHd.deriveChild(child, childIndex, hardened); + } - // IMPORTANT: never allow `await` (or other async) between writing to - // and accessing these! (otherwise the data will be corrupted) - // (stored here for performance - no allocations or garbage collection) - let _indexBuffer = new Uint8Array(4); - let _indexDv = new DataView(_indexBuffer.buffer); - - DashHd.deriveChild = async function (hdkey, index, hardened = HARDENED) { - // seed = indexedKey - let indexedKey = new Uint8Array(INDEXED_KEY_SIZE); - if (hardened) { - if (!hdkey.privateKey) { - throw new Error("Could not derive hardened child key"); - } - index += HARDENED_OFFSET; - indexedKey.set([0], 0); - indexedKey.set(hdkey.privateKey, 1); - } else { - indexedKey.set(hdkey.publicKey, 0); - } - _indexDv.setUint32(0, index, BUFFER_BE); - indexedKey.set(_indexBuffer, KEY_SIZE); - - let chainAndKeys; - try { - //@ts-ignore - chainAndKeys = await DashHd._derive(indexedKey, hdkey); - } catch (e) { - // In essence: - // if it couldn't produce a public key, just go on the next one - // - // More precisely: - // - // throw if IL >= n || (privateKey + IL) === 0 - // In case parse256(IL) >= n or ki == 0, - // one should proceed with the next value for i - - // throw if IL >= n || (g**IL + publicKey) is infinity - // In case parse256(IL) >= n or Ki is the point at infinity, - // one should proceed with the next value for i - //index += 1; // or not - throw e; - } + return child; +}; - let versions = hdkey.versions; - let depth = hdkey.depth + 1; - let parentFingerprint = await DashHd._fingerprint(hdkey.publicKey); - return Object.assign( - { - versions, - depth, - parentFingerprint, - index, - }, - chainAndKeys, - ); - }; +/** @type {HDFingerprint} */ +DashHd._fingerprint = async function (pubBytes) { + if (!pubBytes) { + throw new Error("Public key has not been set"); + } - //@ts-ignore - DashHd._derive = async function (indexedKey, xParent) { - // seed = indexedKey - // I = hash - // IL = keyTweak - // IR = nextChainCode - let hash = await Utils.sha512hmac(xParent.chainCode, indexedKey); - let keyTweak = hash.slice(0, 32); - let hashedChainCode = hash.slice(32); - - let tweakedPrivKey; - if (xParent.privateKey) { - let priv = xParent.privateKey; - tweakedPrivKey = await Utils.privateKeyTweakAdd(priv, keyTweak); - } + /* + * Note: this *happens* to use the same algorithm + * as many toPkh() implementations but, semantically, + * this is NOT toPkh() - it has a different purpose. + * Furthermore, fingerprint() may change independently of toPkh(). + */ + let sha = await Utils.sha256sum(pubBytes); + let identifier = await Utils.ripemd160sum(sha); + let i32be = readUInt32BE(identifier, 0); + return i32be; +}; - let pub = xParent.publicKey; - let tweakedPubkey = await Utils.publicKeyTweakAdd(pub, keyTweak); +/** + * @param {Uint8Array} u8 - a "web" JS buffer + * @param {Number} offset - where to start reading + * @returns {Number} - a 0-shifted (uint) JS Number + */ +function readUInt32BE(u8, offset) { + let dv = new DataView(u8.buffer); + // will read offset + 4 bytes (32-bit uint) + let n = dv.getUint32(offset, BUFFER_BE); + return n; +} - return { - chainCode: hashedChainCode, - privateKey: tweakedPrivKey, - publicKey: tweakedPubkey, - }; +DashHd.fromSeed = async function (seed, opts) { + let purpose = opts?.purpose ?? 44; + let coinType = opts?.coinType ?? 5; + let versions = opts?.versions || DashHd.MAINNET; + + // I = hash + // IL = rootPrivKey + // IR = rootChainCode + let hash = await Utils.sha512hmac(ROOT_CHAIN, seed); + let rootPrivKey = hash.slice(0, 32); + let rootChainCode = hash.slice(32); + let rootPubkey = await Utils.toPublicKey(rootPrivKey); + + let chainAndKeys = { + chainCode: rootChainCode, + privateKey: rootPrivKey, + publicKey: rootPubkey, }; - DashHd.derivePath = async function (parent, path) { - if (path === "m" || path === "M" || path === "m'" || path === "M'") { - return parent; - } + let hdkey = Object.assign( + { + versions: versions, + depth: 0, + parentFingerprint: 0, + index: 0, + }, + chainAndKeys, + { + deriveAccount, + }, + ); + + /** @type {HDDeriveAccount} */ + async function deriveAccount(account) { + let hdpath = `m/${purpose}'/${coinType}'/${account}'`; + let accountKey = await DashHd.derivePath(hdkey, hdpath); + + accountKey = await DashHd._createAccount(accountKey); + return accountKey; + } - let entries = path.split("/"); - let child = parent; - for (let i = 0; i < entries.length; i += 1) { - let c = entries[i]; - if (i === 0) { - assert(/^[mM]{1}/.test(c), 'Path must start with "m" or "M"'); - continue; - } + return hdkey; +}; - let hardened = c.length > 1 && c[c.length - 1] === "'"; - let childIndex = parseInt(c, 10); // & (HARDENED_OFFSET - 1) - assert(childIndex < HARDENED_OFFSET, "Invalid index"); +/** @type {HDCreateAccountKey} */ +DashHd._createAccount = async function (accountKey) { + Object.assign(accountKey, { + deriveXKey, + }); - child = await DashHd.deriveChild(child, childIndex, hardened); - } + async function deriveXKey(use = DashHd.RECEIVE) { + let xkey = await DashHd.deriveChild(accountKey, use, DashHd.PUBLIC); + xkey = DashHd._createXKey(xkey); + return xkey; + } - return child; - }; + return accountKey; +}; - /** @type {HDFingerprint} */ - DashHd._fingerprint = async function (pubBytes) { - if (!pubBytes) { - throw new Error("Public key has not been set"); - } - - /* - * Note: this *happens* to use the same algorithm - * as many toPkh() implementations but, semantically, - * this is NOT toPkh() - it has a different purpose. - * Furthermore, fingerprint() may change independently of toPkh(). - */ - let sha = await Utils.sha256sum(pubBytes); - let identifier = await Utils.ripemd160sum(sha); - let i32be = readUInt32BE(identifier, 0); - return i32be; - }; +/** @type {HDCreateXKey} */ +DashHd._createXKey = async function (xkey) { + Object.assign(xkey, { + deriveAddress, + }); /** - * @param {Uint8Array} u8 - a "web" JS buffer - * @param {Number} offset - where to start reading - * @returns {Number} - a 0-shifted (uint) JS Number + * @param {Number} index - key index + * @throws Error - if index cannot produce a valid public key */ - function readUInt32BE(u8, offset) { - let dv = new DataView(u8.buffer); - // will read offset + 4 bytes (32-bit uint) - let n = dv.getUint32(offset, BUFFER_BE); - return n; + async function deriveAddress(index) { + let key = await DashHd.deriveChild(xkey, index, DashHd.PUBLIC); + return key; } - DashHd.fromSeed = async function (seed, opts) { - let purpose = opts?.purpose ?? 44; - let coinType = opts?.coinType ?? 5; - let versions = opts?.versions || DashHd.MAINNET; - - // I = hash - // IL = rootPrivKey - // IR = rootChainCode - let hash = await Utils.sha512hmac(ROOT_CHAIN, seed); - let rootPrivKey = hash.slice(0, 32); - let rootChainCode = hash.slice(32); - let rootPubkey = await Utils.toPublicKey(rootPrivKey); - - let chainAndKeys = { - chainCode: rootChainCode, - privateKey: rootPrivKey, - publicKey: rootPubkey, - }; - - let hdkey = Object.assign( - { - versions: versions, - depth: 0, - parentFingerprint: 0, - index: 0, - }, - chainAndKeys, - { - deriveAccount, - }, + return xkey; +}; + +DashHd.fromXKey = async function (xkey, opts) { + // version(4) + depth(1) + fingerprint(4) + index(4) + chain(32) + key(1 + 32) + let versions = opts?.versions || DashHd.MAINNET; + let normalizePublicKey = opts?.normalizePublicKey ?? false; + let bip32 = opts?.bip32 ?? false; + + let keyInfo = await Utils.decode(xkey); + /** @type {String} */ //@ts-expect-error - TODO update DashKeys types + let keyHex = keyInfo.xprv || keyInfo.xpub; + let keyBytes = DashKeys.utils.hexToBytes(keyHex); + let keyDv = new DataView(keyBytes.buffer, 0, keyBytes.byteLength); + + //let version = keyDv.getUint32(0, BUFFER_BE); + let version = parseInt(keyInfo.version, 16); + + let privateKey; + let publicKey; + let key = keyBytes.subarray(41); + //if (keyDv.getUint8(41) === 0) + if (key[0] === 0) { + privateKey = key.subarray(1); // cut off first 0x0 byte + let [xprvHex, xprvUint32] = _versionToTuple( + versions.private, + "xprv", + DashHd.MAINNET.private, + "tprv", + DashHd.TESTNET.private, ); - - /** @type {HDDeriveAccount} */ - async function deriveAccount(account) { - let hdpath = `m/${purpose}'/${coinType}'/${account}'`; - let accountKey = await DashHd.derivePath(hdkey, hdpath); - - accountKey = await DashHd._createAccount(accountKey); - return accountKey; - } - - return hdkey; - }; - - /** @type {HDCreateAccountKey} */ - DashHd._createAccount = async function (accountKey) { - Object.assign(accountKey, { - deriveXKey, - }); - - async function deriveXKey(use = DashHd.RECEIVE) { - let xkey = await DashHd.deriveChild(accountKey, use, PUBLIC); - xkey = DashHd._createXKey(xkey); - return xkey; - } - - return accountKey; - }; - - /** @type {HDCreateXKey} */ - DashHd._createXKey = async function (xkey) { - Object.assign(xkey, { - deriveAddress, - }); - - /** - * @param {Number} index - key index - * @throws Error - if index cannot produce a valid public key - */ - async function deriveAddress(index) { - let key = await DashHd.deriveChild(xkey, index, PUBLIC); - return key; - } - - return xkey; - }; - - DashHd.fromXKey = async function (xkey, opts) { - // version(4) + depth(1) + fingerprint(4) + index(4) + chain(32) + key(1 + 32) - let versions = opts?.versions ?? DashHd.MAINNET; - let normalizePublicKey = opts?.normalizePublicKey ?? false; - let bip32 = opts?.bip32 ?? false; - - let keyInfo = await Utils.decode(xkey); - let keyBytes = DashKeys.utils.hexToBytes(keyInfo.xprv || keyInfo.xpub); - let keyDv = new DataView(keyBytes.buffer, 0, keyBytes.byteLength); - - //let version = keyDv.getUint32(0, BUFFER_BE); - let version = parseInt(keyInfo.version, 16); - - let privateKey; - let publicKey; - let key = keyBytes.subarray(41); - //if (keyDv.getUint8(41) === 0) - if (key[0] === 0) { - privateKey = key.subarray(1); // cut off first 0x0 byte - } else { - publicKey = key; + assert( + version === xprvUint32, + `Version mismatch: version does not match ${xprvHex} (private)`, + ); + publicKey = await Utils.toPublicKey(privateKey); + } else { + publicKey = key; + let [xpubHex, xpubUint32] = _versionToTuple( + versions.public, + "xpub", + DashHd.MAINNET.public, + "tpub", + DashHd.TESTNET.public, + ); + assert( + version === xpubUint32, + `Version mismatch: version does not match ${xpubHex} (public)`, + ); + // at one point xy pubs (1 + 64 bytes) were allowed (per spec) + // but nothing in the ecosystem actually works that way + assert(key.length === 33, "Public key must be 33 (1 + 32) bytes."); + if (normalizePublicKey) { + publicKey = await Utils.publicKeyNormalize(publicKey); } + } - if (publicKey) { - let [xpubHex, xpubUint32] = _versionToTuple( - versions.public, - "xpub", - //@ts-ignore - it's a number, I promise - DashHd.MAINNET.public, - "tpub", - DashHd.TESTNET.public, - ); - assert( - version === xpubUint32, - `Version mismatch: version does not match ${xpubHex} (public)`, + let depth = keyDv.getUint8(0); + if (!bip32) { + if (depth !== XKEY_DEPTH) { + throw new Error( + `XKey with depth=${depth} does not represent an account (depth=${XKEY_DEPTH}), set { bip32: true } for xkeys with arbirtrary depths`, ); - // at one point xy pubs (1 + 64 bytes) were allowed (per spec) - // but nothing in the ecosystem actually works that way - assert(key.length === 33, "Public key must be 33 (1 + 32) bytes."); - if (normalizePublicKey) { - publicKey = await Utils.publicKeyNormalize(publicKey); - } - } else { - let [xprvHex, xprvUint32] = _versionToTuple( - versions.private, - "xprv", - //@ts-ignore - it's a number, I promise - DashHd.MAINNET.private, - "tprv", - DashHd.TESTNET.private, - ); - assert( - version === xprvUint32, - `Version mismatch: version does not match ${xprvHex} (private)`, - ); - publicKey = await Utils.toPublicKey(privateKey); - } - - let depth = keyDv.getUint8(0); - if (!bip32) { - if (depth !== XKEY_DEPTH) { - throw new Error( - `XKey with depth=${depth} does not represent an account (depth=${XKEY_DEPTH}), set { bip32: true } for xkeys with arbirtrary depths`, - ); - } } + } - let parentFingerprint = keyDv.getUint32(1, BUFFER_BE); - let index = keyDv.getUint32(5, BUFFER_BE); - let chainCode = keyBytes.subarray(9, 41); - let hdkey = DashHd._createXKey({ - versions, - depth, - parentFingerprint, - index, - chainCode, - privateKey, - publicKey, - }); + let parentFingerprint = keyDv.getUint32(1, BUFFER_BE); + let index = keyDv.getUint32(5, BUFFER_BE); + let chainCode = keyBytes.subarray(9, 41); + let hdkey = DashHd._createXKey({ + versions, + depth, + parentFingerprint, + index, + chainCode, + privateKey, + publicKey, + }); - hdkey = DashHd._createXKey(hdkey); - return hdkey; - }; + hdkey = DashHd._createXKey(hdkey); + return hdkey; +}; - /** - * - * @param {String|Number} version - * @param {String} mainStr - 'xprv'|'xpub' - * @param {Number} mainInt - DashHd.MAINNET.private|DashHd.MAINNET.public - * @param {String} testStr - 'tprv'|'tpub' - * @param {Number} testInt - DashHd.TESTNET.private|DashHd.TESTNET.publi c - * @returns {[String, Number]} - */ - function _versionToTuple(version, mainStr, mainInt, testInt, testStr) { - let isMainnet = version === mainStr || version === "mainnet"; - let isTestnet = version === testStr || version === "testnet"; - if (isMainnet) { - version = mainInt; - } else if (isTestnet) { - version = testInt; - } - // intended for uint32, but doesn't break hex - let xkeyHex = version.toString(16); - xkeyHex = xkeyHex.padStart(8, "0"); - let xkeyUint32 = parseInt(xkeyHex, 16); - xkeyUint32 = xkeyUint32 >>> 0; /* jshint ignore:line */ // coerce uint32 - xkeyHex = `0x${xkeyHex}`; - - return [xkeyHex, xkeyUint32]; +/** + * @param {String|Number} version + * @param {String} mainStr - 'xprv'|'xpub' + * @param {Number} mainInt - DashHd.MAINNET.private|DashHd.MAINNET.public + * @param {String} testStr - 'tprv'|'tpub' + * @param {Number} testInt - DashHd.TESTNET.private|DashHd.TESTNET.publi c + * @returns {[String, Number]} + */ +function _versionToTuple(version, mainStr, mainInt, testStr, testInt) { + let isMainnet = version === mainStr || version === "mainnet"; + let isTestnet = version === testStr || version === "testnet"; + if (isMainnet) { + version = mainInt; + } else if (isTestnet) { + version = testInt; } + // intended for uint32, but doesn't break hex + let xkeyHex = version.toString(16); + xkeyHex = xkeyHex.padStart(8, "0"); + let xkeyUint32 = parseInt(xkeyHex, 16); + xkeyUint32 = xkeyUint32 >>> 0; /* jshint ignore:line */ // coerce uint32 + xkeyHex = `0x${xkeyHex}`; + + return [xkeyHex, xkeyUint32]; +} - DashHd.toId = async function (hdkey) { - let idBytes = await DashHd.toIdBytes(hdkey); - let id = Utils.bytesToBase64Url(idBytes); +DashHd.toId = async function (hdkey) { + let idBytes = await DashHd.toIdBytes(hdkey); + let id = Utils.bytesToBase64Url(idBytes); - return id; - }; + return id; +}; - DashHd.toIdBytes = async function (hdkey) { - let xpubBytes = await DashHd.toXPubBytes(hdkey); +DashHd.toIdBytes = async function (hdkey) { + let xpubBytes = await DashHd.toXPubBytes(hdkey); - let hashBuffer = await Crypto.subtle.digest("SHA-256", xpubBytes); - let idBuffer = hashBuffer.slice(0, 8); - let idBytes = new Uint8Array(idBuffer); + let hashBuffer = await Crypto.subtle.digest("SHA-256", xpubBytes); + let idBuffer = hashBuffer.slice(0, 8); + let idBytes = new Uint8Array(idBuffer); - return idBytes; - }; + return idBytes; +}; - DashHd.toPublic = function (_hdkey) { - let hdkey = Object.assign({}, _hdkey); - hdkey.privateKey = null; - return hdkey; - }; +DashHd.toPublic = function (_hdkey) { + let hdkey = Object.assign({}, _hdkey); + hdkey.privateKey = null; + return hdkey; +}; - DashHd.wipePrivateData = function (hdkey) { - if (hdkey.privateKey) { - Utils.secureErase(hdkey.privateKey); - } - hdkey.privateKey = null; - return hdkey; - }; - - DashHd.toPublic = function (_hdkey) { - let hdkey = Object.assign({}, _hdkey); - hdkey.privateKey = null; - return hdkey; - }; - - /** - * @param {Boolean} assertion - * @param {String} message - */ - function assert(assertion, message) { - if (!assertion) { - throw new Error(message); - } +DashHd.wipePrivateData = function (hdkey) { + if (hdkey.privateKey) { + Utils.secureErase(hdkey.privateKey); } + hdkey.privateKey = null; + return hdkey; +}; - DashHd.HARDENED_OFFSET = HARDENED_OFFSET; - - // @ts-ignore - window.DashHd = DashHd; -})(("object" === typeof window && window) || {}, DashHd); -if ("object" === typeof module) { - module.exports = DashHd; +/** + * @param {Boolean} assertion + * @param {String} message + */ +function assert(assertion, message) { + if (!assertion) { + throw new Error(message); + } } // Type Definitions @@ -801,8 +772,8 @@ if ("object" === typeof module) { /** * @typedef HDVersionsOption - * @prop {Uint32|String} [private] - 'mainnet', 'testnet', 'xprv' or 'tprv', or 4-byte hex or uint32 - * @prop {Uint32|String} [public] - 'mainnet', 'testnet', 'xpub' or 'tpub', or 4-byte hex or uint32 + * @prop {Uint32|String} private - 'mainnet', 'testnet', 'xprv' or 'tprv', or 4-byte hex or uint32 + * @prop {Uint32|String} public - 'mainnet', 'testnet', 'xpub' or 'tpub', or 4-byte hex or uint32 */ /** @@ -1053,3 +1024,34 @@ if ("object" === typeof module) { /** * @typedef {Number} Uint32 */ + +export default DashHd; // for ESM compatibility +// for NPM/CommonJS compatibility with node 22.0+ +export let CHANGE = DashHd.CHANGE; +export let HARDENED = DashHd.HARDENED; +export let HARDENED_OFFSET = DashHd.HARDENED_OFFSET; +export let MAINNET = DashHd.MAINNET; +export let PUBLIC = DashHd.PUBLIC; +export let RECEIVE = DashHd.RECEIVE; +export let TESTNET = DashHd.TESTNET; +// export let _createAccount = DashHd._createAccount; +// export let _createXKey = DashHd._createXKey; +// export let _derive = DashHd._derive; +// export let _fingerprint = DashHd._fingerprint; +// export let _toXBytes = DashHd._toXBytes; +// export let _utils = DashHd._utils; +export let create = DashHd.create; +export let deriveChild = DashHd.deriveChild; +export let derivePath = DashHd.derivePath; +export let fromSeed = DashHd.fromSeed; +export let fromXKey = DashHd.fromXKey; +export let toAddr = DashHd.toAddr; +export let toId = DashHd.toId; +export let toIdBytes = DashHd.toIdBytes; +export let toPublic = DashHd.toPublic; +export let toWif = DashHd.toWif; +export let toXPrv = DashHd.toXPrv; +export let toXPrvBytes = DashHd.toXPrvBytes; +export let toXPub = DashHd.toXPub; +export let toXPubBytes = DashHd.toXPubBytes; +export let wipePrivateData = DashHd.wipePrivateData; diff --git a/jsconfig.json b/jsconfig.json index 7ba9292..2b93cda 100644 --- a/jsconfig.json +++ b/jsconfig.json @@ -11,10 +11,10 @@ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ /* Language and Environment */ - "target": "es2022", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + "target": "es2024", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ // "jsx": "preserve", /* Specify what JSX code is generated. */ - // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ + // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ @@ -25,17 +25,27 @@ // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ /* Modules */ - "module": "commonjs", /* Specify what module code is generated. */ + "module": "nodenext", /* Specify what module code is generated. */ // "rootDir": "./", /* Specify the root folder within your source files. */ - "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ + "moduleResolution": "nodenext", /* Specify how TypeScript looks up a file from a given module specifier. */ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ - // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + "paths": { + "dashhd": ["./dashhd.js"], + "dashhd/*": ["./*"] + }, /* Specify a set of entries that re-map imports to additional lookup locations. */ // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ "typeRoots": ["./typings","./node_modules/@types"], /* Specify multiple folders that act like './node_modules/@types'. */ // "types": [], /* Specify type package names to be included without being referenced in a source file. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ + // "rewriteRelativeImportExtensions": true, /* Rewrite '.ts', '.tsx', '.mts', and '.cts' file extensions in relative import paths to their JavaScript equivalent in output files. */ + // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ + // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ + // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ + // "noUncheckedSideEffectImports": true, /* Check side effect imports. */ // "resolveJsonModule": true, /* Enable importing .json files. */ + // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ /* JavaScript Support */ @@ -48,16 +58,15 @@ // "declarationMap": true, /* Create sourcemaps for d.ts files. */ // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + "noEmit": true, /* Disable emitting files from a compilation. */ // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ // "outDir": "./", /* Specify an output folder for all emitted files. */ // "removeComments": true, /* Disable emitting comments. */ - "noEmit": true, /* Disable emitting files from a compilation. */ // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ - // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ // "newLine": "crlf", /* Set the newline character for emitting files. */ @@ -66,10 +75,11 @@ // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ - // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ /* Interop Constraints */ // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ + // "isolatedDeclarations": true, /* Require sufficient annotation on exports so other tools can trivially generate declaration files. */ // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ @@ -82,6 +92,7 @@ // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "strictBuiltinIteratorReturn": true, /* Built-in iterators are instantiated with a 'TReturn' type of 'undefined' instead of 'any'. */ // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ @@ -101,10 +112,11 @@ "skipLibCheck": true /* Skip type checking all .d.ts files. */ }, "include": [ - "*.js", - "bin/**/*.js", - "lib/**/*.js", - "src/**/*.js" -], + "*.js", + "bin/**/*.js", + "lib/**/*.js", + "src/**/*.js", + "tests/**/*.js" + ], "exclude": ["node_modules"] } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 9869f67..60a56e7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,9 +8,11 @@ "name": "dashhd", "version": "3.3.3", "license": "SEE LICENSE IN LICENSE", + "dependencies": { + "dashkeys": "^1.1.5" + }, "devDependencies": { "@dashincubator/secp256k1": "^1.7.1-5", - "dashkeys": "^1.1.3", "dashphrase": "^1.4.0", "mocha": "^10.2.0", "mocha-lcov-reporter": "0.0.1" @@ -23,10 +25,11 @@ "dev": true }, "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -78,7 +81,8 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/binary-extensions": { "version": "2.2.0", @@ -94,17 +98,19 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -212,17 +218,11 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, "node_modules/dashkeys": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dashkeys/-/dashkeys-1.1.3.tgz", - "integrity": "sha512-4GF5KA/HSJB8IWVm+duMK/FHs+k1IV40b4Cx5n7hU03yRxWqatc8KiPR6jAUpkdMELw6pz8RvDDKn/y1ubm+wQ==", - "dev": true + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/dashkeys/-/dashkeys-1.1.5.tgz", + "integrity": "sha512-ohHoe3bNeWZPsVxmOrWFaqZrJP3GeuSk6AtAawUCx0ZXVkTraeDQyMMp7ewhy3OEHkvs5yy6woMAQnwhmooX8w==", + "license": "SEE LICENSE IN LICENSE" }, "node_modules/dashphrase": { "version": "1.4.0", @@ -231,12 +231,13 @@ "dev": true }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "dev": true, + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -247,12 +248,6 @@ } } }, - "node_modules/debug/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/decamelize": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", @@ -266,10 +261,11 @@ } }, "node_modules/diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" } @@ -302,10 +298,11 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -342,7 +339,8 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/fsevents": { "version": "2.3.2", @@ -368,20 +366,21 @@ } }, "node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "minimatch": "^5.0.1", + "once": "^1.3.0" }, "engines": { - "node": "*" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -399,28 +398,6 @@ "node": ">= 6" } }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -443,7 +420,9 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dev": true, + "license": "ISC", "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -453,7 +432,8 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/is-binary-path": { "version": "2.1.0", @@ -502,6 +482,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -571,10 +552,11 @@ } }, "node_modules/minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -583,32 +565,32 @@ } }, "node_modules/mocha": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", - "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", - "dev": true, - "dependencies": { - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.4", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.2.0", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "5.0.1", - "ms": "2.1.3", - "nanoid": "3.3.3", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "workerpool": "6.2.1", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.8.2.tgz", + "integrity": "sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-colors": "^4.1.3", + "browser-stdout": "^1.3.1", + "chokidar": "^3.5.3", + "debug": "^4.3.5", + "diff": "^5.2.0", + "escape-string-regexp": "^4.0.0", + "find-up": "^5.0.0", + "glob": "^8.1.0", + "he": "^1.2.0", + "js-yaml": "^4.1.0", + "log-symbols": "^4.1.0", + "minimatch": "^5.1.6", + "ms": "^2.1.3", + "serialize-javascript": "^6.0.2", + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^6.5.1", + "yargs": "^16.2.0", + "yargs-parser": "^20.2.9", + "yargs-unparser": "^2.0.0" }, "bin": { "_mocha": "bin/_mocha", @@ -616,10 +598,6 @@ }, "engines": { "node": ">= 14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mochajs" } }, "node_modules/mocha-lcov-reporter": { @@ -637,18 +615,6 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, - "node_modules/nanoid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", - "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", - "dev": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -663,6 +629,7 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, + "license": "ISC", "dependencies": { "wrappy": "1" } @@ -706,15 +673,6 @@ "node": ">=8" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", @@ -732,6 +690,7 @@ "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "^5.1.0" } @@ -775,13 +734,15 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "randombytes": "^2.1.0" } @@ -844,6 +805,7 @@ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -852,10 +814,11 @@ } }, "node_modules/workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", - "dev": true + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", + "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", + "dev": true, + "license": "Apache-2.0" }, "node_modules/wrap-ansi": { "version": "7.0.0", @@ -878,7 +841,8 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/y18n": { "version": "5.0.8", @@ -908,10 +872,11 @@ } }, "node_modules/yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true, + "license": "ISC", "engines": { "node": ">=10" } diff --git a/package.json b/package.json index 860f933..0f0a8dd 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,34 @@ "version": "3.3.3", "description": "Manage HD Keys from HD Wallet Seed and Extended (xprv, xpub) Key Paths. Part of $DASH Tools.", "main": "dashhd.js", + "files": [ + "dashhd.js", + "jsconfig.json" + ], + "type": "module", + "imports": { + "dashhd": "./dashhd.js", + "dashhd/": "./" + }, + "exports": { + ".": "./dashhd.js", + "./*": "./*" + }, + "scripts": { + "browser-test": "npx mochify@6 --wd -R spec", + "test": "mocha", + "unit": "mocha", + "coverage": "npx istanbul@0.4 cover ./node_modules/.bin/_mocha -- --reporter list test/*.js", + "coveralls": "npm run-script coverage && npx coveralls@3 < coverage/lcov.info", + "jshint": "npx -p jshint@2.x -- jshint -c ./.jshintrc ./*.js", + "lint": "npm run jshint && npm run tsc", + "prettier": "npx -p prettier@3.x -- prettier -w '**/*.{js,md}'", + "fmt": "npm run prettier", + "bump": "npm version -m \"chore(release): bump to v%s\"", + "tsc": "! npx -p typescript@5.x -- tsc -p ./jsconfig.json | grep '\\.js(\\d\\+,\\d\\+): error' | grep -v '\\