diff --git a/README.md b/README.md index e92a9824..9429af4f 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,9 @@ LightWallet is a HD wallet that can store your private keys encrypted in the bro LightWallet is primarily intended to be a signing provider for the [Hooked Web3 provider](https://github.com/ConsenSys/hooked-web3-provider) through the `keystore` module. This allows you to have full control over your private keys while still connecting to a remote node to relay signed transactions. Moreover, the `txutils` functions can be used to construct transactions when offline, for use in e.g. air-gapped coldwallet implementations. -The default BIP32 HD derivation path is `m/0'/0'/0'/i`. + +As of version 3.0.0, the keystore default BIP32 HD derivation path is `m/44'/60'/0'/0/n`. +Previous releases defaults to `m/0'/0'/0'`. ## Security @@ -79,8 +81,9 @@ Constructor of the keystore object. The seed `seed` is encrypted with `pwDerived #### Inputs -* words: string defining a 12-word seed according to [BIP39][] +* seed: string defining a 12-word seed according to [BIP39][] * pwDerivedKey: symmetric key to encrypt the seed (Uint8Array) +* hdPathString (optional): The HD derivation path as described in [BIP44]. Defaults to `m/44'/60'/0'/0/n` since 3.0.0. ### `keystore.isDerivedKeyCorrect(pwDerivedKey)` @@ -295,6 +298,7 @@ npm run coverage [BIP39]: https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki [BIP32]: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki +[BIP44]: https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki ## License diff --git a/lib/keystore.js b/lib/keystore.js index 7ef25b84..e1c38a04 100644 --- a/lib/keystore.js +++ b/lib/keystore.js @@ -59,7 +59,7 @@ function nacl_decodeHex(msgHex) { var KeyStore = function(mnemonic, pwDerivedKey, hdPathString) { - this.defaultHdPathString = "m/0'/0'/0'"; + this.defaultHdPathString = "m/44'/60'/0'/0"; if (hdPathString === undefined) { hdPathString = this.defaultHdPathString; @@ -94,9 +94,7 @@ var KeyStore = function(mnemonic, pwDerivedKey, hdPathString) { // generateNewAddress(). The derived keys are then // `hdRoot/hdIndex`. // - // Default hdRoot is m/0'/0'/0', the overall logic is - // m/0'/Persona'/Purpose', where the 0' purpose is - // for standard Ethereum accounts. + // Default hdRoot is m/44'/60'/0'/0 var hdRoot = new Mnemonic(mnemonic).toHDPrivateKey().xprivkey; this.encHdRootPriv = KeyStore._encryptString(hdRoot, pwDerivedKey); @@ -318,12 +316,13 @@ KeyStore.deserialize = function (keystore) { throw new Error('Old version of serialized keystore. Please use KeyStore.upgradeOldSerialized() to convert it to the latest version.') } - // Create keystore + // Create keystore with old default path var keystoreX = new KeyStore(); - keystoreX.encSeed = jsonKS.encSeed; - keystoreX.encHdRootPriv = jsonKS.encHdRootPriv; - keystoreX.ksData = jsonKS.ksData; + keystoreX.encSeed = jsonKS.encSeed; + keystoreX.encHdRootPriv = jsonKS.encHdRootPriv; + keystoreX.ksData = jsonKS.ksData; + keystoreX.defaultHdPathString = jsonKS.defaultHdPathString; return keystoreX; }; @@ -334,6 +333,7 @@ KeyStore.prototype.serialize = function () { var jsonKS = {'encSeed': this.encSeed, 'ksData' : this.ksData, 'encHdRootPriv' : this.encHdRootPriv, + 'defaultHdPathString' : this.defaultHdPathString, 'version' : this.version}; return JSON.stringify(jsonKS); @@ -498,8 +498,15 @@ KeyStore.prototype.hasAddress = function (address, callback) { }; -KeyStore.prototype.signTransaction = function (txParams, callback) { +//Putting hdPath as optional argument after callback is a bit ugly, +//but makes integration of the new default path less of a hassle +//for users +KeyStore.prototype.signTransaction = function (txParams, callback, hdPathString) { + if (hdPathString === undefined) { + hdPathString = this.defaultHdPathString; + } + var ethjsTxParams = {}; ethjsTxParams.from = add0x(txParams.from); @@ -517,7 +524,7 @@ KeyStore.prototype.signTransaction = function (txParams, callback) { this.passwordProvider( function (err, password) { if (err) return callback(err); KeyStore.deriveKeyFromPassword(password, function (err, pwDerivedKey) { - var signedTx = signing.signTx(self, pwDerivedKey, rawTx, signingAddress, self.defaultHdPathString); + var signedTx = signing.signTx(self, pwDerivedKey, rawTx, signingAddress, hdPathString); callback(null, '0x' + signedTx); }) }) diff --git a/lib/upgrade.js b/lib/upgrade.js index 4e05ced0..a1b5755d 100644 --- a/lib/upgrade.js +++ b/lib/upgrade.js @@ -36,7 +36,9 @@ upgradeOldSerialized = function (oldSerialized, password, callback) { var derivedKey = legacyGenerateEncKey(password, oldKS.salt, oldKS.keyHash); var seed = legacyDecryptString(oldKS.encSeed, derivedKey); keystore.deriveKeyFromPassword(password, function(err, pwDerivedKey) { - var newKeyStore = new keystore(seed, pwDerivedKey); + var newKeyStore = new keystore(seed, pwDerivedKey, "m/0'/0'/0'"); + newKeyStore.setDefaultHdDerivationPath("m/0'/0'/0'"); + var hdIndex = oldKS.hdIndex; newKeyStore.generateNewAddress(pwDerivedKey, hdIndex); diff --git a/package.json b/package.json index 5b65cb91..738cbe96 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eth-lightwallet", - "version": "2.3.0", + "version": "3.0.0", "description": "A lightweight ethereum javascript wallet.", "main": "index.js", "repository": { diff --git a/test/fixtures/keystore.json b/test/fixtures/keystore.json index 1acd00c1..ef78aaee 100644 --- a/test/fixtures/keystore.json +++ b/test/fixtures/keystore.json @@ -43,7 +43,13 @@ "70d505a34e1ff438a6e0fca3ba37ba8e3c7d7b9843a5762b45d3be9e4d38633f", "7c2864ef868146251c881d2cb4e92cab3a1868bb3fc49b233a4471dcb1bc050e", "9c493f840b54cb4d48c1dbc8dacf4b7fa6a471e4f462eae3f64ebf10fcd9430c", - "170023f3a4ef99ae36f97bfedb8e55be277755a2b1b8caa35067cfe93e467b1d" ]} + "170023f3a4ef99ae36f97bfedb8e55be277755a2b1b8caa35067cfe93e467b1d" ]}, + + "m/44/66/0'/0" : {"addresses" : ["627ac4c2d731e12fb386bd649114a08ebcc0c33f", + "28ad3648ab755e505af7f07c9e8aa2ed70676c6d", + "623c0fa7a6bb3ceabb56b6d6d034fc12cb835f0b", + "17820c2129aa8d0b5c05e66d467b5fe6c1da6551", + "5c52998d98cf4c38a6301b6739b242d05a7dee19"]} }, diff --git a/test/keystore.js b/test/keystore.js index 529a24c0..f943ff9b 100644 --- a/test/keystore.js +++ b/test/keystore.js @@ -168,20 +168,33 @@ describe("Keystore", function() { var N = fixtures.valid.length; - it("returns a new address, next in hd wallet", function(done) { + it("returns a new address with path m/0'/0'/0', next in hd wallet", function(done) { this.timeout(10000); + var hdPath = "m/0'/0'/0'"; for (var i=0; i