From 74925995520ed151ffd3357151f3ade651c6165b Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Fri, 4 Apr 2014 17:16:10 -0300 Subject: [PATCH] public key ring, symmetric for all holders --- js/models/PublicKeyRing.js | 88 ++++++++++++++++++++------------------ test/test.publickeyring.js | 32 +++++--------- 2 files changed, 57 insertions(+), 63 deletions(-) diff --git a/js/models/PublicKeyRing.js b/js/models/PublicKeyRing.js index fd29e26c8..a078c51f3 100644 --- a/js/models/PublicKeyRing.js +++ b/js/models/PublicKeyRing.js @@ -1,4 +1,7 @@ + 'use strict'; + + var imports = require('soop').imports(); var bitcore = require('bitcore'); var BIP32 = bitcore.BIP32; @@ -25,7 +28,6 @@ var storage = Storage.default(); var PUBLIC_BRANCH = 'm/0/'; var CHANGE_BRANCH = 'm/1/'; - function PublicKeyRing(opts) { opts = opts || {}; @@ -38,8 +40,7 @@ function PublicKeyRing(opts) { this.id = opts.id || PublicKeyRing.getRandomId(); this.dirty = 1; - this.copayersWallets = []; - this.bip32 = new BIP32(opts.bytes || this.network.name); + this.copayersBIP32 = []; this.changeAddressIndex=0; this.addressIndex=0; @@ -83,8 +84,10 @@ PublicKeyRing.read = function (id, passphrase) { w.requiredCopayers = data.neededCopayers; w.totalCopayers = data.totalCopayers; - w.copayersWallets = data.copayersExtPubKeys.map( function (pk) { - return new PublicKeyRing({bytes:pk, network: w.network.name}); + +// this.bip32 = ; + w.copayersBIP32 = data.copayersExtPubKeys.map( function (pk) { + return new BIP32(pk); }); w.dirty = 0; @@ -98,12 +101,13 @@ PublicKeyRing.prototype.serialize = function () { network: this.network.name, requiredCopayers: this.neededCopayers, totalCopayers: this.totalCopayers, - copayersExtPubKeys: this.copayersWallets.map( function (b) { - return b.getMasterExtendedPubKey(); + copayersExtPubKeys: this.copayersBIP32.map( function (b) { + return b.extendedPublicKeyString(); }), }); }; + PublicKeyRing.prototype.store = function (passphrase) { if (!this.id) @@ -116,16 +120,9 @@ PublicKeyRing.prototype.store = function (passphrase) { }; PublicKeyRing.prototype.registeredCopayers = function () { - if (! this.copayersWallets) return 1; - - - // 1 is self. - return 1 + this.copayersWallets.length; + return this.copayersBIP32.length; }; -PublicKeyRing.prototype.getMasterExtendedPubKey = function () { - return this.bip32.extendedPublicKeyString(); -}; PublicKeyRing.prototype.haveAllRequiredPubKeys = function () { @@ -139,62 +136,69 @@ PublicKeyRing.prototype._checkKeys = function() { }; -// should receive an array also? -PublicKeyRing.prototype.addCopayerExtendedPubKey = function (newEpk) { +PublicKeyRing.prototype._newExtendedPublicKey = function () { + return new BIP32(this.network.name) + .extendedPublicKeyString(); +}; + +PublicKeyRing.prototype.addCopayer = function (newEpk) { if (this.haveAllRequiredPubKeys()) throw new Error('already have all required key:' + this.totalCopayers); - if (this.getMasterExtendedPubKey() === newEpk) - throw new Error('already have that key (self key)'); + if (!newEpk) { + newEpk = this._newExtendedPublicKey(); + } - - this.copayersWallets.forEach(function(b){ - if (b.getMasterExtendedPubKey() === newEpk) + this.copayersBIP32.forEach(function(b){ + if (b.extendedPublicKeyString() === newEpk) throw new Error('already have that key'); }); - this.copayersWallets.push(new PublicKeyRing({bytes:newEpk, network: this.network.name } )); + this.copayersBIP32.push(new BIP32(newEpk)); this.dirty = 1; + return newEpk; }; -PublicKeyRing.prototype.getPubKey = function (index,isChange) { - - var path = (isChange ? CHANGE_BRANCH : PUBLIC_BRANCH) + index; - var bip32 = this.bip32.derive(path); - var pub = bip32.eckey.public; - return pub; -}; - PublicKeyRing.prototype.getCopayersPubKeys = function (index, isChange) { this._checkKeys(); var pubKeys = []; - var l = this.copayersWallets.length; + var l = this.copayersBIP32.length; for(var i=0; i this.changeAddressIndex) - || (!isChange && index > this.addressIndex)) { +PublicKeyRing.prototype._checkIndexRange = function (index, isChange) { + if ( (isChange && index > this.changeAddressIndex) || + (!isChange && index > this.addressIndex)) { log('Out of bounds at getAddress: Index %d isChange: %d', index, isChange); throw new Error('index out of bound'); } +}; + +PublicKeyRing.prototype.getRedeemScript = function (index, isChange) { + this._checkIndexRange(index, isChange); var pubKeys = this.getCopayersPubKeys(); - var version = this.network.addressScript; var script = Script.createMultisig(this.requiredCopayers, pubKeys); - var buf = script.buffer; - var hash = coinUtil.sha256ripe160(buf); + return script; +}; + +PublicKeyRing.prototype.getAddress = function (index, isChange) { + this._checkIndexRange(index, isChange); + + var script = this.getRedeemScript(index,isChange); + var hash = coinUtil.sha256ripe160(script.getBuffer()); + var version = this.network.addressScript; var addr = new Address(version, hash); - var addrStr = addr.as('base58'); - return addrStr; + return addr.as('base58'); }; //generate a new address, update index. diff --git a/test/test.publickeyring.js b/test/test.publickeyring.js index 1648ef613..38c992905 100644 --- a/test/test.publickeyring.js +++ b/test/test.publickeyring.js @@ -16,24 +16,20 @@ var config = { network:'livenet', }; -var createW = function (network, bytes) { +var createW = function (network) { var config = { network: network || 'livenet', }; - if (bytes) config.bytes = bytes; var w = new PublicKeyRing(config); should.exist(w); var copayers = []; - for(var i=0; i<4; i++) { - delete config['bytes']; - var c = new PublicKeyRing(config); + for(var i=0; i<5; i++) { w.haveAllRequiredPubKeys().should.equal(false); - - w.addCopayerExtendedPubKey(c.getMasterExtendedPubKey()); - copayers.push(c); + var newEpk = w.addCopayer(); + copayers.push(newEpk); } return {w:w, copayers: copayers}; @@ -54,17 +50,11 @@ describe('PublicKeyRing model', function() { w2.network.name.should.equal('testnet'); }); - it('should create an master pub key', function () { - var w2 = new PublicKeyRing(config); - should.exist(w2); - should.exist(w2.getMasterExtendedPubKey()); - }); - it('should fail to generate shared pub keys wo extended key', function () { var w2 = new PublicKeyRing(config); should.exist(w2); - w2.registeredCopayers().should.equal(1); + w2.registeredCopayers().should.equal(0); w2.haveAllRequiredPubKeys().should.equal(false); w2.getAddress.bind(false).should.throw(); @@ -76,9 +66,9 @@ describe('PublicKeyRing model', function() { var copayers = k.copayers; w.haveAllRequiredPubKeys().should.equal(true); - w.addCopayerExtendedPubKey.bind(w.getMasterExtendedPubKey()).should.throw(); - w.addCopayerExtendedPubKey.bind(copayers[0].getMasterExtendedPubKey()).should.throw(); - w.addCopayerExtendedPubKey.bind((new PublicKeyRing(config)).getMasterExtendedPubKey()).should.throw(); + w.addCopayer.bind().should.throw(); + for(var i =0; i<5; i++) + w.addCopayer.bind(copayers[i]).should.throw(); }); it('show be able to store and retrieve', function () { @@ -93,9 +83,9 @@ describe('PublicKeyRing model', function() { var w2 = PublicKeyRing.read(ID); w2.haveAllRequiredPubKeys().should.equal(true); - w2.addCopayerExtendedPubKey.bind(w.getMasterExtendedPubKey()).should.throw(); - w2.addCopayerExtendedPubKey.bind(copayers[0].getMasterExtendedPubKey()).should.throw(); - w2.addCopayerExtendedPubKey.bind((new PublicKeyRing(config)).getMasterExtendedPubKey()).should.throw(); + w2.addCopayer.bind().should.throw(); + for(var i =0; i<5; i++) + w2.addCopayer.bind(copayers[i]).should.throw(); });