Browse Source

derive public to public child keys

master
JP Richardson 11 years ago
parent
commit
53ae7e350f
  1. 1
      CHANGELOG.md
  2. 23
      lib/hdkey.js
  3. 25
      test/hdkey.test.js

1
CHANGELOG.md

@ -1,6 +1,7 @@
0.2.0 / 2014-06-25
------------------
- upgraded `"ecurve": "^0.8.0"` to `"ecurve": "^1.0.0"`
- added functionality to dervice public to public child keys
0.1.0 / 2014-06-16
------------------

23
lib/hdkey.js

@ -2,7 +2,7 @@ var assert = require('assert')
var crypto = require('crypto')
var BigInteger = require('bigi')
var ecurve = require('ecurve')
var ecparams = ecurve.getCurveByName('secp256k1')
var curve = ecurve.getCurveByName('secp256k1')
var Point = ecurve.Point
var sha512 = require('sha512')
@ -39,7 +39,8 @@ Object.defineProperty(HDKey.prototype, 'privateKey', {
assert.equal(value.length, 32, 'Private key must be 32 bytes.')
this._privateKey = value
this._privateKeyInteger = BigInteger.fromBuffer(this._privateKey)
this._publicKey = ecparams.G.multiply(this._privateKeyInteger).getEncoded(true) //force compressed point
this._publicPoint = curve.G.multiply(this._privateKeyInteger)
this._publicKey = this._publicPoint.getEncoded(true) //force compressed point
this._identifier = hash160(this.publicKey)
this._fingerprint = this._identifier.slice(0, 4).readUInt32BE(0)
}
@ -51,8 +52,8 @@ Object.defineProperty(HDKey.prototype, 'publicKey', {
},
set: function(value) {
assert(value.length === 33 || value.length === 65, 'Public key must be 33 or 65 bytes.')
var pt = Point.decodeFrom(ecparams, value)
this._publicKey = pt.getEncoded(true) //force compressed point
this._publicPoint = Point.decodeFrom(curve, value)
this._publicKey = this._publicPoint.getEncoded(true) //force compressed point
this._identifier = hash160(this.publicKey)
this._fingerprint = this._identifier.slice(0, 4).readUInt32BE(0)
this._privateKey = null
@ -128,10 +129,10 @@ HDKey.prototype.deriveChild = function(index) {
// Private parent key -> private child key
if (this.privateKey) {
// ki = parse256(IL) + kpar (mod n)
var ki = pIL.add(BigInteger.fromBuffer(this.privateKey)).mod(ecparams.n)
var ki = pIL.add(BigInteger.fromBuffer(this.privateKey)).mod(curve.n)
// In case parse256(IL) >= n or ki == 0, one should proceed with the next value for i
if (pIL.compareTo(ecparams.n) >= 0 || ki.signum() === 0) {
if (pIL.compareTo(curve.n) >= 0 || ki.signum() === 0) {
return this.derive(index + 1)
}
@ -141,14 +142,16 @@ HDKey.prototype.deriveChild = function(index) {
} else {
// Ki = point(parse256(IL)) + Kpar
// = G*IL + Kpar
//var Ki = ecparams.getG().multiply(pIL).add(this.pub.Q)
var Ki = curve.G.multiply(pIL).add(this._publicPoint)
// In case parse256(IL) >= n or Ki is the point at infinity, one should proceed with the next value for i
//if (pIL.compareTo(ecparams.getN()) >= 0 || Ki.isInfinity()) {
// return this.derive(index + 1)
//}
if (curve.isInfinity(Ki)) {
return this.derive(index + 1)
}
//hd.pub = new ECPubKey(Ki, true)
//this._publicPoint = Ki
hd.publicKey = Ki.getEncoded(true)
}
hd.chainCode = IR

25
test/hdkey.test.js

@ -4,7 +4,7 @@ var BigInteger = require('bigi')
var cs = require('coinstring')
var ecurve = require('ecurve')
var secureRandom = require('secure-random')
var ecparams = ecurve.getCurveByName('secp256k1')
var curve = ecurve.getCurveByName('secp256k1')
var HDKey = require('../')
var fixtures = require('./fixtures/hdkey')
@ -46,7 +46,7 @@ describe('hdkey', function() {
it('should not throw if key is 33 bytes (compressed)', function() {
var priv = secureRandom.randomBuffer(32)
var pub = ecparams.G.multiply(BigInteger.fromBuffer(priv)).getEncoded(true)
var pub = curve.G.multiply(BigInteger.fromBuffer(priv)).getEncoded(true)
assert.equal(pub.length, 33)
var hdkey = new HDKey()
hdkey.publicKey = pub
@ -54,7 +54,7 @@ describe('hdkey', function() {
it('should not throw if key is 65 bytes (not compressed)', function() {
var priv = secureRandom.randomBuffer(32)
var pub = ecparams.G.multiply(BigInteger.fromBuffer(priv)).getEncoded(false)
var pub = curve.G.multiply(BigInteger.fromBuffer(priv)).getEncoded(false)
assert.equal(pub.length, 65)
var hdkey = new HDKey()
hdkey.publicKey = pub
@ -66,7 +66,7 @@ describe('hdkey', function() {
it('should parse it', function() {
//m/0/2147483647'/1/2147483646'/2
var key = "xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j"
var keyBuffer = cs.decode(key).slice(0, 78)//bs58.decode(key).slice(0, 78)
var keyBuffer = cs.decode(key)
var hdkey = HDKey.fromExtendedKey(keyBuffer)
assert.equal(hdkey.versions.private, 0x0488ade4)
assert.equal(hdkey.versions.public, 0x0488b21e)
@ -84,7 +84,7 @@ describe('hdkey', function() {
it('should parse it', function() {
//m/0/2147483647'/1/2147483646'/2
var key = "xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt"
var keyBuffer = cs.decode(key).slice(0, 78)//bs58.decode(key).slice(0, 78)
var keyBuffer = cs.decode(key)
var hdkey = HDKey.fromExtendedKey(keyBuffer)
assert.equal(hdkey.versions.private, 0x0488ade4)
assert.equal(hdkey.versions.public, 0x0488b21e)
@ -98,4 +98,19 @@ describe('hdkey', function() {
})
})
})
describe('> when deriving public key', function() {
it('should work', function() {
var key = "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8"
var keyBuffer = cs.decode(key)
var hdkey = HDKey.fromExtendedKey(keyBuffer)
var path = "m/3353535/2223/0/99424/4/33"
var derivedHDKey = hdkey.derive(path)
var expected = "xpub6JdKdVJtdx6sC3nh87pDvnGhotXuU5Kz6Qy7Piy84vUAwWSYShsUGULE8u6gCivTHgz7cCKJHiXaaMeieB4YnoFVAsNgHHKXJ2mN6jCMbH1"
assert.equal(cs.encode(derivedHDKey.publicExtendedKey), expected)
})
})
})

Loading…
Cancel
Save