diff --git a/js/models/core/PrivateKey.js b/js/models/core/PrivateKey.js index 8f0643b59..110dca65b 100644 --- a/js/models/core/PrivateKey.js +++ b/js/models/core/PrivateKey.js @@ -20,13 +20,20 @@ function PrivateKey(opts) { PrivateKey.prototype.getId = function() { if (!this.id) { - var path = PublicKeyRing.ID_BRANCH; - var bip32 = this.bip.derive(path); - this.id= bip32.eckey.public.toString('hex'); + var path = PublicKeyRing.IdFullBranch(); + var idhk = this.bip.derive(path); + this.id= idhk.eckey.public.toString('hex'); } return this.id; }; +PrivateKey.prototype.deriveBIP45Branch = function() { + if (!this.bip45Branch) { + this.bip45Branch = this.bip.derive(PublicKeyRing.BIP45_PUBLIC_PREFIX); + } + return this.bip45Branch; +} + PrivateKey.fromObj = function(obj) { return new PrivateKey(obj); }; @@ -55,13 +62,11 @@ PrivateKey.prototype._getHK = function(path) { }; PrivateKey.prototype.get = function(index,isChange) { - var path = PublicKeyRing.Branch(index, isChange); + var path = PublicKeyRing.FullBranch(index, isChange); var pk = this.privateKeyCache[path]; if (!pk) { var derivedHK = this._getHK(path); pk = this.privateKeyCache[path] = derivedHK.eckey.private.toString('hex'); - } else { - //console.log('cache hit!'); } var wk = new WalletKey({network: this.network}); wk.fromObj({priv: pk}); diff --git a/js/models/core/PublicKeyRing.js b/js/models/core/PublicKeyRing.js index c76d0914d..14ae83add 100644 --- a/js/models/core/PublicKeyRing.js +++ b/js/models/core/PublicKeyRing.js @@ -36,21 +36,39 @@ function PublicKeyRing(opts) { this.copayerIds = []; } -/* - * This follow Electrum convetion, as described in - * https://bitcointalk.org/index.php?topic=274182.0 - * - * We should probably adopt the next standard once it's ready, as discussed in: - * http://sourceforge.net/p/bitcoin/mailman/message/32148600/ - * - */ -PublicKeyRing.Branch = function (index, isChange) { - // first 0 is for future use: could be copayerId. - return 'm/0/'+(isChange?1:0)+'/'+index; +/* + * Based on https://github.com/maraoz/bips/blob/master/bip-NNNN.mediawiki + * m / purpose' / cosigner_index / change / address_index + */ +var PURPOSE = 45; +var MAX_NON_HARDENED = 0x8000000 - 1; + +var SHARED_INDEX = MAX_NON_HARDENED - 0; +var ID_INDEX = MAX_NON_HARDENED - 1; + +var BIP45_PUBLIC_PREFIX = 'm/'+ PURPOSE+'\''; +PublicKeyRing.BIP45_PUBLIC_PREFIX = BIP45_PUBLIC_PREFIX; + + +PublicKeyRing.Branch = function(address_index, isChange, cosigner_index) { + var ret = 'm/'+ + (typeof cosigner_index !== 'undefined'? cosigner_index: SHARED_INDEX)+'/'+ + (isChange?1:0)+'/'+ + address_index; + return ret; }; -PublicKeyRing.ID_BRANCH = 'm/100/0/0'; +PublicKeyRing.FullBranch = function(address_index, isChange, cosigner_index) { + var sub = PublicKeyRing.Branch(address_index, isChange, cosigner_index); + sub = sub.substring(2); + return BIP45_PUBLIC_PREFIX + '/' + sub; +}; +PublicKeyRing.IdFullBranch = function() { + return PublicKeyRing.FullBranch(0, 0, ID_INDEX); +}; + + PublicKeyRing.fromObj = function (data) { if (data instanceof PublicKeyRing) { @@ -114,8 +132,7 @@ PublicKeyRing.prototype._newExtendedPublicKey = function () { }; PublicKeyRing.prototype._updateBip = function (index) { - var path = PublicKeyRing.ID_BRANCH; - var hk = this.copayersHK[index].derive(path); + var hk = this.copayersHK[index].derive(PublicKeyRing.Branch(0, 0, ID_INDEX)); this.copayerIds[index]= hk.eckey.public.toString('hex'); }; @@ -123,38 +140,34 @@ PublicKeyRing.prototype._setNicknameForIndex = function (index, nickname) { this.nicknameFor[this.copayerIds[index]] = nickname; }; -PublicKeyRing.prototype.nicknameForIndex = function (index) { +PublicKeyRing.prototype.nicknameForIndex = function(index) { return this.nicknameFor[this.copayerIds[index]]; }; -PublicKeyRing.prototype.nicknameForCopayer = function (copayerId) { +PublicKeyRing.prototype.nicknameForCopayer = function(copayerId) { return this.nicknameFor[copayerId]; }; -PublicKeyRing.prototype.addCopayer = function (newEpk, nickname) { +PublicKeyRing.prototype.addCopayer = function(newEpk, nickname) { if (this.isComplete()) - throw new Error('already have all required key:' + this.totalCopayers); - - if (!newEpk) { - newEpk = this._newExtendedPublicKey(); - } + throw new Error('PKR already has all required key:' + this.totalCopayers); this.copayersHK.forEach(function(b){ if (b.extendedPublicKeyString() === newEpk) - throw new Error('already have that key'); + throw new Error('PKR already has that key'); }); - var i=this.copayersHK.length; + var i = this.copayersHK.length; var bip = new HK(newEpk); this.copayersHK.push(bip); this._updateBip(i); if (nickname) { - this._setNicknameForIndex(i,nickname); + this._setNicknameForIndex(i, nickname); } return newEpk; }; -PublicKeyRing.prototype.getPubKeys = function (index, isChange) { +PublicKeyRing.prototype.getPubKeys = function(index, isChange) { this._checkKeys(); var path = PublicKeyRing.Branch(index, isChange); diff --git a/js/models/core/WalletFactory.js b/js/models/core/WalletFactory.js index 602d8c3a2..afd322d6f 100644 --- a/js/models/core/WalletFactory.js +++ b/js/models/core/WalletFactory.js @@ -53,14 +53,6 @@ WalletFactory.prototype.fromObj = function(obj) { console.log('## Decrypting'); //TODO var w = Wallet.fromObj(obj, this.storage, this.network, this.blockchain); w.verbose = this.verbose; - // JIC: Add our key - try { - w.publicKeyRing.addCopayer( - w.privateKey.getExtendedPublicKeyString() - ); - } catch (e) { - // No really an error, just to be sure. - } this.log('### WALLET OPENED:', w.id); return w; }; @@ -107,7 +99,9 @@ WalletFactory.prototype.create = function(opts) { requiredCopayers: requiredCopayers, totalCopayers: totalCopayers, }); - opts.publicKeyRing.addCopayer(opts.privateKey.getExtendedPublicKeyString(), opts.nickname); + opts.publicKeyRing.addCopayer( + opts.privateKey.deriveBIP45Branch().extendedPublicKeyString(), + opts.nickname); this.log('\t### PublicKeyRing Initialized'); opts.txProposals = opts.txProposals || new TxProposals({