BIP32 PrivateKey wrapper

This commit is contained in:
Matias Alejo Garcia 2014-04-09 20:37:14 -03:00
parent 1caea99917
commit 972ffb34b6
5 changed files with 114 additions and 35 deletions

View File

@ -3,4 +3,5 @@ module.exports.Storage = require('./js/models/Storage');
module.exports.PublicKeyRing = require('./js/models/PublicKeyRing'); module.exports.PublicKeyRing = require('./js/models/PublicKeyRing');
module.exports.TxProposals = require('./js/models/TxProposals'); module.exports.TxProposals = require('./js/models/TxProposals');
module.exports.CopayPeer = require('./js/models/CopayPeer'); module.exports.CopayPeer = require('./js/models/CopayPeer');
module.exports.PrivateKey = require('./js/models/PrivateKey');
module.exports.FakeStorage = require('./test/FakeStorage'); module.exports.FakeStorage = require('./test/FakeStorage');

35
js/models/PrivateKey.js Normal file
View File

@ -0,0 +1,35 @@
'use strict';
var imports = require('soop').imports();
var bitcore = require('bitcore');
var BIP32 = bitcore.BIP32;
var WalletKey = bitcore.WalletKey;
var networks = bitcore.networks;
var PublicKeyRing = require('./PublicKeyRing');
function PrivateKey(opts) {
this.id = opts.id;
this.network = opts.networkName === 'testnet' ?
networks.testnet : networks.livenet;
this.BIP32 = opts.BIP32 || new BIP32(this.network.name);
};
PrivateKey.prototype.getBIP32 = function(index,isChange) {
if (typeof index === 'undefined') {
return this.BIP32;
}
return this.BIP32.derive( isChange ?
PublicKeyRing.ChangeBranch(index):PublicKeyRing.PublicBranch(index) );
};
PrivateKey.prototype.get = function(index,isChange) {
var derivedBIP32 = this.getBIP32(index,isChange);
var wk = new WalletKey({network: this.network});
var p = derivedBIP32.eckey.private.toString('hex');
wk.fromObj({priv: p});
return wk;
};
module.exports = require('soop')(PrivateKey);

View File

@ -12,17 +12,13 @@ var buffertools = bitcore.buffertools;
var Storage = imports.Storage || require('./Storage'); var Storage = imports.Storage || require('./Storage');
var storage = Storage.default(); var storage = Storage.default();
/* function TxProposal(opts) {
* This follow Electrum convetion, as described in this.tx = opts.tx;
* https://bitcointalk.org/index.php?topic=274182.0 this.seenBy = {};
* this.signedBy = {};
* We should probably adopt the next standard once it's ready, as discussed in: };
* http://sourceforge.net/p/bitcoin/mailman/message/32148600/ module.exports = require('soop')(TxProposal);
*
*/
var PUBLIC_BRANCH = 'm/0/';
var CHANGE_BRANCH = 'm/1/';
function TxProposals(opts) { function TxProposals(opts) {
opts = opts || {}; opts = opts || {};
@ -36,9 +32,9 @@ function TxProposals(opts) {
this.dirty = 1; this.dirty = 1;
} }
TxProposals.prototype.list = function() { TxProposals.prototype.list = function() {
var ret = []; var ret = [];
var ret = [];
this.txs.forEach(function(tx) { this.txs.forEach(function(tx) {
}); });
@ -66,9 +62,16 @@ TxProposals.prototype.create = function(toAddress, amountSat, utxos, onePrivKey)
} }
var tx = b.build(); var tx = b.build();
var txHex = tx.serialize(); this.txs.push(
this.txs.push(txHex); new TxProposal({
return txHex; signedBy: {
},
seenBy: {
},
tx: tx
})
);
return tx;
}; };
TxProposals.prototype.sign = function(index) { TxProposals.prototype.sign = function(index) {

50
test/test.PrivateKey.js Normal file
View File

@ -0,0 +1,50 @@
'use strict';
var chai = chai || require('chai');
var should = chai.should();
var bitcore = bitcore || require('bitcore');
var Transaction = bitcore.Transaction;
var buffertools = bitcore.buffertools;
var WalletKey = bitcore.WalletKey;
var Key = bitcore.Key;
var BIP32 = bitcore.BIP32;
var bignum = bitcore.bignum;
var networks = bitcore.networks;
var Address = bitcore.Address;
var BitcorePrivateKey = bitcore.PrivateKey;
var copay = copay || require('../copay');
var PrivateKey = copay.PrivateKey || require('../js/models/PrivateKey');
var config = {
networkName:'livenet',
};
describe('PrivateKey model', function() {
it('should create an instance', function () {
var w = new PrivateKey(config);
should.exist(w);
should.exist(w.BIP32);
should.exist(w.BIP32.derive);
});
it('should derive priv keys', function () {
var w = new PrivateKey(config);
for(var j=0; j<2; j++) {
for(var i=0; i<3; i++) {
var wk = w.get(i,j);
should.exist(wk);
var o=wk.storeObj();
should.exist(o);
should.exist(o.priv);
should.exist(o.pub);
should.exist(o.addr);
var a = new Address(o.addr);
a.isValid().should.equal(true);
(function() {
var p = new PrivateKey(o.priv)
}).should.not.throw();
}
}
});
});

View File

@ -12,6 +12,7 @@ var bignum = bitcore.bignum;
var networks = bitcore.networks; var networks = bitcore.networks;
var copay = copay || require('../copay'); var copay = copay || require('../copay');
var fakeStorage = copay.FakeStorage; var fakeStorage = copay.FakeStorage;
var PrivateKey = copay.PrivateKey || require('../js/models/PrivateKey');
var TxProposals = copay.TxProposals || require('../js/models/TxProposal'); var TxProposals = copay.TxProposals || require('../js/models/TxProposal');
var PublicKeyRing = (typeof process.versions === 'undefined') ? copay.PublicKeyRing : var PublicKeyRing = (typeof process.versions === 'undefined') ? copay.PublicKeyRing :
require('soop').load('../js/models/PublicKeyRing', {Storage: fakeStorage}); require('soop').load('../js/models/PublicKeyRing', {Storage: fakeStorage});
@ -74,25 +75,21 @@ describe('TxProposals model', function() {
unspentTest[0].address = w.publicKeyRing.getAddress(1, true); unspentTest[0].address = w.publicKeyRing.getAddress(1, true);
unspentTest[0].scriptPubKey = w.publicKeyRing.getRedeemScript(1, true).getBuffer(); unspentTest[0].scriptPubKey = w.publicKeyRing.getRedeemScript(1, true).getBuffer();
var txHex = w.create( var tx = w.create(
'15q6HKjWHAksHcH91JW23BJEuzZgFwydBt', '15q6HKjWHAksHcH91JW23BJEuzZgFwydBt',
bignum('123456789'), bignum('123456789'),
unspentTest unspentTest
); );
should.exist(txHex); should.exist(tx);
tx.isComplete().should.equal(false);
var t2=new Transaction();
t2.parse(txHex);
t2.isComplete().should.equal(false);
}); });
it('#create. Singing with derivate keys', function () { it('#create. Singing with derivate keys', function () {
var oneBIP32 = new BIP32(config.networkName); var priv = new PrivateKey(config);
var w = new TxProposals({ var w = new TxProposals({
networkName: config.networkName, networkName: config.networkName,
publicKeyRing: createW([oneBIP32]), publicKeyRing: createW([priv.getBIP32()]),
}); });
should.exist(w); should.exist(w);
w.network.name.should.equal('livenet'); w.network.name.should.equal('livenet');
@ -103,22 +100,15 @@ describe('TxProposals model', function() {
unspentTest[0].address = w.publicKeyRing.getAddress(index, isChange); unspentTest[0].address = w.publicKeyRing.getAddress(index, isChange);
unspentTest[0].scriptPubKey = w.publicKeyRing.getRedeemScript(index, isChange).getBuffer(); unspentTest[0].scriptPubKey = w.publicKeyRing.getRedeemScript(index, isChange).getBuffer();
var derivedBip32 = oneBIP32.derive( isChange ? PublicKeyRing.ChangeBranch(index):PublicKeyRing.PublicBranch(index) ); var tx = w.create(
var wk = new WalletKey({network: networks.livenet});
var p = derivedBip32.eckey.private.toString('hex');
wk.fromObj({priv: p});
var txHex = w.create(
'15q6HKjWHAksHcH91JW23BJEuzZgFwydBt', '15q6HKjWHAksHcH91JW23BJEuzZgFwydBt',
bignum('123456789'), bignum('123456789'),
unspentTest, unspentTest,
wk priv.get(index,isChange)
); );
should.exist(txHex); should.exist(tx);
var t2=new Transaction(); tx.isComplete().should.equal(false);
t2.parse(txHex); tx.countInputMissingSignatures(0).should.equal(2);
t2.isComplete().should.equal(false);
t2.countInputMissingSignatures(0).should.equal(2);
} }
} }