From 0a9b9b97f90df85c58b1e900f4a15cfdb509c4f2 Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Thu, 20 Jul 2023 11:59:02 -0600 Subject: [PATCH 1/5] feat+doc: expose toPublic and document wipePrivateData --- README.md | 18 ++++++++++++++++++ dashhd.js | 13 +++++++++++++ 2 files changed, 31 insertions(+) diff --git a/README.md b/README.md index a8c853e..9b67f77 100644 --- a/README.md +++ b/README.md @@ -239,6 +239,8 @@ However, production code will look more like this: RECEIVE, CHANGE async fromSeed(seedBytes, opts) // depth-0 hdkey (Wallet) async fromXKey(xprv||xpub, opts) // depth-4 hdkey (XKey) + async toPublic(xKey) + async wipePrivateData(xKey) async toWif(privBytes, opts) async toAddr(pubBytes, opts) async toXPrv(xprvKey, opts) @@ -415,6 +417,22 @@ let xkey = await DashHd.fromXKey(xprvOrXPub, options); } ``` +### `toPublic(xkey)` + +Creates a copy of the HD Key with `privateKey` set to `null`. + +```js +let xpubKey = await DashHd.toPublic(xprvKey); +``` + +### `wipePrivateData(xkey)` + +Performs an in-place secure erase of the private key memory. + +```js +await DashHd.wipePrivateData(xprvKey); +``` + ### `toWif(privBytes, opts)` Wrapper around `DashKeys.encodeKey(keyBytes, options)` to Base58Check-encode a diff --git a/dashhd.js b/dashhd.js index 04d84c0..8fea4b0 100644 --- a/dashhd.js +++ b/dashhd.js @@ -14,6 +14,7 @@ * @prop {HDToXKeyBytes} toXPubBytes * @prop {HDUtils} utils * @prop {HDWipePrivates} wipePrivateData - randomizes private key buffer in-place + * @prop {HDToPublic} toPublic - returns public key * @prop {Number} HARDENED_OFFSET - 0x80000000 * @prop {HDVersions} MAINNET - 'xprv' & 'xpub' * @prop {HDVersions} TESTNET - 'tprv' & 'tpub' @@ -651,6 +652,12 @@ var DashHd = ("object" === typeof module && exports) || {}; 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); @@ -908,6 +915,12 @@ if ("object" === typeof module) { * @param {Uint8Array} buf */ +/** + * @callback HDToPublic + * @param {HDKey} hdkey + * @returns {HDKey} + */ + /** * @callback HDWipePrivates * @param {HDKey} hdkey From 9d4fa0e9a74c540737768ac05a8746ea4f130c72 Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Thu, 20 Jul 2023 11:47:34 -0600 Subject: [PATCH 2/5] feat: implement HDKey ID --- dashhd.js | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/dashhd.js b/dashhd.js index 8fea4b0..db2b488 100644 --- a/dashhd.js +++ b/dashhd.js @@ -6,6 +6,8 @@ * @prop {HDFingerprint} _fingerprint * @prop {HDFromSeed} fromSeed * @prop {HDFromXKey} fromXKey + * @prop {HDToId} toId + * @prop {HDToIdBytes} toIdBytes * @prop {HDToAddr} toAddr * @prop {HDToWif} toWif * @prop {HDToXPrv} toXPrv @@ -36,6 +38,7 @@ * @prop {HDHasher} ripemd160sum * @prop {HDHasher} sha256sum * @prop {HDHasher} sha512hmac + * @prop {HDBase64Url} bytesToBase64Url * @prop {HDKeyToKey} toPublicKey */ @@ -219,6 +222,23 @@ var DashHd = ("object" === typeof module && exports) || {}; 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); + } + + 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) { if (!Crypto.getRandomValues) { @@ -652,6 +672,23 @@ var DashHd = ("object" === typeof module && exports) || {}; return hdkey; }; + DashHd.toId = async function (hdkey) { + let idBytes = await DashHd.toIdBytes(hdkey); + let id = Utils.bytesToBase64Url(idBytes); + + return id; + }; + + 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); + + return idBytes; + }; + DashHd.toPublic = function (_hdkey) { let hdkey = Object.assign({}, _hdkey); hdkey.privateKey = null; @@ -835,6 +872,18 @@ if ("object" === typeof module) { * @returns {Promise} */ +/** + * @callback HDToId + * @param {HDKey} hdkey + * @returns {Promise} + */ + +/** + * @callback HDToIdBytes + * @param {HDKey} hdkey + * @returns {Promise} + */ + /** * @callback HDToXKeyBytes * @param {HDKey} hdkey @@ -878,6 +927,12 @@ if ("object" === typeof module) { * @returns {Promise} */ +/** + * @callback HDBase64Url + * @param {Uint8Array} bytes + * @returns {String} - URL-Safe Base64 Encoding + */ + /** * @callback HDHasher * @param {Uint8Array} bytes From 7be29831d43f362d681b50b2ae3f7228c564b95e Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Thu, 20 Jul 2023 11:48:13 -0600 Subject: [PATCH 3/5] ref: expose private-ish utils for debugging --- dashhd.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dashhd.js b/dashhd.js index db2b488..24e5e56 100644 --- a/dashhd.js +++ b/dashhd.js @@ -269,6 +269,8 @@ var DashHd = ("object" === typeof module && exports) || {}; 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 }; From d0b70ab3f6403f6ac24d2925703eac6a24b457eb Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Thu, 20 Jul 2023 12:03:32 -0600 Subject: [PATCH 4/5] chore(release): bump to v3.2.0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9723bc3..af1ace6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "dashhd", - "version": "3.1.0", + "version": "3.2.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "dashhd", - "version": "3.1.0", + "version": "3.2.0", "license": "SEE LICENSE IN LICENSE", "dependencies": { "dashkeys": "^1.0.0" diff --git a/package.json b/package.json index d806595..2309cb7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dashhd", - "version": "3.1.0", + "version": "3.2.0", "description": "Manage HD Keys from HD Wallet Seed and Extended (xprv, xpub) Key Paths. Part of $DASH Tools.", "main": "dashhd.js", "browser": { From 570d5af24442b1a61dc3ce6fabb3e4fa9b8048ea Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Thu, 20 Jul 2023 11:59:02 -0600 Subject: [PATCH 5/5] feat+doc: expose toPublic and document wipePrivateData --- dashhd.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dashhd.js b/dashhd.js index 24e5e56..60f35e4 100644 --- a/dashhd.js +++ b/dashhd.js @@ -705,6 +705,12 @@ var DashHd = ("object" === typeof module && exports) || {}; return hdkey; }; + DashHd.toPublic = function (_hdkey) { + let hdkey = Object.assign({}, _hdkey); + hdkey.privateKey = null; + return hdkey; + }; + /** * @param {Boolean} assertion * @param {String} message