1 | 'use strict';
|
2 |
|
3 |
|
4 | var assert = require('assert');
|
5 | var buffer = require('buffer');
|
6 | var _ = require('lodash');
|
7 | var $ = require('./util/preconditions');
|
8 |
|
9 | var BN = require('./crypto/bn');
|
10 | var Base58 = require('./encoding/base58');
|
11 | var Base58Check = require('./encoding/base58check');
|
12 | var Hash = require('./crypto/hash');
|
13 | var Network = require('./networks');
|
14 | var Point = require('./crypto/point');
|
15 | var PrivateKey = require('./privatekey');
|
16 | var Random = require('./crypto/random');
|
17 |
|
18 | var errors = require('./errors');
|
19 | var hdErrors = errors.HDPrivateKey;
|
20 | var BufferUtil = require('./util/buffer');
|
21 | var JSUtil = require('./util/js');
|
22 |
|
23 | var MINIMUM_ENTROPY_BITS = 128;
|
24 | var BITS_TO_BYTES = 1 / 8;
|
25 | var MAXIMUM_ENTROPY_BITS = 512;
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 |
|
36 | function HDPrivateKey(arg) {
|
37 |
|
38 | if (arg instanceof HDPrivateKey) {
|
39 | return arg;
|
40 | }
|
41 | if (!(this instanceof HDPrivateKey)) {
|
42 | return new HDPrivateKey(arg);
|
43 | }
|
44 | if (!arg) {
|
45 | return this._generateRandomly();
|
46 | }
|
47 |
|
48 | if (Network.get(arg)) {
|
49 | return this._generateRandomly(arg);
|
50 | } else if (_.isString(arg) || BufferUtil.isBuffer(arg)) {
|
51 | if (HDPrivateKey.isValidSerialized(arg)) {
|
52 | this._buildFromSerialized(arg);
|
53 | } else if (JSUtil.isValidJSON(arg)) {
|
54 | this._buildFromJSON(arg);
|
55 | } else if (BufferUtil.isBuffer(arg) && HDPrivateKey.isValidSerialized(arg.toString())) {
|
56 | this._buildFromSerialized(arg.toString());
|
57 | } else {
|
58 | throw HDPrivateKey.getSerializedError(arg);
|
59 | }
|
60 | } else if (_.isObject(arg)) {
|
61 | this._buildFromObject(arg);
|
62 | } else {
|
63 | throw new hdErrors.UnrecognizedArgument(arg);
|
64 | }
|
65 | }
|
66 |
|
67 |
|
68 |
|
69 |
|
70 |
|
71 |
|
72 |
|
73 |
|
74 | HDPrivateKey.isValidPath = function(arg, hardened) {
|
75 | if (_.isString(arg)) {
|
76 | var indexes = HDPrivateKey._getDerivationIndexes(arg);
|
77 | return indexes !== null && _.every(indexes, HDPrivateKey.isValidPath);
|
78 | }
|
79 |
|
80 | if (_.isNumber(arg)) {
|
81 | if (arg < HDPrivateKey.Hardened && hardened === true) {
|
82 | arg += HDPrivateKey.Hardened;
|
83 | }
|
84 | return arg >= 0 && arg < HDPrivateKey.MaxIndex;
|
85 | }
|
86 |
|
87 | return false;
|
88 | };
|
89 |
|
90 |
|
91 |
|
92 |
|
93 |
|
94 |
|
95 |
|
96 |
|
97 |
|
98 | HDPrivateKey._getDerivationIndexes = function(path) {
|
99 | var steps = path.split('/');
|
100 |
|
101 |
|
102 | if (_.includes(HDPrivateKey.RootElementAlias, path)) {
|
103 | return [];
|
104 | }
|
105 |
|
106 | if (!_.includes(HDPrivateKey.RootElementAlias, steps[0])) {
|
107 | return null;
|
108 | }
|
109 |
|
110 | var indexes = steps.slice(1).map(function(step) {
|
111 | var isHardened = step.slice(-1) === '\'';
|
112 | if (isHardened) {
|
113 | step = step.slice(0, -1);
|
114 | }
|
115 | if (!step || step[0] === '-') {
|
116 | return NaN;
|
117 | }
|
118 | var index = +step;
|
119 | if (isHardened) {
|
120 | index += HDPrivateKey.Hardened;
|
121 | }
|
122 |
|
123 | return index;
|
124 | });
|
125 |
|
126 | return _.some(indexes, isNaN) ? null : indexes;
|
127 | };
|
128 |
|
129 |
|
130 |
|
131 |
|
132 |
|
133 |
|
134 |
|
135 |
|
136 |
|
137 |
|
138 |
|
139 |
|
140 |
|
141 |
|
142 |
|
143 |
|
144 |
|
145 |
|
146 |
|
147 |
|
148 |
|
149 |
|
150 |
|
151 |
|
152 |
|
153 |
|
154 |
|
155 | HDPrivateKey.prototype.derive = function(arg, hardened) {
|
156 | return this.deriveNonCompliantChild(arg, hardened);
|
157 | };
|
158 |
|
159 |
|
160 |
|
161 |
|
162 |
|
163 |
|
164 |
|
165 |
|
166 |
|
167 |
|
168 |
|
169 |
|
170 |
|
171 |
|
172 |
|
173 |
|
174 |
|
175 |
|
176 |
|
177 |
|
178 |
|
179 |
|
180 |
|
181 |
|
182 |
|
183 |
|
184 |
|
185 |
|
186 |
|
187 |
|
188 | HDPrivateKey.prototype.deriveChild = function(arg, hardened) {
|
189 | if (_.isNumber(arg)) {
|
190 | return this._deriveWithNumber(arg, hardened);
|
191 | } else if (_.isString(arg)) {
|
192 | return this._deriveFromString(arg);
|
193 | } else {
|
194 | throw new hdErrors.InvalidDerivationArgument(arg);
|
195 | }
|
196 | };
|
197 |
|
198 |
|
199 |
|
200 |
|
201 |
|
202 |
|
203 |
|
204 |
|
205 |
|
206 |
|
207 |
|
208 |
|
209 |
|
210 |
|
211 |
|
212 |
|
213 |
|
214 | HDPrivateKey.prototype.deriveNonCompliantChild = function(arg, hardened) {
|
215 | if (_.isNumber(arg)) {
|
216 | return this._deriveWithNumber(arg, hardened, true);
|
217 | } else if (_.isString(arg)) {
|
218 | return this._deriveFromString(arg, true);
|
219 | } else {
|
220 | throw new hdErrors.InvalidDerivationArgument(arg);
|
221 | }
|
222 | };
|
223 |
|
224 | HDPrivateKey.prototype._deriveWithNumber = function(index, hardened, nonCompliant) {
|
225 |
|
226 |
|
227 | if (!HDPrivateKey.isValidPath(index, hardened)) {
|
228 | throw new hdErrors.InvalidPath(index);
|
229 | }
|
230 |
|
231 | hardened = index >= HDPrivateKey.Hardened ? true : hardened;
|
232 | if (index < HDPrivateKey.Hardened && hardened === true) {
|
233 | index += HDPrivateKey.Hardened;
|
234 | }
|
235 |
|
236 | var indexBuffer = BufferUtil.integerAsBuffer(index);
|
237 | var data;
|
238 | if (hardened && nonCompliant) {
|
239 |
|
240 |
|
241 | var nonZeroPadded = this.privateKey.bn.toBuffer();
|
242 | data = BufferUtil.concat([Buffer.from([0]), nonZeroPadded, indexBuffer]);
|
243 | } else if (hardened) {
|
244 |
|
245 | var privateKeyBuffer = this.privateKey.bn.toBuffer({size: 32});
|
246 | assert(privateKeyBuffer.length === 32, 'length of private key buffer is expected to be 32 bytes');
|
247 | data = BufferUtil.concat([Buffer.from([0]), privateKeyBuffer, indexBuffer]);
|
248 | } else {
|
249 | data = BufferUtil.concat([this.publicKey.toBuffer(), indexBuffer]);
|
250 | }
|
251 | var hash = Hash.sha512hmac(data, this._buffers.chainCode);
|
252 | var leftPart = BN.fromBuffer(hash.slice(0, 32), {
|
253 | size: 32
|
254 | });
|
255 | var chainCode = hash.slice(32, 64);
|
256 |
|
257 | var privateKey = leftPart.add(this.privateKey.toBigNumber()).umod(Point.getN()).toBuffer({
|
258 | size: 32
|
259 | });
|
260 |
|
261 | if (!PrivateKey.isValid(privateKey)) {
|
262 |
|
263 | return this._deriveWithNumber(index + 1, null, nonCompliant);
|
264 | }
|
265 |
|
266 | var derived = new HDPrivateKey({
|
267 | network: this.network,
|
268 | depth: this.depth + 1,
|
269 | parentFingerPrint: this.fingerPrint,
|
270 | childIndex: index,
|
271 | chainCode: chainCode,
|
272 | privateKey: privateKey
|
273 | });
|
274 |
|
275 | return derived;
|
276 | };
|
277 |
|
278 | HDPrivateKey.prototype._deriveFromString = function(path, nonCompliant) {
|
279 | if (!HDPrivateKey.isValidPath(path)) {
|
280 | throw new hdErrors.InvalidPath(path);
|
281 | }
|
282 |
|
283 | var indexes = HDPrivateKey._getDerivationIndexes(path);
|
284 | var derived = indexes.reduce(function(prev, index) {
|
285 | return prev._deriveWithNumber(index, null, nonCompliant);
|
286 | }, this);
|
287 |
|
288 | return derived;
|
289 | };
|
290 |
|
291 |
|
292 |
|
293 |
|
294 |
|
295 |
|
296 |
|
297 |
|
298 |
|
299 |
|
300 | HDPrivateKey.isValidSerialized = function(data, network) {
|
301 | return !HDPrivateKey.getSerializedError(data, network);
|
302 | };
|
303 |
|
304 |
|
305 |
|
306 |
|
307 |
|
308 |
|
309 |
|
310 |
|
311 |
|
312 |
|
313 | HDPrivateKey.getSerializedError = function(data, network) {
|
314 |
|
315 | if (!(_.isString(data) || BufferUtil.isBuffer(data))) {
|
316 | return new hdErrors.UnrecognizedArgument('Expected string or buffer');
|
317 | }
|
318 | if (!Base58.validCharacters(data)) {
|
319 | return new errors.InvalidB58Char('(unknown)', data);
|
320 | }
|
321 | try {
|
322 | data = Base58Check.decode(data);
|
323 | } catch (e) {
|
324 | return new errors.InvalidB58Checksum(data);
|
325 | }
|
326 | if (data.length !== HDPrivateKey.DataLength) {
|
327 | return new hdErrors.InvalidLength(data);
|
328 | }
|
329 | if (!_.isUndefined(network)) {
|
330 | var error = HDPrivateKey._validateNetwork(data, network);
|
331 | if (error) {
|
332 | return error;
|
333 | }
|
334 | }
|
335 | return null;
|
336 | };
|
337 |
|
338 | HDPrivateKey._validateNetwork = function(data, networkArg) {
|
339 | var network = Network.get(networkArg);
|
340 | if (!network) {
|
341 | return new errors.InvalidNetworkArgument(networkArg);
|
342 | }
|
343 | var version = data.slice(0, 4);
|
344 | if (BufferUtil.integerFromBuffer(version) !== network.xprivkey) {
|
345 | return new errors.InvalidNetwork(version);
|
346 | }
|
347 | return null;
|
348 | };
|
349 |
|
350 | HDPrivateKey.fromString = function(arg) {
|
351 | $.checkArgument(_.isString(arg), 'No valid string was provided');
|
352 | return new HDPrivateKey(arg);
|
353 | };
|
354 |
|
355 | HDPrivateKey.fromObject = function(arg) {
|
356 | $.checkArgument(_.isObject(arg), 'No valid argument was provided');
|
357 | return new HDPrivateKey(arg);
|
358 | };
|
359 |
|
360 | HDPrivateKey.prototype._buildFromJSON = function(arg) {
|
361 | return this._buildFromObject(JSON.parse(arg));
|
362 | };
|
363 |
|
364 | HDPrivateKey.prototype._buildFromObject = function(arg) {
|
365 |
|
366 |
|
367 | var buffers = {
|
368 | version: arg.network ? BufferUtil.integerAsBuffer(Network.get(arg.network).xprivkey) : arg.version,
|
369 | depth: _.isNumber(arg.depth) ? BufferUtil.integerAsSingleByteBuffer(arg.depth) : arg.depth,
|
370 | parentFingerPrint: _.isNumber(arg.parentFingerPrint) ? BufferUtil.integerAsBuffer(arg.parentFingerPrint) : arg.parentFingerPrint,
|
371 | childIndex: _.isNumber(arg.childIndex) ? BufferUtil.integerAsBuffer(arg.childIndex) : arg.childIndex,
|
372 | chainCode: _.isString(arg.chainCode) ? Buffer.from(arg.chainCode,'hex') : arg.chainCode,
|
373 | privateKey: (_.isString(arg.privateKey) && JSUtil.isHexa(arg.privateKey)) ? Buffer.from(arg.privateKey,'hex') : arg.privateKey,
|
374 | checksum: arg.checksum ? (arg.checksum.length ? arg.checksum : BufferUtil.integerAsBuffer(arg.checksum)) : undefined
|
375 | };
|
376 | return this._buildFromBuffers(buffers);
|
377 | };
|
378 |
|
379 | HDPrivateKey.prototype._buildFromSerialized = function(arg) {
|
380 | var decoded = Base58Check.decode(arg);
|
381 | var buffers = {
|
382 | version: decoded.slice(HDPrivateKey.VersionStart, HDPrivateKey.VersionEnd),
|
383 | depth: decoded.slice(HDPrivateKey.DepthStart, HDPrivateKey.DepthEnd),
|
384 | parentFingerPrint: decoded.slice(HDPrivateKey.ParentFingerPrintStart,
|
385 | HDPrivateKey.ParentFingerPrintEnd),
|
386 | childIndex: decoded.slice(HDPrivateKey.ChildIndexStart, HDPrivateKey.ChildIndexEnd),
|
387 | chainCode: decoded.slice(HDPrivateKey.ChainCodeStart, HDPrivateKey.ChainCodeEnd),
|
388 | privateKey: decoded.slice(HDPrivateKey.PrivateKeyStart, HDPrivateKey.PrivateKeyEnd),
|
389 | checksum: decoded.slice(HDPrivateKey.ChecksumStart, HDPrivateKey.ChecksumEnd),
|
390 | xprivkey: arg
|
391 | };
|
392 | return this._buildFromBuffers(buffers);
|
393 | };
|
394 |
|
395 | HDPrivateKey.prototype._generateRandomly = function(network) {
|
396 | return HDPrivateKey.fromSeed(Random.getRandomBuffer(64), network);
|
397 | };
|
398 |
|
399 |
|
400 |
|
401 |
|
402 |
|
403 |
|
404 |
|
405 |
|
406 | HDPrivateKey.fromSeed = function(hexa, network) {
|
407 |
|
408 | if (JSUtil.isHexaString(hexa)) {
|
409 | hexa = Buffer.from(hexa, 'hex');
|
410 | }
|
411 | if (!Buffer.isBuffer(hexa)) {
|
412 | throw new hdErrors.InvalidEntropyArgument(hexa);
|
413 | }
|
414 | if (hexa.length < MINIMUM_ENTROPY_BITS * BITS_TO_BYTES) {
|
415 | throw new hdErrors.InvalidEntropyArgument.NotEnoughEntropy(hexa);
|
416 | }
|
417 | if (hexa.length > MAXIMUM_ENTROPY_BITS * BITS_TO_BYTES) {
|
418 | throw new hdErrors.InvalidEntropyArgument.TooMuchEntropy(hexa);
|
419 | }
|
420 | var hash = Hash.sha512hmac(hexa, Buffer.from('Bitcoin seed'));
|
421 |
|
422 | return new HDPrivateKey({
|
423 | network: Network.get(network) || Network.defaultNetwork,
|
424 | depth: 0,
|
425 | parentFingerPrint: 0,
|
426 | childIndex: 0,
|
427 | privateKey: hash.slice(0, 32),
|
428 | chainCode: hash.slice(32, 64)
|
429 | });
|
430 | };
|
431 |
|
432 |
|
433 |
|
434 | HDPrivateKey.prototype._calcHDPublicKey = function() {
|
435 | if (!this._hdPublicKey) {
|
436 | var HDPublicKey = require('./hdpublickey');
|
437 | this._hdPublicKey = new HDPublicKey(this);
|
438 | }
|
439 | };
|
440 |
|
441 |
|
442 |
|
443 |
|
444 |
|
445 |
|
446 |
|
447 |
|
448 |
|
449 |
|
450 |
|
451 |
|
452 |
|
453 |
|
454 |
|
455 |
|
456 |
|
457 | HDPrivateKey.prototype._buildFromBuffers = function(arg) {
|
458 |
|
459 |
|
460 |
|
461 | HDPrivateKey._validateBufferArguments(arg);
|
462 |
|
463 | JSUtil.defineImmutable(this, {
|
464 | _buffers: arg
|
465 | });
|
466 |
|
467 | var sequence = [
|
468 | arg.version, arg.depth, arg.parentFingerPrint, arg.childIndex, arg.chainCode,
|
469 | BufferUtil.emptyBuffer(1), arg.privateKey
|
470 | ];
|
471 | var concat = buffer.Buffer.concat(sequence);
|
472 | if (!arg.checksum || !arg.checksum.length) {
|
473 | arg.checksum = Base58Check.checksum(concat);
|
474 | } else {
|
475 | if (arg.checksum.toString() !== Base58Check.checksum(concat).toString()) {
|
476 | throw new errors.InvalidB58Checksum(concat);
|
477 | }
|
478 | }
|
479 |
|
480 | var network = Network.get(BufferUtil.integerFromBuffer(arg.version));
|
481 | var xprivkey;
|
482 | xprivkey = Base58Check.encode(buffer.Buffer.concat(sequence));
|
483 | arg.xprivkey = Buffer.from(xprivkey);
|
484 |
|
485 | var privateKey = new PrivateKey(BN.fromBuffer(arg.privateKey), network);
|
486 | var publicKey = privateKey.toPublicKey();
|
487 | var size = HDPrivateKey.ParentFingerPrintSize;
|
488 | var fingerPrint = Hash.sha256ripemd160(publicKey.toBuffer()).slice(0, size);
|
489 |
|
490 | JSUtil.defineImmutable(this, {
|
491 | xprivkey: xprivkey,
|
492 | network: network,
|
493 | depth: BufferUtil.integerFromSingleByteBuffer(arg.depth),
|
494 | privateKey: privateKey,
|
495 | publicKey: publicKey,
|
496 | fingerPrint: fingerPrint
|
497 | });
|
498 |
|
499 | this._hdPublicKey = null;
|
500 |
|
501 | Object.defineProperty(this, 'hdPublicKey', {
|
502 | configurable: false,
|
503 | enumerable: true,
|
504 | get: function() {
|
505 | this._calcHDPublicKey();
|
506 | return this._hdPublicKey;
|
507 | }
|
508 | });
|
509 | Object.defineProperty(this, 'xpubkey', {
|
510 | configurable: false,
|
511 | enumerable: true,
|
512 | get: function() {
|
513 | this._calcHDPublicKey();
|
514 | return this._hdPublicKey.xpubkey;
|
515 | }
|
516 | });
|
517 | return this;
|
518 | };
|
519 |
|
520 | HDPrivateKey._validateBufferArguments = function(arg) {
|
521 | var checkBuffer = function(name, size) {
|
522 | var buff = arg[name];
|
523 | assert(BufferUtil.isBuffer(buff), name + ' argument is not a buffer');
|
524 | assert(
|
525 | buff.length === size,
|
526 | name + ' has not the expected size: found ' + buff.length + ', expected ' + size
|
527 | );
|
528 | };
|
529 | checkBuffer('version', HDPrivateKey.VersionSize);
|
530 | checkBuffer('depth', HDPrivateKey.DepthSize);
|
531 | checkBuffer('parentFingerPrint', HDPrivateKey.ParentFingerPrintSize);
|
532 | checkBuffer('childIndex', HDPrivateKey.ChildIndexSize);
|
533 | checkBuffer('chainCode', HDPrivateKey.ChainCodeSize);
|
534 | checkBuffer('privateKey', HDPrivateKey.PrivateKeySize);
|
535 | if (arg.checksum && arg.checksum.length) {
|
536 | checkBuffer('checksum', HDPrivateKey.CheckSumSize);
|
537 | }
|
538 | };
|
539 |
|
540 |
|
541 |
|
542 |
|
543 |
|
544 |
|
545 |
|
546 | HDPrivateKey.prototype.toString = function() {
|
547 | return this.xprivkey;
|
548 | };
|
549 |
|
550 |
|
551 |
|
552 |
|
553 |
|
554 | HDPrivateKey.prototype.inspect = function() {
|
555 | return '<HDPrivateKey: ' + this.xprivkey + '>';
|
556 | };
|
557 |
|
558 |
|
559 |
|
560 |
|
561 |
|
562 |
|
563 |
|
564 |
|
565 |
|
566 |
|
567 |
|
568 |
|
569 |
|
570 |
|
571 |
|
572 |
|
573 |
|
574 |
|
575 |
|
576 |
|
577 | HDPrivateKey.prototype.toObject = HDPrivateKey.prototype.toJSON = function toObject() {
|
578 | return {
|
579 | network: Network.get(BufferUtil.integerFromBuffer(this._buffers.version), 'xprivkey').name,
|
580 | depth: BufferUtil.integerFromSingleByteBuffer(this._buffers.depth),
|
581 | fingerPrint: BufferUtil.integerFromBuffer(this.fingerPrint),
|
582 | parentFingerPrint: BufferUtil.integerFromBuffer(this._buffers.parentFingerPrint),
|
583 | childIndex: BufferUtil.integerFromBuffer(this._buffers.childIndex),
|
584 | chainCode: BufferUtil.bufferToHex(this._buffers.chainCode),
|
585 | privateKey: this.privateKey.toBuffer().toString('hex'),
|
586 | checksum: BufferUtil.integerFromBuffer(this._buffers.checksum),
|
587 | xprivkey: this.xprivkey
|
588 | };
|
589 | };
|
590 |
|
591 |
|
592 |
|
593 |
|
594 |
|
595 |
|
596 |
|
597 | HDPrivateKey.fromBuffer = function(arg) {
|
598 | return new HDPrivateKey(arg.toString());
|
599 | };
|
600 |
|
601 |
|
602 |
|
603 |
|
604 |
|
605 |
|
606 | HDPrivateKey.prototype.toBuffer = function() {
|
607 | return BufferUtil.copy(this._buffers.xprivkey);
|
608 | };
|
609 |
|
610 | HDPrivateKey.DefaultDepth = 0;
|
611 | HDPrivateKey.DefaultFingerprint = 0;
|
612 | HDPrivateKey.DefaultChildIndex = 0;
|
613 | HDPrivateKey.Hardened = 0x80000000;
|
614 | HDPrivateKey.MaxIndex = 2 * HDPrivateKey.Hardened;
|
615 |
|
616 | HDPrivateKey.RootElementAlias = ['m', 'M', 'm\'', 'M\''];
|
617 |
|
618 | HDPrivateKey.VersionSize = 4;
|
619 | HDPrivateKey.DepthSize = 1;
|
620 | HDPrivateKey.ParentFingerPrintSize = 4;
|
621 | HDPrivateKey.ChildIndexSize = 4;
|
622 | HDPrivateKey.ChainCodeSize = 32;
|
623 | HDPrivateKey.PrivateKeySize = 32;
|
624 | HDPrivateKey.CheckSumSize = 4;
|
625 |
|
626 | HDPrivateKey.DataLength = 78;
|
627 | HDPrivateKey.SerializedByteSize = 82;
|
628 |
|
629 | HDPrivateKey.VersionStart = 0;
|
630 | HDPrivateKey.VersionEnd = HDPrivateKey.VersionStart + HDPrivateKey.VersionSize;
|
631 | HDPrivateKey.DepthStart = HDPrivateKey.VersionEnd;
|
632 | HDPrivateKey.DepthEnd = HDPrivateKey.DepthStart + HDPrivateKey.DepthSize;
|
633 | HDPrivateKey.ParentFingerPrintStart = HDPrivateKey.DepthEnd;
|
634 | HDPrivateKey.ParentFingerPrintEnd = HDPrivateKey.ParentFingerPrintStart + HDPrivateKey.ParentFingerPrintSize;
|
635 | HDPrivateKey.ChildIndexStart = HDPrivateKey.ParentFingerPrintEnd;
|
636 | HDPrivateKey.ChildIndexEnd = HDPrivateKey.ChildIndexStart + HDPrivateKey.ChildIndexSize;
|
637 | HDPrivateKey.ChainCodeStart = HDPrivateKey.ChildIndexEnd;
|
638 | HDPrivateKey.ChainCodeEnd = HDPrivateKey.ChainCodeStart + HDPrivateKey.ChainCodeSize;
|
639 | HDPrivateKey.PrivateKeyStart = HDPrivateKey.ChainCodeEnd + 1;
|
640 | HDPrivateKey.PrivateKeyEnd = HDPrivateKey.PrivateKeyStart + HDPrivateKey.PrivateKeySize;
|
641 | HDPrivateKey.ChecksumStart = HDPrivateKey.PrivateKeyEnd;
|
642 | HDPrivateKey.ChecksumEnd = HDPrivateKey.ChecksumStart + HDPrivateKey.CheckSumSize;
|
643 |
|
644 | assert(HDPrivateKey.ChecksumEnd === HDPrivateKey.SerializedByteSize);
|
645 |
|
646 | module.exports = HDPrivateKey;
|