diff --git a/examples/ElectrumMPK.js b/examples/ElectrumMPK.js new file mode 100644 index 000000000..8375fd885 --- /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 000000000..58822a278 --- /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 41993682e..8f279a61b 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; }