From c818b549c633f87655cc7a877caeaa4755a9a693 Mon Sep 17 00:00:00 2001 From: olalonde Date: Mon, 21 Apr 2014 03:52:07 +0800 Subject: [PATCH 1/5] Added Electrum.js which allows Electrum style key derivation --- examples/ElectrumMPK.js | 20 ++++++++++++++++ lib/Electrum.js | 51 +++++++++++++++++++++++++++++++++++++++++ src/eckey.cc | 1 + 3 files changed, 72 insertions(+) create mode 100644 examples/ElectrumMPK.js create mode 100644 lib/Electrum.js diff --git a/examples/ElectrumMPK.js b/examples/ElectrumMPK.js new file mode 100644 index 0000000..8375fd8 --- /dev/null +++ b/examples/ElectrumMPK.js @@ -0,0 +1,20 @@ +var Key = require('../lib/Key'); +var Address = require('../lib/Address'); +var k = new Key(); + +//k.public = new Buffer('92eea4d2f5263651db9e3222caded1fd4c89772f79a7c03fb6afc00e9d2c9d2ed9b86c2c95fc1171e49163079dacb7f048b3c509a27a490e1df9e7128362d468', 'hex'); +//k.public = new Buffer('0492eea4d2f5263651db9e3222caded1fd4c89772f79a7c03fb6afc00e9d2c9d2ed9b86c2c95fc1171e49163079dacb7f048b3c509a27a490e1df9e7128362d468', 'hex'); +//k.public = new Buffer('0478d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71a1518063243acd4dfe96b66e3f2ec8013c8e072cd09b3834a19f81f659cc3455', 'hex'); +//k.generatePubKey(); +//debugger; +//console.log(k); + +var Electrum = require('../lib/Electrum'); +//92eea4d2f5263651db9e3222caded1fd4c89772f79a7c03fb6afc00e9d2c9d2ed9b86c2c95fc1171e49163079dacb7f048b3c509a27a490e1df9e7128362d468 +var mpk = '92eea4d2f5263651db9e3222caded1fd4c89772f79a7c03fb6afc00e9d2c9d2ed9b86c2c95fc1171e49163079dacb7f048b3c509a27a490e1df9e7128362d468'; +mpk = new Electrum(mpk); + +var key1 = mpk.generatePubKey(0); +var addr1 = Address.fromPubKey(key1); + +console.log(addr1.as('base58')); diff --git a/lib/Electrum.js b/lib/Electrum.js new file mode 100644 index 0000000..58822a2 --- /dev/null +++ b/lib/Electrum.js @@ -0,0 +1,51 @@ +var Key = require('./Key'), + Point = require('./Point'), + twoSha256 = require('../util').twoSha256, + buffertools = require('buffertools'), + bignum = require('bignum'); + +/** + * Pre-BIP32 Electrum public key derivation (electrum <2.0) + * + * @example examples/ElectrumMPK.js + */ +function Electrum (master_public_key) { + this.mpk = new Buffer(master_public_key, 'hex'); +} + +Electrum.prototype.getSequence = function (for_change, n) { + var mode = for_change ? 1 : 0; + var buf = Buffer.concat([ new Buffer(n + ':' + mode + ':', 'utf8'), this.mpk ]); + return bignum.fromBuffer(twoSha256(buf)); +}; + +Electrum.prototype.generatePubKey = function (n, for_change) { + var x = bignum.fromBuffer(this.mpk.slice(0, 32), { size: 32 }); + var y = bignum.fromBuffer(this.mpk.slice(32, 64), { size: 32 }); + var mpk_pt = new Point(x, y); + + var sequence = this.getSequence(false, n); + var sequence_key = new Key(); + sequence_key.private = sequence.toBuffer(); + sequence_key.regenerateSync(); + + var sequence_pt = Point.fromKey(sequence_key); + + pt = Point.add(mpk_pt, sequence_pt); + + var xbuf = pt.x.toBuffer({ size: 32 }); + var ybuf = pt.y.toBuffer({ size: 32 }); + var prefix = new Buffer([0x04]); + + var key = new Key(); + key.compressed = false; + key.public = Buffer.concat([prefix, xbuf, ybuf]); + + return key.public; +}; + +Electrum.prototype.generateChangePubKey = function (sequence) { + return this.generatePubKey(sequence, true); +}; + +module.exports = Electrum; diff --git a/src/eckey.cc b/src/eckey.cc index 4199368..8f279a6 100644 --- a/src/eckey.cc +++ b/src/eckey.cc @@ -317,6 +317,7 @@ Key::SetPublic(Local property, Local value, const AccessorInfo& i if (!ret) { // TODO: Error + VException("Invalid public key."); return; } From 7466d916f1b6ed8d1d29c01ddb4ad7619610aa98 Mon Sep 17 00:00:00 2001 From: olalonde Date: Mon, 21 Apr 2014 03:53:54 +0800 Subject: [PATCH 2/5] Electrum.js specified what is supported for now --- lib/Electrum.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/Electrum.js b/lib/Electrum.js index 58822a2..e108690 100644 --- a/lib/Electrum.js +++ b/lib/Electrum.js @@ -7,6 +7,9 @@ var Key = require('./Key'), /** * Pre-BIP32 Electrum public key derivation (electrum <2.0) * + * For now, this class can only understands master public keys. + * It doesn't support derivation from a private master key (TODO). + * * @example examples/ElectrumMPK.js */ function Electrum (master_public_key) { From 2644dbb2db67ee538eb7cf63cf33d5e0e984c168 Mon Sep 17 00:00:00 2001 From: olalonde Date: Mon, 21 Apr 2014 04:21:33 +0800 Subject: [PATCH 3/5] Electrum.js: wrote some tests --- bitcore.js | 1 + lib/Electrum.js | 2 +- test/test.Electrum.js | 78 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 test/test.Electrum.js diff --git a/bitcore.js b/bitcore.js index 4e2b370..aa0de4b 100644 --- a/bitcore.js +++ b/bitcore.js @@ -49,6 +49,7 @@ requireWhenAccessed('Wallet', './lib/Wallet'); requireWhenAccessed('WalletKey', './lib/WalletKey'); requireWhenAccessed('PeerManager', './lib/PeerManager'); requireWhenAccessed('Message', './lib/Message'); +requireWhenAccessed('Electrum', './lib/Electrum'); module.exports.Buffer = Buffer; if (typeof process.versions === 'undefined') { diff --git a/lib/Electrum.js b/lib/Electrum.js index e108690..1cf499e 100644 --- a/lib/Electrum.js +++ b/lib/Electrum.js @@ -27,7 +27,7 @@ Electrum.prototype.generatePubKey = function (n, for_change) { var y = bignum.fromBuffer(this.mpk.slice(32, 64), { size: 32 }); var mpk_pt = new Point(x, y); - var sequence = this.getSequence(false, n); + var sequence = this.getSequence(for_change, n); var sequence_key = new Key(); sequence_key.private = sequence.toBuffer(); sequence_key.regenerateSync(); diff --git a/test/test.Electrum.js b/test/test.Electrum.js new file mode 100644 index 0000000..8e82c18 --- /dev/null +++ b/test/test.Electrum.js @@ -0,0 +1,78 @@ +'use strict'; + +var chai = chai || require('chai'); +var bitcore = bitcore || require('../bitcore'); + +var should = chai.should(); + +var Electrum = bitcore.Electrum; +var Address = bitcore.Address; +var mpk = '92eea4d2f5263651db9e3222caded1fd4c89772f79a7c03fb6afc00e9d2c9d2ed9b86c2c95fc1171e49163079dacb7f048b3c509a27a490e1df9e7128362d468'; + +/** + * The hard coded values (expected public key / address hash) were retrieved + * by creating an Electrum wallet and looking which addresses were generated for + * master public key mpk. Not very rigorous but it will help catch regressions. + */ +describe('Electrum', function() { + it('should initialze the main object', function() { + should.exist(Electrum); + }); + it('should be able to create instance', function() { + var elec = new Electrum(mpk); + should.exist(elec); + }); + it('should be able to call generatePubKey', function() { + var elec = new Electrum(mpk); + (function () { + elec.generatePubKey(0); + }).should.not.throw(Error); + }); + it('should be able to call generateChangePubKey', function() { + var elec = new Electrum(mpk); + (function () { + elec.generateChangePubKey(0); + }).should.not.throw(Error); + }); + it('should generate correct public key at sequence 0', function() { + var elec = new Electrum(mpk); + var pubkey = elec.generatePubKey(0); + var addr = Address.fromPubKey(pubkey); + addr.as('base58').should.equal('15Ur7LV4hZFvFYQHkB12g1mdnKuHyHBDiW'); + }); + it('should generate correct (change) public keys at sequence 0,1,2', function() { + var expected_values = { + receiving: [ + '15Ur7LV4hZFvFYQHkB12g1mdnKuHyHBDiW', + '19K48MhyXK4qChGCUJzAHxLFjbQRg9tb9F', + '1EfoxVmRVzYf1a1WELv2qMvEEpu2u5pXsy' + ], + change: [ + '138EGyTTyXFuqWBr8Jd7qmPbnfJUFmmuQg', + '12H7HZhtn7aNpTySXysKXiyxULybMktukh', + '1KMEUhmmiSdjX9fsv8aCAiYnVZnTTjqx7W' + ] + }; + var elec = new Electrum(mpk); + + var pubkey, addr, addr_change; + + for (var i = 0; i < expected_values.receiving.length; i++) { + //receiving + pubkey = elec.generatePubKey(i); + addr = Address.fromPubKey(pubkey); + addr.as('base58').should.equal(expected_values.receiving[i]); + + //change + pubkey = elec.generateChangePubKey(i); + addr = Address.fromPubKey(pubkey); + console.log('change'); + addr.as('base58').should.equal(expected_values.change[i]); + } + }); +}); + + + + + From 8e30c05e3e3d08797bd2475726bcf8b7489eef6e Mon Sep 17 00:00:00 2001 From: olalonde Date: Mon, 21 Apr 2014 04:29:23 +0800 Subject: [PATCH 4/5] Electrum: removed dead code --- examples/ElectrumMPK.js | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/examples/ElectrumMPK.js b/examples/ElectrumMPK.js index 8375fd8..c6bbb13 100644 --- a/examples/ElectrumMPK.js +++ b/examples/ElectrumMPK.js @@ -1,20 +1,11 @@ -var Key = require('../lib/Key'); +var Electrum = require('../lib/Electrum'); var Address = require('../lib/Address'); -var k = new Key(); - -//k.public = new Buffer('92eea4d2f5263651db9e3222caded1fd4c89772f79a7c03fb6afc00e9d2c9d2ed9b86c2c95fc1171e49163079dacb7f048b3c509a27a490e1df9e7128362d468', 'hex'); -//k.public = new Buffer('0492eea4d2f5263651db9e3222caded1fd4c89772f79a7c03fb6afc00e9d2c9d2ed9b86c2c95fc1171e49163079dacb7f048b3c509a27a490e1df9e7128362d468', 'hex'); -//k.public = new Buffer('0478d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71a1518063243acd4dfe96b66e3f2ec8013c8e072cd09b3834a19f81f659cc3455', 'hex'); -//k.generatePubKey(); -//debugger; -//console.log(k); -var Electrum = require('../lib/Electrum'); -//92eea4d2f5263651db9e3222caded1fd4c89772f79a7c03fb6afc00e9d2c9d2ed9b86c2c95fc1171e49163079dacb7f048b3c509a27a490e1df9e7128362d468 var mpk = '92eea4d2f5263651db9e3222caded1fd4c89772f79a7c03fb6afc00e9d2c9d2ed9b86c2c95fc1171e49163079dacb7f048b3c509a27a490e1df9e7128362d468'; + mpk = new Electrum(mpk); -var key1 = mpk.generatePubKey(0); -var addr1 = Address.fromPubKey(key1); +var key0 = mpk.generatePubKey(0); +var addr0 = Address.fromPubKey(key0); -console.log(addr1.as('base58')); +console.log(addr0.as('base58')); From e4e45c5245fdf6d3a0e718be3f1e1d36f6140da9 Mon Sep 17 00:00:00 2001 From: "Ryan X. Charles" Date: Sun, 20 Apr 2014 17:49:43 -0300 Subject: [PATCH 5/5] add Electrum to browser build and tests --- browser/build.js | 1 + test/index.html | 1 + 2 files changed, 2 insertions(+) diff --git a/browser/build.js b/browser/build.js index 4680175..a7c0805 100644 --- a/browser/build.js +++ b/browser/build.js @@ -30,6 +30,7 @@ var modules = [ 'lib/Bloom', 'lib/Connection', 'lib/Deserialize', + 'lib/Electrum', 'lib/Message', 'lib/Opcode', 'lib/Peer', diff --git a/test/index.html b/test/index.html index 3e823e4..551c46d 100644 --- a/test/index.html +++ b/test/index.html @@ -22,6 +22,7 @@ +