commit
17041553df
@ -291,6 +291,30 @@ HDNode.prototype.isNeutered = function () {
|
|||||||
return !(this.keyPair.d)
|
return !(this.keyPair.d)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HDNode.prototype.derivePath = function (path) {
|
||||||
|
typeforce(types.Bip32Path, path)
|
||||||
|
|
||||||
|
var splitPath = path.split('/')
|
||||||
|
if (splitPath[0] === 'm') {
|
||||||
|
if (this.parentFingerprint) {
|
||||||
|
throw new Error('Not a master node')
|
||||||
|
}
|
||||||
|
|
||||||
|
splitPath = splitPath.slice(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return splitPath.reduce(function (prevHd, indexStr) {
|
||||||
|
var index
|
||||||
|
if (indexStr.slice(-1) === "'") {
|
||||||
|
index = parseInt(indexStr.slice(0, -1), 10)
|
||||||
|
return prevHd.deriveHardened(index)
|
||||||
|
} else {
|
||||||
|
index = parseInt(indexStr, 10)
|
||||||
|
return prevHd.derive(index)
|
||||||
|
}
|
||||||
|
}, this)
|
||||||
|
}
|
||||||
|
|
||||||
HDNode.prototype.toString = HDNode.prototype.toBase58
|
HDNode.prototype.toString = HDNode.prototype.toBase58
|
||||||
|
|
||||||
module.exports = HDNode
|
module.exports = HDNode
|
||||||
|
|||||||
@ -26,6 +26,11 @@ function UInt53 (value) {
|
|||||||
Math.floor(value) === value
|
Math.floor(value) === value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Bip32Path (value) {
|
||||||
|
return typeforce.String(value) &&
|
||||||
|
value.match(/^(m\/)?(\d+'?\/)*\d+'?$/)
|
||||||
|
}
|
||||||
|
|
||||||
// external dependent types
|
// external dependent types
|
||||||
var BigInt = typeforce.quacksLike('BigInteger')
|
var BigInt = typeforce.quacksLike('BigInteger')
|
||||||
var ECPoint = typeforce.quacksLike('Point')
|
var ECPoint = typeforce.quacksLike('Point')
|
||||||
@ -57,7 +62,8 @@ var types = {
|
|||||||
UInt8: UInt8,
|
UInt8: UInt8,
|
||||||
UInt31: UInt31,
|
UInt31: UInt31,
|
||||||
UInt32: UInt32,
|
UInt32: UInt32,
|
||||||
UInt53: UInt53
|
UInt53: UInt53,
|
||||||
|
Bip32Path: Bip32Path
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var typeName in typeforce) {
|
for (var typeName in typeforce) {
|
||||||
|
|||||||
25
test/fixtures/hdnode.json
vendored
25
test/fixtures/hdnode.json
vendored
@ -109,7 +109,7 @@
|
|||||||
"address": "19EuDJdgfRkwCmRzbzVBHZWQG9QNWhftbZ"
|
"address": "19EuDJdgfRkwCmRzbzVBHZWQG9QNWhftbZ"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "m/0/2147483647",
|
"description": "m/0/2147483647'",
|
||||||
"m": 2147483647,
|
"m": 2147483647,
|
||||||
"hardened": true,
|
"hardened": true,
|
||||||
"wif": "L1m5VpbXmMp57P3knskwhoMTLdhAAaXiHvnGLMribbfwzVRpz2Sr",
|
"wif": "L1m5VpbXmMp57P3knskwhoMTLdhAAaXiHvnGLMribbfwzVRpz2Sr",
|
||||||
@ -134,7 +134,7 @@
|
|||||||
"address": "1BxrAr2pHpeBheusmd6fHDP2tSLAUa3qsW"
|
"address": "1BxrAr2pHpeBheusmd6fHDP2tSLAUa3qsW"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "m/0/2147483647'/1/2147483646",
|
"description": "m/0/2147483647'/1/2147483646'",
|
||||||
"m": 2147483646,
|
"m": 2147483646,
|
||||||
"hardened": true,
|
"hardened": true,
|
||||||
"wif": "L5KhaMvPYRW1ZoFmRjUtxxPypQ94m6BcDrPhqArhggdaTbbAFJEF",
|
"wif": "L5KhaMvPYRW1ZoFmRjUtxxPypQ94m6BcDrPhqArhggdaTbbAFJEF",
|
||||||
@ -232,6 +232,27 @@
|
|||||||
"exception": "Point is not on the curve",
|
"exception": "Point is not on the curve",
|
||||||
"hex": "0488b21e000000000000000000873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508020045400697100007000037899988826500030092003000016366806305909050"
|
"hex": "0488b21e000000000000000000873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508020045400697100007000037899988826500030092003000016366806305909050"
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"deriveHardened": [
|
||||||
|
2147483648,
|
||||||
|
null,
|
||||||
|
"foo",
|
||||||
|
-1
|
||||||
|
],
|
||||||
|
"derive": [
|
||||||
|
4294967296,
|
||||||
|
null,
|
||||||
|
"foo",
|
||||||
|
-1
|
||||||
|
],
|
||||||
|
"derivePath": [
|
||||||
|
2,
|
||||||
|
[2, 3, 4],
|
||||||
|
"/",
|
||||||
|
"m/m/123",
|
||||||
|
"a/0/1/2",
|
||||||
|
"m/0/ 1 /2",
|
||||||
|
"m/0/1.5/2"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -272,6 +272,7 @@ describe('HDNode', function () {
|
|||||||
fixtures.valid.forEach(function (f) {
|
fixtures.valid.forEach(function (f) {
|
||||||
var network = NETWORKS[f.network]
|
var network = NETWORKS[f.network]
|
||||||
var hd = HDNode.fromSeedHex(f.master.seed, network)
|
var hd = HDNode.fromSeedHex(f.master.seed, network)
|
||||||
|
var master = hd
|
||||||
|
|
||||||
// FIXME: test data is only testing Private -> private for now
|
// FIXME: test data is only testing Private -> private for now
|
||||||
f.children.forEach(function (c, i) {
|
f.children.forEach(function (c, i) {
|
||||||
@ -285,6 +286,42 @@ describe('HDNode', function () {
|
|||||||
verifyVector(hd, c, i + 1)
|
verifyVector(hd, c, i + 1)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// testing deriving path from master
|
||||||
|
f.children.forEach(function (c) {
|
||||||
|
it(c.description + ' from ' + f.master.fingerprint + ' by path', function () {
|
||||||
|
var path = c.description
|
||||||
|
var child = master.derivePath(path)
|
||||||
|
|
||||||
|
var pathSplit = path.split('/').slice(1)
|
||||||
|
var pathNotM = pathSplit.join('/')
|
||||||
|
var childNotM = master.derivePath(pathNotM)
|
||||||
|
|
||||||
|
verifyVector(child, c, pathSplit.length)
|
||||||
|
verifyVector(childNotM, c, pathSplit.length)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// testing deriving path from children
|
||||||
|
f.children.forEach(function (c, i) {
|
||||||
|
var cn = master.derivePath(c.description)
|
||||||
|
|
||||||
|
f.children.slice(i + 1).forEach(function (cc) {
|
||||||
|
it(cc.description + ' from ' + c.fingerprint + ' by path', function () {
|
||||||
|
var path = cc.description
|
||||||
|
|
||||||
|
var pathSplit = path.split('/').slice(i + 2)
|
||||||
|
var pathEnd = pathSplit.join('/')
|
||||||
|
var pathEndM = 'm/' + pathEnd
|
||||||
|
var child = cn.derivePath(pathEnd)
|
||||||
|
verifyVector(child, cc, pathSplit.length + i + 1)
|
||||||
|
|
||||||
|
assert.throws(function () {
|
||||||
|
cn.derivePath(pathEndM)
|
||||||
|
}, /Not a master node/)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('works for Private -> public (neutered)', function () {
|
it('works for Private -> public (neutered)', function () {
|
||||||
@ -328,46 +365,27 @@ describe('HDNode', function () {
|
|||||||
}, /Could not derive hardened child key/)
|
}, /Could not derive hardened child key/)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('throws on negative indexes', function () {
|
it('throws on wrong types', function () {
|
||||||
var f = fixtures.valid[0]
|
var f = fixtures.valid[0]
|
||||||
var master = HDNode.fromBase58(f.master.base58, NETWORKS_LIST)
|
var master = HDNode.fromBase58(f.master.base58, NETWORKS_LIST)
|
||||||
|
|
||||||
assert.throws(function () {
|
fixtures.invalid.derive.forEach(function (fx) {
|
||||||
master.deriveHardened(-1)
|
assert.throws(function () {
|
||||||
}, /Expected UInt31/)
|
master.derive(fx)
|
||||||
assert.throws(function () {
|
}, /Expected UInt32/)
|
||||||
master.derive(-1)
|
})
|
||||||
}, /Expected UInt32/)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('throws on high indexes', function () {
|
fixtures.invalid.deriveHardened.forEach(function (fx) {
|
||||||
var f = fixtures.valid[0]
|
assert.throws(function () {
|
||||||
var master = HDNode.fromBase58(f.master.base58, NETWORKS_LIST)
|
master.deriveHardened(fx)
|
||||||
|
}, /Expected UInt31/)
|
||||||
|
})
|
||||||
|
|
||||||
assert.throws(function () {
|
fixtures.invalid.derivePath.forEach(function (fx) {
|
||||||
master.deriveHardened(0x80000000)
|
assert.throws(function () {
|
||||||
}, /Expected UInt31/)
|
master.derivePath(fx)
|
||||||
assert.throws(function () {
|
}, /Expected Bip32Path/)
|
||||||
master.derive(0x100000000)
|
})
|
||||||
}, /Expected UInt32/)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('throws on non-numbers', function () {
|
|
||||||
var f = fixtures.valid[0]
|
|
||||||
var master = HDNode.fromBase58(f.master.base58, NETWORKS_LIST)
|
|
||||||
|
|
||||||
assert.throws(function () {
|
|
||||||
master.deriveHardened()
|
|
||||||
}, /Expected UInt31/)
|
|
||||||
assert.throws(function () {
|
|
||||||
master.derive()
|
|
||||||
}, /Expected UInt32/)
|
|
||||||
assert.throws(function () {
|
|
||||||
master.deriveHardened('foo')
|
|
||||||
}, /Expected UInt31/)
|
|
||||||
assert.throws(function () {
|
|
||||||
master.derive('foo')
|
|
||||||
}, /Expected UInt32/)
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user