Skip to content
This repository was archived by the owner on Apr 3, 2019. It is now read-only.

Commit 6e311fe

Browse files
committed
defaults to nonCompliant key derivation
1 parent d0e8627 commit 6e311fe

File tree

5 files changed

+147
-68
lines changed

5 files changed

+147
-68
lines changed

lib/hdprivatekey.js

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ HDPrivateKey._getDerivationIndexes = function(path) {
127127
return _.any(indexes, isNaN) ? null : indexes;
128128
};
129129

130+
130131
/**
131132
* Get a derived child based on a string or number.
132133
*
@@ -156,6 +157,41 @@ HDPrivateKey._getDerivationIndexes = function(path) {
156157
*
157158
*/
158159
HDPrivateKey.prototype.derive = function(arg, hardened, nonCompliant) {
160+
161+
// Defaults to the nonCompliant derivation, for backwards compatibility
162+
if (_.isUndefined(nonCompliant))
163+
nonCompliant = true;
164+
165+
if (_.isNumber(arg)) {
166+
return this._deriveWithNumber(arg, hardened, nonCompliant);
167+
} else if (_.isString(arg)) {
168+
return this._deriveFromString(arg, nonCompliant);
169+
} else {
170+
throw new hdErrors.InvalidDerivationArgument(arg);
171+
}
172+
};
173+
174+
175+
176+
/**
177+
*
178+
* WARNING: This method should not be called directly. Please use: `getChild` or `getNonCompliantChild'.
179+
*
180+
* Internal method to get a derived child based on a string or number.
181+
*
182+
* @param {string|number} arg
183+
* @param {boolean?} hardened
184+
* @param {boolean?} nonCompliant - This should not be used and only for backwards compatibility
185+
*
186+
*/
187+
HDPrivateKey.prototype.derive = function(arg, hardened, nonCompliant) {
188+
189+
// Defaults to the nonCompliant derivation, for backwards compatibility
190+
if (_.isUndefined(nonCompliant)) {
191+
console.log('Warning: Using no BIP32 Compliant key derivation. If this is on purpose, use `getNonCompliantChild` to avoid this warning, otherwise use the `getChild`')
192+
nonCompliant = true;
193+
}
194+
159195
if (_.isNumber(arg)) {
160196
return this._deriveWithNumber(arg, hardened, nonCompliant);
161197
} else if (_.isString(arg)) {
@@ -165,9 +201,40 @@ HDPrivateKey.prototype.derive = function(arg, hardened, nonCompliant) {
165201
}
166202
};
167203

204+
205+
/**
206+
* Get a derived child based on a string or number.
207+
*
208+
* If the first argument is a string, it's parsed as the full path of
209+
* derivation. Valid values for this argument include "m" (which returns the
210+
* same private key), "m/0/1/40/2'/1000", where the ' quote means a hardened
211+
* derivation.
212+
*
213+
* If the first argument is a number, the child with that index will be
214+
* derived. If the second argument is truthy, the hardened version will be
215+
* derived. See the example usage for clarification.
216+
*
217+
* @example
218+
* ```javascript
219+
* var parent = new HDPrivateKey('xprv...');
220+
* var child_0_1_2h = parent.getChild(0).getChild(1).getChild(2, true);
221+
* var copy_of_child_0_1_2h = parent.getChild("m/0/1/2'");
222+
* assert(child_0_1_2h.xprivkey === copy_of_child_0_1_2h);
223+
* ```
224+
*
225+
* @param {string|number} arg
226+
* @param {boolean?} hardened
227+
*
228+
*/
229+
230+
HDPrivateKey.prototype.getChild = function(arg, hardened) {
231+
var derived = this.derive(arg, hardened, false);
232+
return derived;
233+
};
234+
168235
/**
169236
* WARNING: If this is a new implementation you should NOT use this method, you should be using
170-
* `derive` instead.
237+
* `getChild` instead.
171238
*
172239
* This method is explicitly for use and compatibility with an implementation that
173240
* was not compliant with BIP32 regarding the derivation algorithm. The private key
@@ -178,7 +245,7 @@ HDPrivateKey.prototype.derive = function(arg, hardened, nonCompliant) {
178245
* @param {string|number} arg
179246
* @param {boolean?} hardened
180247
*/
181-
HDPrivateKey.prototype.deriveNonCompliant = function(arg, hardened) {
248+
HDPrivateKey.prototype.getNonCompliantChild = function(arg, hardened) {
182249
var derived = this.derive(arg, hardened, true);
183250
return derived;
184251
};
@@ -209,7 +276,9 @@ HDPrivateKey.prototype._deriveWithNumber = function(index, hardened, nonComplian
209276
data = BufferUtil.concat([new buffer.Buffer([0]), nonZeroPadded, indexBuffer]);
210277
} else if (hardened) {
211278
// This will use a 32 byte zero padded serialization of the private key
212-
var privateKeyBuffer = this.privateKey.bn.toBuffer({size: 32});
279+
var privateKeyBuffer = this.privateKey.bn.toBuffer({
280+
size: 32
281+
});
213282
assert(privateKeyBuffer.length === 32, 'length of private key buffer is expected to be 32 bytes');
214283
data = BufferUtil.concat([new buffer.Buffer([0]), privateKeyBuffer, indexBuffer]);
215284
} else {

lib/hdpublickey.js

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,22 @@ HDPublicKey.isValidPath = function(arg) {
8686
return false;
8787
};
8888

89+
90+
/**
91+
* Internal method to get a derivated child based on a string or number.
92+
*
93+
*/
94+
95+
HDPublicKey.prototype.derive = function(arg, hardened) {
96+
if (_.isNumber(arg)) {
97+
return this._deriveWithNumber(arg, hardened);
98+
} else if (_.isString(arg)) {
99+
return this._deriveFromString(arg);
100+
} else {
101+
throw new hdErrors.InvalidDerivationArgument(arg);
102+
}
103+
};
104+
89105
/**
90106
* Get a derivated child based on a string or number.
91107
*
@@ -108,14 +124,8 @@ HDPublicKey.isValidPath = function(arg) {
108124
*
109125
* @param {string|number} arg
110126
*/
111-
HDPublicKey.prototype.derive = function(arg, hardened) {
112-
if (_.isNumber(arg)) {
113-
return this._deriveWithNumber(arg, hardened);
114-
} else if (_.isString(arg)) {
115-
return this._deriveFromString(arg);
116-
} else {
117-
throw new hdErrors.InvalidDerivationArgument(arg);
118-
}
127+
HDPublicKey.prototype.getChild = function(arg, hardened) {
128+
return this.derive(arg, hardened);
119129
};
120130

121131
HDPublicKey.prototype._deriveWithNumber = function(index, hardened) {

test/hdkeycache.js

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,29 +24,29 @@ describe('HDKey cache', function() {
2424
});
2525

2626
it('saves a derived key', function() {
27-
var child = master.derive(0);
27+
var child = master.getChild(0);
2828
expect(cache._cache['0' + master.xprivkey + '/0/false'].xprivkey).to.equal(child.xprivkey);
2929
});
3030
it('starts erasing unused keys', function() {
31-
var child1 = master.derive(0);
32-
var child2 = child1.derive(0);
33-
var child3 = child2.derive(0);
31+
var child1 = master.getChild(0);
32+
var child2 = child1.getChild(0);
33+
var child3 = child2.getChild(0);
3434
expect(cache._cache['0' + master.xprivkey + '/0/false'].xprivkey).to.equal(child1.xprivkey);
35-
var child4 = child3.derive(0);
35+
var child4 = child3.getChild(0);
3636
expect(cache._cache['0' + master.xprivkey + '/0/false']).to.equal(undefined);
3737
});
3838
it('avoids erasing keys that get cache hits ("hot keys")', function() {
39-
var child1 = master.derive(0);
40-
var child2 = master.derive(0).derive(0);
39+
var child1 = master.getChild(0);
40+
var child2 = master.getChild(0).getChild(0);
4141
expect(cache._cache['0' + master.xprivkey + '/0/false'].xprivkey).to.equal(child1.xprivkey);
42-
var child1_copy = master.derive(0);
42+
var child1_copy = master.getChild(0);
4343
expect(cache._cache['0' + master.xprivkey + '/0/false'].xprivkey).to.equal(child1.xprivkey);
4444
});
4545
it('keeps the size of the cache small', function() {
46-
var child1 = master.derive(0);
47-
var child2 = child1.derive(0);
48-
var child3 = child2.derive(0);
49-
var child4 = child3.derive(0);
46+
var child1 = master.getChild(0);
47+
var child2 = child1.getChild(0);
48+
var child3 = child2.getChild(0);
49+
var child4 = child3.getChild(0);
5050
expect(_.size(cache._cache)).to.equal(3);
5151
});
5252
});

0 commit comments

Comments
 (0)