@opcat-labs/opcat 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.mocharc.yaml +3 -0
- package/index.d.ts +1541 -0
- package/index.js +74 -0
- package/lib/address.js +478 -0
- package/lib/block/block.js +277 -0
- package/lib/block/blockheader.js +295 -0
- package/lib/block/index.js +4 -0
- package/lib/block/merkleblock.js +323 -0
- package/lib/bn.js +3423 -0
- package/lib/crypto/bn.js +278 -0
- package/lib/crypto/ecdsa.js +339 -0
- package/lib/crypto/hash.browser.js +171 -0
- package/lib/crypto/hash.js +2 -0
- package/lib/crypto/hash.node.js +171 -0
- package/lib/crypto/point.js +221 -0
- package/lib/crypto/random.browser.js +28 -0
- package/lib/crypto/random.js +2 -0
- package/lib/crypto/random.node.js +11 -0
- package/lib/crypto/signature.js +325 -0
- package/lib/encoding/base58.js +111 -0
- package/lib/encoding/base58check.js +121 -0
- package/lib/encoding/bufferreader.js +212 -0
- package/lib/encoding/bufferwriter.js +140 -0
- package/lib/encoding/decode-asm.js +24 -0
- package/lib/encoding/decode-hex.js +32 -0
- package/lib/encoding/decode-script-chunks.js +43 -0
- package/lib/encoding/encode-hex.js +284 -0
- package/lib/encoding/is-hex.js +7 -0
- package/lib/encoding/varint.js +75 -0
- package/lib/errors/index.js +54 -0
- package/lib/errors/spec.js +314 -0
- package/lib/hash-cache.js +50 -0
- package/lib/hdprivatekey.js +678 -0
- package/lib/hdpublickey.js +525 -0
- package/lib/message/message.js +191 -0
- package/lib/mnemonic/mnemonic.js +303 -0
- package/lib/mnemonic/pbkdf2.browser.js +68 -0
- package/lib/mnemonic/pbkdf2.js +2 -0
- package/lib/mnemonic/pbkdf2.node.js +68 -0
- package/lib/mnemonic/words/chinese.js +2054 -0
- package/lib/mnemonic/words/english.js +2054 -0
- package/lib/mnemonic/words/french.js +2054 -0
- package/lib/mnemonic/words/index.js +8 -0
- package/lib/mnemonic/words/italian.js +2054 -0
- package/lib/mnemonic/words/japanese.js +2054 -0
- package/lib/mnemonic/words/spanish.js +2054 -0
- package/lib/networks.js +379 -0
- package/lib/opcode.js +255 -0
- package/lib/privatekey.js +374 -0
- package/lib/publickey.js +386 -0
- package/lib/script/index.js +5 -0
- package/lib/script/interpreter.js +1834 -0
- package/lib/script/script.js +1074 -0
- package/lib/script/stack.js +109 -0
- package/lib/script/write-i32-le.js +17 -0
- package/lib/script/write-push-data.js +35 -0
- package/lib/script/write-u16-le.js +12 -0
- package/lib/script/write-u32-le.js +16 -0
- package/lib/script/write-u64-le.js +24 -0
- package/lib/script/write-u8-le.js +8 -0
- package/lib/script/write-varint.js +46 -0
- package/lib/transaction/index.js +7 -0
- package/lib/transaction/input/index.js +5 -0
- package/lib/transaction/input/input.js +354 -0
- package/lib/transaction/input/multisig.js +242 -0
- package/lib/transaction/input/publickey.js +100 -0
- package/lib/transaction/input/publickeyhash.js +118 -0
- package/lib/transaction/output.js +231 -0
- package/lib/transaction/sighash.js +167 -0
- package/lib/transaction/signature.js +97 -0
- package/lib/transaction/transaction.js +1639 -0
- package/lib/transaction/unspentoutput.js +113 -0
- package/lib/util/_.js +47 -0
- package/lib/util/js.js +90 -0
- package/lib/util/preconditions.js +33 -0
- package/package.json +26 -0
- package/test/address.js +509 -0
- package/test/block/block.js +251 -0
- package/test/block/blockheader.js +275 -0
- package/test/block/merklebloack.js +211 -0
- package/test/crypto/bn.js +177 -0
- package/test/crypto/ecdsa.js +391 -0
- package/test/crypto/hash.browser.js +135 -0
- package/test/crypto/hash.js +136 -0
- package/test/crypto/point.js +224 -0
- package/test/crypto/random.js +32 -0
- package/test/crypto/signature.js +409 -0
- package/test/data/bip69.json +215 -0
- package/test/data/bitcoind/base58_keys_invalid.json +52 -0
- package/test/data/bitcoind/base58_keys_valid.json +335 -0
- package/test/data/bitcoind/blocks.json +22 -0
- package/test/data/bitcoind/script_tests.json +3822 -0
- package/test/data/bitcoind/sig_canonical.json +7 -0
- package/test/data/bitcoind/sig_noncanonical.json +36 -0
- package/test/data/bitcoind/tx_invalid.json +445 -0
- package/test/data/bitcoind/tx_valid.json +44 -0
- package/test/data/blk86756-testnet.dat +0 -0
- package/test/data/blk86756-testnet.js +14 -0
- package/test/data/blk86756-testnet.json +684 -0
- package/test/data/block.hex +1 -0
- package/test/data/ecdsa.json +230 -0
- package/test/data/merkleblocks.js +488 -0
- package/test/data/messages.json +22 -0
- package/test/data/sighash.json +12 -0
- package/test/data/tx_creation.json +95 -0
- package/test/encoding/base58.js +131 -0
- package/test/encoding/base58check.js +136 -0
- package/test/encoding/bufferreader.js +337 -0
- package/test/encoding/bufferwriter.js +172 -0
- package/test/encoding/varint.js +104 -0
- package/test/hashCache.js +67 -0
- package/test/hdkeys.js +445 -0
- package/test/hdprivatekey.js +332 -0
- package/test/hdpublickey.js +304 -0
- package/test/index.js +16 -0
- package/test/message/message.js +204 -0
- package/test/mnemonic/data/fixtures.json +300 -0
- package/test/mnemonic/mnemonic.js +259 -0
- package/test/mnemonic/mocha.opts +1 -0
- package/test/mnemonic/pbkdf2.test.js +59 -0
- package/test/networks.js +159 -0
- package/test/opcode.js +161 -0
- package/test/privatekey.js +439 -0
- package/test/publickey.js +554 -0
- package/test/script/interpreter.js +734 -0
- package/test/script/script.js +1437 -0
- package/test/transaction/deserialize.js +34 -0
- package/test/transaction/input/input.js +90 -0
- package/test/transaction/input/multisig.js +90 -0
- package/test/transaction/input/publickey.js +68 -0
- package/test/transaction/input/publickeyhash.js +51 -0
- package/test/transaction/output.js +185 -0
- package/test/transaction/sighash.js +65 -0
- package/test/transaction/signature.js +114 -0
- package/test/transaction/transaction.js +1109 -0
- package/test/transaction/unspentoutput.js +110 -0
- package/test/util/js.js +76 -0
- package/test/util/preconditions.js +79 -0
|
@@ -0,0 +1,678 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var assert = require('assert');
|
|
4
|
+
var _ = require('./util/_');
|
|
5
|
+
var $ = require('./util/preconditions');
|
|
6
|
+
|
|
7
|
+
var BN = require('./crypto/bn');
|
|
8
|
+
var Base58 = require('./encoding/base58');
|
|
9
|
+
var Base58Check = require('./encoding/base58check');
|
|
10
|
+
var Hash = require('./crypto/hash');
|
|
11
|
+
var Network = require('./networks');
|
|
12
|
+
var Point = require('./crypto/point');
|
|
13
|
+
var PrivateKey = require('./privatekey');
|
|
14
|
+
var Random = require('./crypto/random');
|
|
15
|
+
|
|
16
|
+
var errors = require('./errors');
|
|
17
|
+
var hdErrors = errors.HDPrivateKey;
|
|
18
|
+
var JSUtil = require('./util/js');
|
|
19
|
+
|
|
20
|
+
var MINIMUM_ENTROPY_BITS = 128;
|
|
21
|
+
var BITS_TO_BYTES = 1 / 8;
|
|
22
|
+
var MAXIMUM_ENTROPY_BITS = 512;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Represents an instance of an hierarchically derived private key.
|
|
26
|
+
*
|
|
27
|
+
* More info on https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
|
|
28
|
+
*
|
|
29
|
+
* @constructor
|
|
30
|
+
* @param {string|Buffer|Object} arg
|
|
31
|
+
*/
|
|
32
|
+
function HDPrivateKey(arg) {
|
|
33
|
+
if (arg instanceof HDPrivateKey) {
|
|
34
|
+
return arg;
|
|
35
|
+
}
|
|
36
|
+
if (!(this instanceof HDPrivateKey)) {
|
|
37
|
+
return new HDPrivateKey(arg);
|
|
38
|
+
}
|
|
39
|
+
if (!arg) {
|
|
40
|
+
return this._generateRandomly();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (Network.get(arg)) {
|
|
44
|
+
return this._generateRandomly(arg);
|
|
45
|
+
} else if (_.isString(arg) || Buffer.isBuffer(arg)) {
|
|
46
|
+
if (HDPrivateKey.isValidSerialized(arg)) {
|
|
47
|
+
this._buildFromSerialized(arg);
|
|
48
|
+
} else if (JSUtil.isValidJSON(arg)) {
|
|
49
|
+
this._buildFromJSON(arg);
|
|
50
|
+
} else if (Buffer.isBuffer(arg) && HDPrivateKey.isValidSerialized(arg.toString())) {
|
|
51
|
+
this._buildFromSerialized(arg.toString());
|
|
52
|
+
} else {
|
|
53
|
+
throw HDPrivateKey.getSerializedError(arg);
|
|
54
|
+
}
|
|
55
|
+
} else if (_.isObject(arg)) {
|
|
56
|
+
this._buildFromObject(arg);
|
|
57
|
+
} else {
|
|
58
|
+
throw new hdErrors.UnrecognizedArgument(arg);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
HDPrivateKey.fromRandom = function () {
|
|
63
|
+
return new HDPrivateKey();
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Verifies that a given path is valid.
|
|
68
|
+
*
|
|
69
|
+
* @param {string|number} arg
|
|
70
|
+
* @param {boolean?} hardened
|
|
71
|
+
* @return {boolean}
|
|
72
|
+
*/
|
|
73
|
+
HDPrivateKey.isValidPath = function (arg, hardened) {
|
|
74
|
+
if (_.isString(arg)) {
|
|
75
|
+
var indexes = HDPrivateKey._getDerivationIndexes(arg);
|
|
76
|
+
return indexes !== null && _.every(indexes, HDPrivateKey.isValidPath);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (_.isNumber(arg)) {
|
|
80
|
+
if (arg < HDPrivateKey.Hardened && hardened === true) {
|
|
81
|
+
arg += HDPrivateKey.Hardened;
|
|
82
|
+
}
|
|
83
|
+
return arg >= 0 && arg < HDPrivateKey.MaxIndex;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return false;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Internal function that splits a string path into a derivation index array.
|
|
91
|
+
* It will return null if the string path is malformed.
|
|
92
|
+
* It does not validate if indexes are in bounds.
|
|
93
|
+
*
|
|
94
|
+
* @param {string} path
|
|
95
|
+
* @return {Array}
|
|
96
|
+
*/
|
|
97
|
+
HDPrivateKey._getDerivationIndexes = function (path) {
|
|
98
|
+
var steps = path.split('/');
|
|
99
|
+
|
|
100
|
+
// Special cases:
|
|
101
|
+
if (_.includes(HDPrivateKey.RootElementAlias, path)) {
|
|
102
|
+
return [];
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (!_.includes(HDPrivateKey.RootElementAlias, steps[0])) {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
var indexes = steps.slice(1).map(function (step) {
|
|
110
|
+
var isHardened = step.slice(-1) === "'";
|
|
111
|
+
if (isHardened) {
|
|
112
|
+
step = step.slice(0, -1);
|
|
113
|
+
}
|
|
114
|
+
if (!step || step[0] === '-') {
|
|
115
|
+
return NaN;
|
|
116
|
+
}
|
|
117
|
+
var index = +step; // cast to number
|
|
118
|
+
if (isHardened) {
|
|
119
|
+
index += HDPrivateKey.Hardened;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return index;
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
return _.some(indexes, isNaN) ? null : indexes;
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* WARNING: This method is deprecated. Use deriveChild or deriveNonCompliantChild instead. This is not BIP32 compliant
|
|
130
|
+
*
|
|
131
|
+
*
|
|
132
|
+
* Get a derived child based on a string or number.
|
|
133
|
+
*
|
|
134
|
+
* If the first argument is a string, it's parsed as the full path of
|
|
135
|
+
* derivation. Valid values for this argument include "m" (which returns the
|
|
136
|
+
* same private key), "m/0/1/40/2'/1000", where the ' quote means a hardened
|
|
137
|
+
* derivation.
|
|
138
|
+
*
|
|
139
|
+
* If the first argument is a number, the child with that index will be
|
|
140
|
+
* derived. If the second argument is truthy, the hardened version will be
|
|
141
|
+
* derived. See the example usage for clarification.
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* ```javascript
|
|
145
|
+
* var parent = new HDPrivateKey('xprv...');
|
|
146
|
+
* var child_0_1_2h = parent.derive(0).derive(1).derive(2, true);
|
|
147
|
+
* var copy_of_child_0_1_2h = parent.derive("m/0/1/2'");
|
|
148
|
+
* assert(child_0_1_2h.xprivkey === copy_of_child_0_1_2h);
|
|
149
|
+
* ```
|
|
150
|
+
*
|
|
151
|
+
* @param {string|number} arg
|
|
152
|
+
* @param {boolean?} hardened
|
|
153
|
+
*/
|
|
154
|
+
HDPrivateKey.prototype.derive = function () {
|
|
155
|
+
throw new Error(
|
|
156
|
+
'derive has been deprecated. use deriveChild or, for the old way, deriveNonCompliantChild.',
|
|
157
|
+
);
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* WARNING: This method will not be officially supported until v1.0.0.
|
|
162
|
+
*
|
|
163
|
+
*
|
|
164
|
+
* Get a derived child based on a string or number.
|
|
165
|
+
*
|
|
166
|
+
* If the first argument is a string, it's parsed as the full path of
|
|
167
|
+
* derivation. Valid values for this argument include "m" (which returns the
|
|
168
|
+
* same private key), "m/0/1/40/2'/1000", where the ' quote means a hardened
|
|
169
|
+
* derivation.
|
|
170
|
+
*
|
|
171
|
+
* If the first argument is a number, the child with that index will be
|
|
172
|
+
* derived. If the second argument is truthy, the hardened version will be
|
|
173
|
+
* derived. See the example usage for clarification.
|
|
174
|
+
*
|
|
175
|
+
* WARNING: The `nonCompliant` option should NOT be used, except for older implementation
|
|
176
|
+
* that used a derivation strategy that used a non-zero padded private key.
|
|
177
|
+
*
|
|
178
|
+
* @example
|
|
179
|
+
* ```javascript
|
|
180
|
+
* var parent = new HDPrivateKey('xprv...');
|
|
181
|
+
* var child_0_1_2h = parent.deriveChild(0).deriveChild(1).deriveChild(2, true);
|
|
182
|
+
* var copy_of_child_0_1_2h = parent.deriveChild("m/0/1/2'");
|
|
183
|
+
* assert(child_0_1_2h.xprivkey === copy_of_child_0_1_2h);
|
|
184
|
+
* ```
|
|
185
|
+
*
|
|
186
|
+
* @param {string|number} arg
|
|
187
|
+
* @param {boolean?} hardened
|
|
188
|
+
*/
|
|
189
|
+
HDPrivateKey.prototype.deriveChild = function (arg, hardened) {
|
|
190
|
+
if (_.isNumber(arg)) {
|
|
191
|
+
return this._deriveWithNumber(arg, hardened);
|
|
192
|
+
} else if (_.isString(arg)) {
|
|
193
|
+
return this._deriveFromString(arg);
|
|
194
|
+
} else {
|
|
195
|
+
throw new hdErrors.InvalidDerivationArgument(arg);
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* WARNING: This method will not be officially supported until v1.0.0
|
|
201
|
+
*
|
|
202
|
+
*
|
|
203
|
+
* WARNING: If this is a new implementation you should NOT use this method, you should be using
|
|
204
|
+
* `derive` instead.
|
|
205
|
+
*
|
|
206
|
+
* This method is explicitly for use and compatibility with an implementation that
|
|
207
|
+
* was not compliant with BIP32 regarding the derivation algorithm. The private key
|
|
208
|
+
* must be 32 bytes hashing, and this implementation will use the non-zero padded
|
|
209
|
+
* serialization of a private key, such that it's still possible to derive the privateKey
|
|
210
|
+
* to recover those funds.
|
|
211
|
+
*
|
|
212
|
+
* @param {string|number} arg
|
|
213
|
+
* @param {boolean?} hardened
|
|
214
|
+
*/
|
|
215
|
+
HDPrivateKey.prototype.deriveNonCompliantChild = function (arg, hardened) {
|
|
216
|
+
if (_.isNumber(arg)) {
|
|
217
|
+
return this._deriveWithNumber(arg, hardened, true);
|
|
218
|
+
} else if (_.isString(arg)) {
|
|
219
|
+
return this._deriveFromString(arg, true);
|
|
220
|
+
} else {
|
|
221
|
+
throw new hdErrors.InvalidDerivationArgument(arg);
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
HDPrivateKey.prototype._deriveWithNumber = function (index, hardened, nonCompliant) {
|
|
226
|
+
if (!HDPrivateKey.isValidPath(index, hardened)) {
|
|
227
|
+
throw new hdErrors.InvalidPath(index);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
hardened = index >= HDPrivateKey.Hardened ? true : hardened;
|
|
231
|
+
if (index < HDPrivateKey.Hardened && hardened === true) {
|
|
232
|
+
index += HDPrivateKey.Hardened;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
var indexBuffer = JSUtil.integerAsBuffer(index);
|
|
236
|
+
var data;
|
|
237
|
+
if (hardened && nonCompliant) {
|
|
238
|
+
// The private key serialization in this case will not be exactly 32 bytes and can be
|
|
239
|
+
// any value less, and the value is not zero-padded.
|
|
240
|
+
var nonZeroPadded = this.privateKey.bn.toBuffer();
|
|
241
|
+
data = Buffer.concat([Buffer.from([0]), nonZeroPadded, indexBuffer]);
|
|
242
|
+
} else if (hardened) {
|
|
243
|
+
// This will use a 32 byte zero padded serialization of the private key
|
|
244
|
+
var privateKeyBuffer = this.privateKey.bn.toBuffer({ size: 32 });
|
|
245
|
+
assert(
|
|
246
|
+
privateKeyBuffer.length === 32,
|
|
247
|
+
'length of private key buffer is expected to be 32 bytes',
|
|
248
|
+
);
|
|
249
|
+
data = Buffer.concat([Buffer.from([0]), privateKeyBuffer, indexBuffer]);
|
|
250
|
+
} else {
|
|
251
|
+
data = Buffer.concat([this.publicKey.toBuffer(), indexBuffer]);
|
|
252
|
+
}
|
|
253
|
+
var hash = Hash.sha512hmac(data, this._buffers.chainCode);
|
|
254
|
+
var leftPart = BN.fromBuffer(hash.slice(0, 32), {
|
|
255
|
+
size: 32,
|
|
256
|
+
});
|
|
257
|
+
var chainCode = hash.slice(32, 64);
|
|
258
|
+
|
|
259
|
+
var privateKey = leftPart.add(this.privateKey.toBigNumber()).umod(Point.getN()).toBuffer({
|
|
260
|
+
size: 32,
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
if (!PrivateKey.isValid(privateKey)) {
|
|
264
|
+
// Index at this point is already hardened, we can pass null as the hardened arg
|
|
265
|
+
return this._deriveWithNumber(index + 1, null, nonCompliant);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
var derived = new HDPrivateKey({
|
|
269
|
+
network: this.network,
|
|
270
|
+
depth: this.depth + 1,
|
|
271
|
+
parentFingerPrint: this.fingerPrint,
|
|
272
|
+
childIndex: index,
|
|
273
|
+
chainCode: chainCode,
|
|
274
|
+
privateKey: privateKey,
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
return derived;
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
HDPrivateKey.prototype._deriveFromString = function (path, nonCompliant) {
|
|
281
|
+
if (!HDPrivateKey.isValidPath(path)) {
|
|
282
|
+
throw new hdErrors.InvalidPath(path);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
var indexes = HDPrivateKey._getDerivationIndexes(path);
|
|
286
|
+
var derived = indexes.reduce(function (prev, index) {
|
|
287
|
+
return prev._deriveWithNumber(index, null, nonCompliant);
|
|
288
|
+
}, this);
|
|
289
|
+
|
|
290
|
+
return derived;
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Verifies that a given serialized private key in base58 with checksum format
|
|
295
|
+
* is valid.
|
|
296
|
+
*
|
|
297
|
+
* @param {string|Buffer} data - the serialized private key
|
|
298
|
+
* @param {string|Network=} network - optional, if present, checks that the
|
|
299
|
+
* network provided matches the network serialized.
|
|
300
|
+
* @return {boolean}
|
|
301
|
+
*/
|
|
302
|
+
HDPrivateKey.isValidSerialized = function (data, network) {
|
|
303
|
+
return !HDPrivateKey.getSerializedError(data, network);
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Checks what's the error that causes the validation of a serialized private key
|
|
308
|
+
* in base58 with checksum to fail.
|
|
309
|
+
*
|
|
310
|
+
* @param {string|Buffer} data - the serialized private key
|
|
311
|
+
* @param {string|Network=} network - optional, if present, checks that the
|
|
312
|
+
* network provided matches the network serialized.
|
|
313
|
+
* @return {errors.InvalidArgument|null}
|
|
314
|
+
*/
|
|
315
|
+
HDPrivateKey.getSerializedError = function (data, network) {
|
|
316
|
+
if (!(_.isString(data) || Buffer.isBuffer(data))) {
|
|
317
|
+
return new hdErrors.UnrecognizedArgument('Expected string or buffer');
|
|
318
|
+
}
|
|
319
|
+
if (!Base58.validCharacters(data)) {
|
|
320
|
+
return new errors.InvalidB58Char('(unknown)', data);
|
|
321
|
+
}
|
|
322
|
+
try {
|
|
323
|
+
data = Base58Check.decode(data);
|
|
324
|
+
} catch (e) {
|
|
325
|
+
return new errors.InvalidB58Checksum(data);
|
|
326
|
+
}
|
|
327
|
+
if (data.length !== HDPrivateKey.DataLength) {
|
|
328
|
+
return new hdErrors.InvalidLength(data);
|
|
329
|
+
}
|
|
330
|
+
if (!_.isUndefined(network)) {
|
|
331
|
+
var error = HDPrivateKey._validateNetwork(data, network);
|
|
332
|
+
if (error) {
|
|
333
|
+
return error;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
return null;
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
HDPrivateKey._validateNetwork = function (data, networkArg) {
|
|
340
|
+
var network = Network.get(networkArg);
|
|
341
|
+
if (!network) {
|
|
342
|
+
return new errors.InvalidNetworkArgument(networkArg);
|
|
343
|
+
}
|
|
344
|
+
var version = data.slice(0, 4);
|
|
345
|
+
if (version.readUInt32BE(0) !== network.xprivkey) {
|
|
346
|
+
return new errors.InvalidNetwork(version);
|
|
347
|
+
}
|
|
348
|
+
return null;
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
HDPrivateKey.fromString = function (arg) {
|
|
352
|
+
$.checkArgument(_.isString(arg), 'No valid string was provided');
|
|
353
|
+
return new HDPrivateKey(arg);
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
HDPrivateKey.fromObject = function (arg) {
|
|
357
|
+
$.checkArgument(_.isObject(arg), 'No valid argument was provided');
|
|
358
|
+
return new HDPrivateKey(arg);
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
HDPrivateKey.prototype._buildFromJSON = function (arg) {
|
|
362
|
+
return this._buildFromObject(JSON.parse(arg));
|
|
363
|
+
};
|
|
364
|
+
|
|
365
|
+
HDPrivateKey.prototype._buildFromObject = function (arg) {
|
|
366
|
+
// TODO: Type validation
|
|
367
|
+
var buffers = {
|
|
368
|
+
version: arg.network ? JSUtil.integerAsBuffer(Network.get(arg.network).xprivkey) : arg.version,
|
|
369
|
+
depth: _.isNumber(arg.depth) ? Buffer.from([arg.depth & 0xff]) : arg.depth,
|
|
370
|
+
parentFingerPrint: _.isNumber(arg.parentFingerPrint)
|
|
371
|
+
? JSUtil.integerAsBuffer(arg.parentFingerPrint)
|
|
372
|
+
: arg.parentFingerPrint,
|
|
373
|
+
childIndex: _.isNumber(arg.childIndex)
|
|
374
|
+
? JSUtil.integerAsBuffer(arg.childIndex)
|
|
375
|
+
: arg.childIndex,
|
|
376
|
+
chainCode: _.isString(arg.chainCode) ? Buffer.from(arg.chainCode, 'hex') : arg.chainCode,
|
|
377
|
+
privateKey:
|
|
378
|
+
_.isString(arg.privateKey) && JSUtil.isHexa(arg.privateKey)
|
|
379
|
+
? Buffer.from(arg.privateKey, 'hex')
|
|
380
|
+
: arg.privateKey,
|
|
381
|
+
checksum: arg.checksum
|
|
382
|
+
? arg.checksum.length
|
|
383
|
+
? arg.checksum
|
|
384
|
+
: JSUtil.integerAsBuffer(arg.checksum)
|
|
385
|
+
: undefined,
|
|
386
|
+
};
|
|
387
|
+
return this._buildFromBuffers(buffers);
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
HDPrivateKey.prototype._buildFromSerialized = function (arg) {
|
|
391
|
+
var decoded = Base58Check.decode(arg);
|
|
392
|
+
var buffers = {
|
|
393
|
+
version: decoded.slice(HDPrivateKey.VersionStart, HDPrivateKey.VersionEnd),
|
|
394
|
+
depth: decoded.slice(HDPrivateKey.DepthStart, HDPrivateKey.DepthEnd),
|
|
395
|
+
parentFingerPrint: decoded.slice(
|
|
396
|
+
HDPrivateKey.ParentFingerPrintStart,
|
|
397
|
+
HDPrivateKey.ParentFingerPrintEnd,
|
|
398
|
+
),
|
|
399
|
+
childIndex: decoded.slice(HDPrivateKey.ChildIndexStart, HDPrivateKey.ChildIndexEnd),
|
|
400
|
+
chainCode: decoded.slice(HDPrivateKey.ChainCodeStart, HDPrivateKey.ChainCodeEnd),
|
|
401
|
+
privateKey: decoded.slice(HDPrivateKey.PrivateKeyStart, HDPrivateKey.PrivateKeyEnd),
|
|
402
|
+
checksum: decoded.slice(HDPrivateKey.ChecksumStart, HDPrivateKey.ChecksumEnd),
|
|
403
|
+
xprivkey: arg,
|
|
404
|
+
};
|
|
405
|
+
return this._buildFromBuffers(buffers);
|
|
406
|
+
};
|
|
407
|
+
|
|
408
|
+
HDPrivateKey.prototype._generateRandomly = function (network) {
|
|
409
|
+
return HDPrivateKey.fromSeed(Random.getRandomBuffer(64), network);
|
|
410
|
+
};
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Generate a private key from a seed, as described in BIP32
|
|
414
|
+
*
|
|
415
|
+
* @param {string|Buffer} hexa
|
|
416
|
+
* @param {*} network
|
|
417
|
+
* @return HDPrivateKey
|
|
418
|
+
*/
|
|
419
|
+
HDPrivateKey.fromSeed = function (hexa, network) {
|
|
420
|
+
if (JSUtil.isHexaString(hexa)) {
|
|
421
|
+
hexa = Buffer.from(hexa, 'hex');
|
|
422
|
+
}
|
|
423
|
+
if (!Buffer.isBuffer(hexa)) {
|
|
424
|
+
throw new hdErrors.InvalidEntropyArgument(hexa);
|
|
425
|
+
}
|
|
426
|
+
if (hexa.length < MINIMUM_ENTROPY_BITS * BITS_TO_BYTES) {
|
|
427
|
+
throw new hdErrors.InvalidEntropyArgument.NotEnoughEntropy(hexa);
|
|
428
|
+
}
|
|
429
|
+
if (hexa.length > MAXIMUM_ENTROPY_BITS * BITS_TO_BYTES) {
|
|
430
|
+
throw new hdErrors.InvalidEntropyArgument.TooMuchEntropy(hexa);
|
|
431
|
+
}
|
|
432
|
+
var hash = Hash.sha512hmac(hexa, Buffer.from('Bitcoin seed'));
|
|
433
|
+
|
|
434
|
+
return new HDPrivateKey({
|
|
435
|
+
network: Network.get(network) || Network.defaultNetwork,
|
|
436
|
+
depth: 0,
|
|
437
|
+
parentFingerPrint: 0,
|
|
438
|
+
childIndex: 0,
|
|
439
|
+
privateKey: hash.slice(0, 32),
|
|
440
|
+
chainCode: hash.slice(32, 64),
|
|
441
|
+
});
|
|
442
|
+
};
|
|
443
|
+
|
|
444
|
+
HDPrivateKey.prototype._calcHDPublicKey = function () {
|
|
445
|
+
if (!this._hdPublicKey) {
|
|
446
|
+
var HDPublicKey = require('./hdpublickey');
|
|
447
|
+
this._hdPublicKey = new HDPublicKey(this);
|
|
448
|
+
}
|
|
449
|
+
};
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* Receives a object with buffers in all the properties and populates the
|
|
453
|
+
* internal structure
|
|
454
|
+
*
|
|
455
|
+
* @param {Object} arg
|
|
456
|
+
* @param {buffer.Buffer} arg.version
|
|
457
|
+
* @param {buffer.Buffer} arg.depth
|
|
458
|
+
* @param {buffer.Buffer} arg.parentFingerPrint
|
|
459
|
+
* @param {buffer.Buffer} arg.childIndex
|
|
460
|
+
* @param {buffer.Buffer} arg.chainCode
|
|
461
|
+
* @param {buffer.Buffer} arg.privateKey
|
|
462
|
+
* @param {buffer.Buffer} arg.checksum
|
|
463
|
+
* @param {string=} arg.xprivkey - if set, don't recalculate the base58
|
|
464
|
+
* representation
|
|
465
|
+
* @return {HDPrivateKey} this
|
|
466
|
+
*/
|
|
467
|
+
HDPrivateKey.prototype._buildFromBuffers = function (arg) {
|
|
468
|
+
HDPrivateKey._validateBufferArguments(arg);
|
|
469
|
+
|
|
470
|
+
JSUtil.defineImmutable(this, {
|
|
471
|
+
_buffers: arg,
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
var sequence = [
|
|
475
|
+
arg.version,
|
|
476
|
+
arg.depth,
|
|
477
|
+
arg.parentFingerPrint,
|
|
478
|
+
arg.childIndex,
|
|
479
|
+
arg.chainCode,
|
|
480
|
+
Buffer.alloc(1),
|
|
481
|
+
arg.privateKey,
|
|
482
|
+
];
|
|
483
|
+
var concat = Buffer.concat(sequence);
|
|
484
|
+
if (!arg.checksum || !arg.checksum.length) {
|
|
485
|
+
arg.checksum = Base58Check.checksum(concat);
|
|
486
|
+
} else {
|
|
487
|
+
if (arg.checksum.toString() !== Base58Check.checksum(concat).toString()) {
|
|
488
|
+
throw new errors.InvalidB58Checksum(concat);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
var network = Network.get(arg.version.readUInt32BE(0));
|
|
493
|
+
var xprivkey;
|
|
494
|
+
xprivkey = Base58Check.encode(Buffer.concat(sequence));
|
|
495
|
+
arg.xprivkey = Buffer.from(xprivkey);
|
|
496
|
+
|
|
497
|
+
var privateKey = new PrivateKey(BN.fromBuffer(arg.privateKey), network);
|
|
498
|
+
var publicKey = privateKey.toPublicKey();
|
|
499
|
+
var size = HDPrivateKey.ParentFingerPrintSize;
|
|
500
|
+
var fingerPrint = Hash.sha256ripemd160(publicKey.toBuffer()).slice(0, size);
|
|
501
|
+
|
|
502
|
+
JSUtil.defineImmutable(this, {
|
|
503
|
+
xprivkey: xprivkey,
|
|
504
|
+
network: network,
|
|
505
|
+
depth: arg.depth[0],
|
|
506
|
+
privateKey: privateKey,
|
|
507
|
+
publicKey: publicKey,
|
|
508
|
+
fingerPrint: fingerPrint,
|
|
509
|
+
});
|
|
510
|
+
|
|
511
|
+
this._hdPublicKey = null;
|
|
512
|
+
|
|
513
|
+
Object.defineProperty(this, 'hdPublicKey', {
|
|
514
|
+
configurable: false,
|
|
515
|
+
enumerable: true,
|
|
516
|
+
get: function () {
|
|
517
|
+
this._calcHDPublicKey();
|
|
518
|
+
return this._hdPublicKey;
|
|
519
|
+
},
|
|
520
|
+
});
|
|
521
|
+
Object.defineProperty(this, 'xpubkey', {
|
|
522
|
+
configurable: false,
|
|
523
|
+
enumerable: true,
|
|
524
|
+
get: function () {
|
|
525
|
+
this._calcHDPublicKey();
|
|
526
|
+
return this._hdPublicKey.xpubkey;
|
|
527
|
+
},
|
|
528
|
+
});
|
|
529
|
+
return this;
|
|
530
|
+
};
|
|
531
|
+
|
|
532
|
+
HDPrivateKey._validateBufferArguments = function (arg) {
|
|
533
|
+
var checkBuffer = function (name, size) {
|
|
534
|
+
var buff = arg[name];
|
|
535
|
+
assert(Buffer.isBuffer(buff), name + ' argument is not a buffer');
|
|
536
|
+
assert(
|
|
537
|
+
buff.length === size,
|
|
538
|
+
name + ' has not the expected size: found ' + buff.length + ', expected ' + size,
|
|
539
|
+
);
|
|
540
|
+
};
|
|
541
|
+
checkBuffer('version', HDPrivateKey.VersionSize);
|
|
542
|
+
checkBuffer('depth', HDPrivateKey.DepthSize);
|
|
543
|
+
checkBuffer('parentFingerPrint', HDPrivateKey.ParentFingerPrintSize);
|
|
544
|
+
checkBuffer('childIndex', HDPrivateKey.ChildIndexSize);
|
|
545
|
+
checkBuffer('chainCode', HDPrivateKey.ChainCodeSize);
|
|
546
|
+
checkBuffer('privateKey', HDPrivateKey.PrivateKeySize);
|
|
547
|
+
if (arg.checksum && arg.checksum.length) {
|
|
548
|
+
checkBuffer('checksum', HDPrivateKey.CheckSumSize);
|
|
549
|
+
}
|
|
550
|
+
};
|
|
551
|
+
|
|
552
|
+
/**
|
|
553
|
+
* Returns the string representation of this private key (a string starting
|
|
554
|
+
* with "xprv..."
|
|
555
|
+
*
|
|
556
|
+
* @return string
|
|
557
|
+
*/
|
|
558
|
+
HDPrivateKey.prototype.toString = function () {
|
|
559
|
+
return this.xprivkey;
|
|
560
|
+
};
|
|
561
|
+
|
|
562
|
+
/**
|
|
563
|
+
* Returns the console representation of this extended private key.
|
|
564
|
+
* @return string
|
|
565
|
+
*/
|
|
566
|
+
HDPrivateKey.prototype.inspect = function () {
|
|
567
|
+
return '<HDPrivateKey: ' + this.xprivkey + '>';
|
|
568
|
+
};
|
|
569
|
+
|
|
570
|
+
/**
|
|
571
|
+
* Returns a plain object with a representation of this private key.
|
|
572
|
+
*
|
|
573
|
+
* Fields include:<ul>
|
|
574
|
+
* <li> network: either 'livenet' or 'testnet'
|
|
575
|
+
* <li> depth: a number ranging from 0 to 255
|
|
576
|
+
* <li> fingerPrint: a number ranging from 0 to 2^32-1, taken from the hash of the
|
|
577
|
+
* <li> associated public key
|
|
578
|
+
* <li> parentFingerPrint: a number ranging from 0 to 2^32-1, taken from the hash
|
|
579
|
+
* <li> of this parent's associated public key or zero.
|
|
580
|
+
* <li> childIndex: the index from which this child was derived (or zero)
|
|
581
|
+
* <li> chainCode: an hexa string representing a number used in the derivation
|
|
582
|
+
* <li> privateKey: the private key associated, in hexa representation
|
|
583
|
+
* <li> xprivkey: the representation of this extended private key in checksum
|
|
584
|
+
* <li> base58 format
|
|
585
|
+
* <li> checksum: the base58 checksum of xprivkey
|
|
586
|
+
* </ul>
|
|
587
|
+
* @return {Object}
|
|
588
|
+
*/
|
|
589
|
+
HDPrivateKey.prototype.toObject = HDPrivateKey.prototype.toJSON = function toObject() {
|
|
590
|
+
return {
|
|
591
|
+
network: Network.get(this._buffers.version.readUInt32BE(0), 'xprivkey').name,
|
|
592
|
+
depth: this._buffers.depth[0],
|
|
593
|
+
fingerPrint: this.fingerPrint.readUInt32BE(0),
|
|
594
|
+
parentFingerPrint: this._buffers.parentFingerPrint.readUInt32BE(0),
|
|
595
|
+
childIndex: this._buffers.childIndex.readUInt32BE(0),
|
|
596
|
+
chainCode: this._buffers.chainCode.toString('hex'),
|
|
597
|
+
privateKey: this.privateKey.toBuffer().toString('hex'),
|
|
598
|
+
checksum: this._buffers.checksum.readUInt32BE(0),
|
|
599
|
+
xprivkey: this.xprivkey,
|
|
600
|
+
};
|
|
601
|
+
};
|
|
602
|
+
|
|
603
|
+
/**
|
|
604
|
+
* Build a HDPrivateKey from a buffer
|
|
605
|
+
*
|
|
606
|
+
* @param {Buffer} arg
|
|
607
|
+
* @return {HDPrivateKey}
|
|
608
|
+
*/
|
|
609
|
+
HDPrivateKey.fromBuffer = function (buf) {
|
|
610
|
+
return new HDPrivateKey(buf.toString());
|
|
611
|
+
};
|
|
612
|
+
|
|
613
|
+
/**
|
|
614
|
+
* Build a HDPrivateKey from a hex string
|
|
615
|
+
*
|
|
616
|
+
* @param {string} hex
|
|
617
|
+
* @return {HDPrivateKey}
|
|
618
|
+
*/
|
|
619
|
+
HDPrivateKey.fromHex = function (hex) {
|
|
620
|
+
return HDPrivateKey.fromBuffer(Buffer.from(hex, 'hex'));
|
|
621
|
+
};
|
|
622
|
+
|
|
623
|
+
/**
|
|
624
|
+
* Returns a buffer representation of the HDPrivateKey
|
|
625
|
+
*
|
|
626
|
+
* @return {string}
|
|
627
|
+
*/
|
|
628
|
+
HDPrivateKey.prototype.toBuffer = function () {
|
|
629
|
+
return Buffer.from(this.toString());
|
|
630
|
+
};
|
|
631
|
+
|
|
632
|
+
/**
|
|
633
|
+
* Returns a hex string representation of the HDPrivateKey
|
|
634
|
+
*
|
|
635
|
+
* @return {string}
|
|
636
|
+
*/
|
|
637
|
+
HDPrivateKey.prototype.toHex = function () {
|
|
638
|
+
return this.toBuffer().toString('hex');
|
|
639
|
+
};
|
|
640
|
+
|
|
641
|
+
HDPrivateKey.DefaultDepth = 0;
|
|
642
|
+
HDPrivateKey.DefaultFingerprint = 0;
|
|
643
|
+
HDPrivateKey.DefaultChildIndex = 0;
|
|
644
|
+
HDPrivateKey.Hardened = 0x80000000;
|
|
645
|
+
HDPrivateKey.MaxIndex = 2 * HDPrivateKey.Hardened;
|
|
646
|
+
|
|
647
|
+
HDPrivateKey.RootElementAlias = ['m', 'M', "m'", "M'"];
|
|
648
|
+
|
|
649
|
+
HDPrivateKey.VersionSize = 4;
|
|
650
|
+
HDPrivateKey.DepthSize = 1;
|
|
651
|
+
HDPrivateKey.ParentFingerPrintSize = 4;
|
|
652
|
+
HDPrivateKey.ChildIndexSize = 4;
|
|
653
|
+
HDPrivateKey.ChainCodeSize = 32;
|
|
654
|
+
HDPrivateKey.PrivateKeySize = 32;
|
|
655
|
+
HDPrivateKey.CheckSumSize = 4;
|
|
656
|
+
|
|
657
|
+
HDPrivateKey.DataLength = 78;
|
|
658
|
+
HDPrivateKey.SerializedByteSize = 82;
|
|
659
|
+
|
|
660
|
+
HDPrivateKey.VersionStart = 0;
|
|
661
|
+
HDPrivateKey.VersionEnd = HDPrivateKey.VersionStart + HDPrivateKey.VersionSize;
|
|
662
|
+
HDPrivateKey.DepthStart = HDPrivateKey.VersionEnd;
|
|
663
|
+
HDPrivateKey.DepthEnd = HDPrivateKey.DepthStart + HDPrivateKey.DepthSize;
|
|
664
|
+
HDPrivateKey.ParentFingerPrintStart = HDPrivateKey.DepthEnd;
|
|
665
|
+
HDPrivateKey.ParentFingerPrintEnd =
|
|
666
|
+
HDPrivateKey.ParentFingerPrintStart + HDPrivateKey.ParentFingerPrintSize;
|
|
667
|
+
HDPrivateKey.ChildIndexStart = HDPrivateKey.ParentFingerPrintEnd;
|
|
668
|
+
HDPrivateKey.ChildIndexEnd = HDPrivateKey.ChildIndexStart + HDPrivateKey.ChildIndexSize;
|
|
669
|
+
HDPrivateKey.ChainCodeStart = HDPrivateKey.ChildIndexEnd;
|
|
670
|
+
HDPrivateKey.ChainCodeEnd = HDPrivateKey.ChainCodeStart + HDPrivateKey.ChainCodeSize;
|
|
671
|
+
HDPrivateKey.PrivateKeyStart = HDPrivateKey.ChainCodeEnd + 1;
|
|
672
|
+
HDPrivateKey.PrivateKeyEnd = HDPrivateKey.PrivateKeyStart + HDPrivateKey.PrivateKeySize;
|
|
673
|
+
HDPrivateKey.ChecksumStart = HDPrivateKey.PrivateKeyEnd;
|
|
674
|
+
HDPrivateKey.ChecksumEnd = HDPrivateKey.ChecksumStart + HDPrivateKey.CheckSumSize;
|
|
675
|
+
|
|
676
|
+
assert(HDPrivateKey.ChecksumEnd === HDPrivateKey.SerializedByteSize);
|
|
677
|
+
|
|
678
|
+
module.exports = HDPrivateKey;
|