@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.
Files changed (138) hide show
  1. package/.mocharc.yaml +3 -0
  2. package/index.d.ts +1541 -0
  3. package/index.js +74 -0
  4. package/lib/address.js +478 -0
  5. package/lib/block/block.js +277 -0
  6. package/lib/block/blockheader.js +295 -0
  7. package/lib/block/index.js +4 -0
  8. package/lib/block/merkleblock.js +323 -0
  9. package/lib/bn.js +3423 -0
  10. package/lib/crypto/bn.js +278 -0
  11. package/lib/crypto/ecdsa.js +339 -0
  12. package/lib/crypto/hash.browser.js +171 -0
  13. package/lib/crypto/hash.js +2 -0
  14. package/lib/crypto/hash.node.js +171 -0
  15. package/lib/crypto/point.js +221 -0
  16. package/lib/crypto/random.browser.js +28 -0
  17. package/lib/crypto/random.js +2 -0
  18. package/lib/crypto/random.node.js +11 -0
  19. package/lib/crypto/signature.js +325 -0
  20. package/lib/encoding/base58.js +111 -0
  21. package/lib/encoding/base58check.js +121 -0
  22. package/lib/encoding/bufferreader.js +212 -0
  23. package/lib/encoding/bufferwriter.js +140 -0
  24. package/lib/encoding/decode-asm.js +24 -0
  25. package/lib/encoding/decode-hex.js +32 -0
  26. package/lib/encoding/decode-script-chunks.js +43 -0
  27. package/lib/encoding/encode-hex.js +284 -0
  28. package/lib/encoding/is-hex.js +7 -0
  29. package/lib/encoding/varint.js +75 -0
  30. package/lib/errors/index.js +54 -0
  31. package/lib/errors/spec.js +314 -0
  32. package/lib/hash-cache.js +50 -0
  33. package/lib/hdprivatekey.js +678 -0
  34. package/lib/hdpublickey.js +525 -0
  35. package/lib/message/message.js +191 -0
  36. package/lib/mnemonic/mnemonic.js +303 -0
  37. package/lib/mnemonic/pbkdf2.browser.js +68 -0
  38. package/lib/mnemonic/pbkdf2.js +2 -0
  39. package/lib/mnemonic/pbkdf2.node.js +68 -0
  40. package/lib/mnemonic/words/chinese.js +2054 -0
  41. package/lib/mnemonic/words/english.js +2054 -0
  42. package/lib/mnemonic/words/french.js +2054 -0
  43. package/lib/mnemonic/words/index.js +8 -0
  44. package/lib/mnemonic/words/italian.js +2054 -0
  45. package/lib/mnemonic/words/japanese.js +2054 -0
  46. package/lib/mnemonic/words/spanish.js +2054 -0
  47. package/lib/networks.js +379 -0
  48. package/lib/opcode.js +255 -0
  49. package/lib/privatekey.js +374 -0
  50. package/lib/publickey.js +386 -0
  51. package/lib/script/index.js +5 -0
  52. package/lib/script/interpreter.js +1834 -0
  53. package/lib/script/script.js +1074 -0
  54. package/lib/script/stack.js +109 -0
  55. package/lib/script/write-i32-le.js +17 -0
  56. package/lib/script/write-push-data.js +35 -0
  57. package/lib/script/write-u16-le.js +12 -0
  58. package/lib/script/write-u32-le.js +16 -0
  59. package/lib/script/write-u64-le.js +24 -0
  60. package/lib/script/write-u8-le.js +8 -0
  61. package/lib/script/write-varint.js +46 -0
  62. package/lib/transaction/index.js +7 -0
  63. package/lib/transaction/input/index.js +5 -0
  64. package/lib/transaction/input/input.js +354 -0
  65. package/lib/transaction/input/multisig.js +242 -0
  66. package/lib/transaction/input/publickey.js +100 -0
  67. package/lib/transaction/input/publickeyhash.js +118 -0
  68. package/lib/transaction/output.js +231 -0
  69. package/lib/transaction/sighash.js +167 -0
  70. package/lib/transaction/signature.js +97 -0
  71. package/lib/transaction/transaction.js +1639 -0
  72. package/lib/transaction/unspentoutput.js +113 -0
  73. package/lib/util/_.js +47 -0
  74. package/lib/util/js.js +90 -0
  75. package/lib/util/preconditions.js +33 -0
  76. package/package.json +26 -0
  77. package/test/address.js +509 -0
  78. package/test/block/block.js +251 -0
  79. package/test/block/blockheader.js +275 -0
  80. package/test/block/merklebloack.js +211 -0
  81. package/test/crypto/bn.js +177 -0
  82. package/test/crypto/ecdsa.js +391 -0
  83. package/test/crypto/hash.browser.js +135 -0
  84. package/test/crypto/hash.js +136 -0
  85. package/test/crypto/point.js +224 -0
  86. package/test/crypto/random.js +32 -0
  87. package/test/crypto/signature.js +409 -0
  88. package/test/data/bip69.json +215 -0
  89. package/test/data/bitcoind/base58_keys_invalid.json +52 -0
  90. package/test/data/bitcoind/base58_keys_valid.json +335 -0
  91. package/test/data/bitcoind/blocks.json +22 -0
  92. package/test/data/bitcoind/script_tests.json +3822 -0
  93. package/test/data/bitcoind/sig_canonical.json +7 -0
  94. package/test/data/bitcoind/sig_noncanonical.json +36 -0
  95. package/test/data/bitcoind/tx_invalid.json +445 -0
  96. package/test/data/bitcoind/tx_valid.json +44 -0
  97. package/test/data/blk86756-testnet.dat +0 -0
  98. package/test/data/blk86756-testnet.js +14 -0
  99. package/test/data/blk86756-testnet.json +684 -0
  100. package/test/data/block.hex +1 -0
  101. package/test/data/ecdsa.json +230 -0
  102. package/test/data/merkleblocks.js +488 -0
  103. package/test/data/messages.json +22 -0
  104. package/test/data/sighash.json +12 -0
  105. package/test/data/tx_creation.json +95 -0
  106. package/test/encoding/base58.js +131 -0
  107. package/test/encoding/base58check.js +136 -0
  108. package/test/encoding/bufferreader.js +337 -0
  109. package/test/encoding/bufferwriter.js +172 -0
  110. package/test/encoding/varint.js +104 -0
  111. package/test/hashCache.js +67 -0
  112. package/test/hdkeys.js +445 -0
  113. package/test/hdprivatekey.js +332 -0
  114. package/test/hdpublickey.js +304 -0
  115. package/test/index.js +16 -0
  116. package/test/message/message.js +204 -0
  117. package/test/mnemonic/data/fixtures.json +300 -0
  118. package/test/mnemonic/mnemonic.js +259 -0
  119. package/test/mnemonic/mocha.opts +1 -0
  120. package/test/mnemonic/pbkdf2.test.js +59 -0
  121. package/test/networks.js +159 -0
  122. package/test/opcode.js +161 -0
  123. package/test/privatekey.js +439 -0
  124. package/test/publickey.js +554 -0
  125. package/test/script/interpreter.js +734 -0
  126. package/test/script/script.js +1437 -0
  127. package/test/transaction/deserialize.js +34 -0
  128. package/test/transaction/input/input.js +90 -0
  129. package/test/transaction/input/multisig.js +90 -0
  130. package/test/transaction/input/publickey.js +68 -0
  131. package/test/transaction/input/publickeyhash.js +51 -0
  132. package/test/transaction/output.js +185 -0
  133. package/test/transaction/sighash.js +65 -0
  134. package/test/transaction/signature.js +114 -0
  135. package/test/transaction/transaction.js +1109 -0
  136. package/test/transaction/unspentoutput.js +110 -0
  137. package/test/util/js.js +76 -0
  138. package/test/util/preconditions.js +79 -0
@@ -0,0 +1,525 @@
1
+ 'use strict';
2
+
3
+ var _ = require('./util/_');
4
+ var $ = require('./util/preconditions');
5
+
6
+ var BN = require('./crypto/bn');
7
+ var Base58 = require('./encoding/base58');
8
+ var Base58Check = require('./encoding/base58check');
9
+ var Hash = require('./crypto/hash');
10
+ var HDPrivateKey = require('./hdprivatekey');
11
+ var Network = require('./networks');
12
+ var Point = require('./crypto/point');
13
+ var PublicKey = require('./publickey');
14
+
15
+ var opcatErrors = require('./errors');
16
+ var errors = opcatErrors;
17
+ var hdErrors = opcatErrors.HDPublicKey;
18
+ var assert = require('assert');
19
+
20
+ var JSUtil = require('./util/js');
21
+
22
+ /**
23
+ * The representation of an hierarchically derived public key.
24
+ *
25
+ * See https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
26
+ *
27
+ * @constructor
28
+ * @param {Object|string|Buffer} arg
29
+ */
30
+ function HDPublicKey(arg) {
31
+ if (arg instanceof HDPublicKey) {
32
+ return arg;
33
+ }
34
+ if (!(this instanceof HDPublicKey)) {
35
+ return new HDPublicKey(arg);
36
+ }
37
+ if (arg) {
38
+ if (_.isString(arg) || Buffer.isBuffer(arg)) {
39
+ var error = HDPublicKey.getSerializedError(arg);
40
+ if (!error) {
41
+ return this._buildFromSerialized(arg);
42
+ } else if (Buffer.isBuffer(arg) && !HDPublicKey.getSerializedError(arg.toString())) {
43
+ return this._buildFromSerialized(arg.toString());
44
+ } else {
45
+ if (error instanceof hdErrors.ArgumentIsPrivateExtended) {
46
+ return new HDPrivateKey(arg).hdPublicKey;
47
+ }
48
+ throw error;
49
+ }
50
+ } else {
51
+ if (_.isObject(arg)) {
52
+ if (arg instanceof HDPrivateKey) {
53
+ return this._buildFromPrivate(arg);
54
+ } else {
55
+ return this._buildFromObject(arg);
56
+ }
57
+ } else {
58
+ throw new hdErrors.UnrecognizedArgument(arg);
59
+ }
60
+ }
61
+ } else {
62
+ throw new hdErrors.MustSupplyArgument();
63
+ }
64
+ }
65
+
66
+ HDPublicKey.fromHDPrivateKey = function (hdPrivateKey) {
67
+ return new HDPublicKey(hdPrivateKey);
68
+ };
69
+
70
+ /**
71
+ * Verifies that a given path is valid.
72
+ *
73
+ * @param {string|number} arg
74
+ * @return {boolean}
75
+ */
76
+ HDPublicKey.isValidPath = function (arg) {
77
+ if (_.isString(arg)) {
78
+ var indexes = HDPrivateKey._getDerivationIndexes(arg);
79
+ return indexes !== null && _.every(indexes, HDPublicKey.isValidPath);
80
+ }
81
+
82
+ if (_.isNumber(arg)) {
83
+ return arg >= 0 && arg < HDPublicKey.Hardened;
84
+ }
85
+
86
+ return false;
87
+ };
88
+
89
+ /**
90
+ * WARNING: This method is deprecated. Use deriveChild instead.
91
+ *
92
+ *
93
+ * Get a derivated child based on a string or number.
94
+ *
95
+ * If the first argument is a string, it's parsed as the full path of
96
+ * derivation. Valid values for this argument include "m" (which returns the
97
+ * same public key), "m/0/1/40/2/1000".
98
+ *
99
+ * Note that hardened keys can't be derived from a public extended key.
100
+ *
101
+ * If the first argument is a number, the child with that index will be
102
+ * derived. See the example usage for clarification.
103
+ *
104
+ * @example
105
+ * ```javascript
106
+ * var parent = new HDPublicKey('xpub...');
107
+ * var child_0_1_2 = parent.derive(0).derive(1).derive(2);
108
+ * var copy_of_child_0_1_2 = parent.derive("m/0/1/2");
109
+ * assert(child_0_1_2.xprivkey === copy_of_child_0_1_2);
110
+ * ```
111
+ *
112
+ * @param {string|number} arg
113
+ */
114
+ HDPublicKey.prototype.derive = function () {
115
+ throw new Error(
116
+ 'derive has been deprecated. use deriveChild or, for the old way, deriveNonCompliantChild.',
117
+ );
118
+ };
119
+
120
+ /**
121
+ * WARNING: This method will not be officially supported until v1.0.0.
122
+ *
123
+ *
124
+ * Get a derivated child based on a string or number.
125
+ *
126
+ * If the first argument is a string, it's parsed as the full path of
127
+ * derivation. Valid values for this argument include "m" (which returns the
128
+ * same public key), "m/0/1/40/2/1000".
129
+ *
130
+ * Note that hardened keys can't be derived from a public extended key.
131
+ *
132
+ * If the first argument is a number, the child with that index will be
133
+ * derived. See the example usage for clarification.
134
+ *
135
+ * @example
136
+ * ```javascript
137
+ * var parent = new HDPublicKey('xpub...');
138
+ * var child_0_1_2 = parent.deriveChild(0).deriveChild(1).deriveChild(2);
139
+ * var copy_of_child_0_1_2 = parent.deriveChild("m/0/1/2");
140
+ * assert(child_0_1_2.xprivkey === copy_of_child_0_1_2);
141
+ * ```
142
+ *
143
+ * @param {string|number} arg
144
+ */
145
+ HDPublicKey.prototype.deriveChild = function (arg, hardened) {
146
+ if (_.isNumber(arg)) {
147
+ return this._deriveWithNumber(arg, hardened);
148
+ } else if (_.isString(arg)) {
149
+ return this._deriveFromString(arg);
150
+ } else {
151
+ throw new hdErrors.InvalidDerivationArgument(arg);
152
+ }
153
+ };
154
+
155
+ HDPublicKey.prototype._deriveWithNumber = function (index, hardened) {
156
+ if (index >= HDPublicKey.Hardened || hardened) {
157
+ throw new hdErrors.InvalidIndexCantDeriveHardened();
158
+ }
159
+ if (index < 0) {
160
+ throw new hdErrors.InvalidPath(index);
161
+ }
162
+
163
+ var indexBuffer = JSUtil.integerAsBuffer(index);
164
+ var data = Buffer.concat([this.publicKey.toBuffer(), indexBuffer]);
165
+ var hash = Hash.sha512hmac(data, this._buffers.chainCode);
166
+ var leftPart = BN.fromBuffer(hash.slice(0, 32), { size: 32 });
167
+ var chainCode = hash.slice(32, 64);
168
+
169
+ var publicKey;
170
+ try {
171
+ publicKey = PublicKey.fromPoint(Point.getG().mul(leftPart).add(this.publicKey.point));
172
+ } catch (e) {
173
+ return this._deriveWithNumber(index + 1);
174
+ }
175
+
176
+ var derived = new HDPublicKey({
177
+ network: this.network,
178
+ depth: this.depth + 1,
179
+ parentFingerPrint: this.fingerPrint,
180
+ childIndex: index,
181
+ chainCode: chainCode,
182
+ publicKey: publicKey,
183
+ });
184
+
185
+ return derived;
186
+ };
187
+
188
+ HDPublicKey.prototype._deriveFromString = function (path) {
189
+ if (_.includes(path, "'")) {
190
+ throw new hdErrors.InvalidIndexCantDeriveHardened();
191
+ } else if (!HDPublicKey.isValidPath(path)) {
192
+ throw new hdErrors.InvalidPath(path);
193
+ }
194
+
195
+ var indexes = HDPrivateKey._getDerivationIndexes(path);
196
+ var derived = indexes.reduce(function (prev, index) {
197
+ return prev._deriveWithNumber(index);
198
+ }, this);
199
+
200
+ return derived;
201
+ };
202
+
203
+ /**
204
+ * Verifies that a given serialized public key in base58 with checksum format
205
+ * is valid.
206
+ *
207
+ * @param {string|Buffer} data - the serialized public key
208
+ * @param {string|Network=} network - optional, if present, checks that the
209
+ * network provided matches the network serialized.
210
+ * @return {boolean}
211
+ */
212
+ HDPublicKey.isValidSerialized = function (data, network) {
213
+ return _.isNull(HDPublicKey.getSerializedError(data, network));
214
+ };
215
+
216
+ /**
217
+ * Checks what's the error that causes the validation of a serialized public key
218
+ * in base58 with checksum to fail.
219
+ *
220
+ * @param {string|Buffer} data - the serialized public key
221
+ * @param {string|Network=} network - optional, if present, checks that the
222
+ * network provided matches the network serialized.
223
+ * @return {errors|null}
224
+ */
225
+ HDPublicKey.getSerializedError = function (data, network) {
226
+ if (!(_.isString(data) || Buffer.isBuffer(data))) {
227
+ return new hdErrors.UnrecognizedArgument('expected buffer or string');
228
+ }
229
+ if (!Base58.validCharacters(data)) {
230
+ return new errors.InvalidB58Char('(unknown)', data);
231
+ }
232
+ try {
233
+ data = Base58Check.decode(data);
234
+ } catch (e) {
235
+ return new errors.InvalidB58Checksum(data);
236
+ }
237
+ if (data.length !== HDPublicKey.DataSize) {
238
+ return new hdErrors.InvalidLength(data);
239
+ }
240
+ if (!_.isUndefined(network)) {
241
+ var error = HDPublicKey._validateNetwork(data, network);
242
+ if (error) {
243
+ return error;
244
+ }
245
+ }
246
+ var version = data.readUInt32BE(0);
247
+ if (version === Network.livenet.xprivkey || version === Network.testnet.xprivkey) {
248
+ return new hdErrors.ArgumentIsPrivateExtended();
249
+ }
250
+ return null;
251
+ };
252
+
253
+ HDPublicKey._validateNetwork = function (data, networkArg) {
254
+ var network = Network.get(networkArg);
255
+ if (!network) {
256
+ return new errors.InvalidNetworkArgument(networkArg);
257
+ }
258
+ var version = data.slice(HDPublicKey.VersionStart, HDPublicKey.VersionEnd);
259
+ if (version.readUInt32BE(0) !== network.xpubkey) {
260
+ return new errors.InvalidNetwork(version);
261
+ }
262
+ return null;
263
+ };
264
+
265
+ HDPublicKey.prototype._buildFromPrivate = function (arg) {
266
+ var args = _.clone(arg._buffers);
267
+ var point = Point.getG().mul(BN.fromBuffer(args.privateKey));
268
+ args.publicKey = Point.pointToCompressed(point);
269
+ args.version = JSUtil.integerAsBuffer(Network.get(args.version.readUInt32BE(0)).xpubkey);
270
+ args.privateKey = undefined;
271
+ args.checksum = undefined;
272
+ args.xprivkey = undefined;
273
+ return this._buildFromBuffers(args);
274
+ };
275
+
276
+ HDPublicKey.prototype._buildFromObject = function (arg) {
277
+ // TODO: Type validation
278
+ var buffers = {
279
+ version: arg.network ? JSUtil.integerAsBuffer(Network.get(arg.network).xpubkey) : arg.version,
280
+ depth: _.isNumber(arg.depth) ? Buffer.from([arg.depth & 0xff]) : arg.depth,
281
+ parentFingerPrint: _.isNumber(arg.parentFingerPrint)
282
+ ? JSUtil.integerAsBuffer(arg.parentFingerPrint)
283
+ : arg.parentFingerPrint,
284
+ childIndex: _.isNumber(arg.childIndex)
285
+ ? JSUtil.integerAsBuffer(arg.childIndex)
286
+ : arg.childIndex,
287
+ chainCode: _.isString(arg.chainCode) ? Buffer.from(arg.chainCode, 'hex') : arg.chainCode,
288
+ publicKey: _.isString(arg.publicKey)
289
+ ? Buffer.from(arg.publicKey, 'hex')
290
+ : Buffer.isBuffer(arg.publicKey)
291
+ ? arg.publicKey
292
+ : arg.publicKey.toBuffer(),
293
+ checksum: _.isNumber(arg.checksum) ? JSUtil.integerAsBuffer(arg.checksum) : arg.checksum,
294
+ };
295
+ return this._buildFromBuffers(buffers);
296
+ };
297
+
298
+ HDPublicKey.prototype._buildFromSerialized = function (arg) {
299
+ var decoded = Base58Check.decode(arg);
300
+ var buffers = {
301
+ version: decoded.slice(HDPublicKey.VersionStart, HDPublicKey.VersionEnd),
302
+ depth: decoded.slice(HDPublicKey.DepthStart, HDPublicKey.DepthEnd),
303
+ parentFingerPrint: decoded.slice(
304
+ HDPublicKey.ParentFingerPrintStart,
305
+ HDPublicKey.ParentFingerPrintEnd,
306
+ ),
307
+ childIndex: decoded.slice(HDPublicKey.ChildIndexStart, HDPublicKey.ChildIndexEnd),
308
+ chainCode: decoded.slice(HDPublicKey.ChainCodeStart, HDPublicKey.ChainCodeEnd),
309
+ publicKey: decoded.slice(HDPublicKey.PublicKeyStart, HDPublicKey.PublicKeyEnd),
310
+ checksum: decoded.slice(HDPublicKey.ChecksumStart, HDPublicKey.ChecksumEnd),
311
+ xpubkey: arg,
312
+ };
313
+ return this._buildFromBuffers(buffers);
314
+ };
315
+
316
+ /**
317
+ * Receives a object with buffers in all the properties and populates the
318
+ * internal structure
319
+ *
320
+ * @param {Object} arg
321
+ * @param {buffer.Buffer} arg.version
322
+ * @param {buffer.Buffer} arg.depth
323
+ * @param {buffer.Buffer} arg.parentFingerPrint
324
+ * @param {buffer.Buffer} arg.childIndex
325
+ * @param {buffer.Buffer} arg.chainCode
326
+ * @param {buffer.Buffer} arg.publicKey
327
+ * @param {buffer.Buffer} arg.checksum
328
+ * @param {string=} arg.xpubkey - if set, don't recalculate the base58
329
+ * representation
330
+ * @return {HDPublicKey} this
331
+ */
332
+ HDPublicKey.prototype._buildFromBuffers = function (arg) {
333
+ HDPublicKey._validateBufferArguments(arg);
334
+
335
+ JSUtil.defineImmutable(this, {
336
+ _buffers: arg,
337
+ });
338
+
339
+ var sequence = [
340
+ arg.version,
341
+ arg.depth,
342
+ arg.parentFingerPrint,
343
+ arg.childIndex,
344
+ arg.chainCode,
345
+ arg.publicKey,
346
+ ];
347
+ var concat = Buffer.concat(sequence);
348
+ var checksum = Base58Check.checksum(concat);
349
+ if (!arg.checksum || !arg.checksum.length) {
350
+ arg.checksum = checksum;
351
+ } else {
352
+ if (arg.checksum.toString('hex') !== checksum.toString('hex')) {
353
+ throw new errors.InvalidB58Checksum(concat, checksum);
354
+ }
355
+ }
356
+ var network = Network.get(arg.version.readUInt32BE(0));
357
+
358
+ var xpubkey;
359
+ xpubkey = Base58Check.encode(Buffer.concat(sequence));
360
+ arg.xpubkey = Buffer.from(xpubkey);
361
+
362
+ var publicKey = new PublicKey(arg.publicKey, { network: network });
363
+ var size = HDPublicKey.ParentFingerPrintSize;
364
+ var fingerPrint = Hash.sha256ripemd160(publicKey.toBuffer()).slice(0, size);
365
+
366
+ JSUtil.defineImmutable(this, {
367
+ xpubkey: xpubkey,
368
+ network: network,
369
+ depth: arg.depth[0],
370
+ publicKey: publicKey,
371
+ fingerPrint: fingerPrint,
372
+ });
373
+
374
+ return this;
375
+ };
376
+
377
+ HDPublicKey._validateBufferArguments = function (arg) {
378
+ var checkBuffer = function (name, size) {
379
+ var buff = arg[name];
380
+ assert(Buffer.isBuffer(buff), name + " argument is not a buffer, it's " + typeof buff);
381
+ assert(
382
+ buff.length === size,
383
+ name + ' has not the expected size: found ' + buff.length + ', expected ' + size,
384
+ );
385
+ };
386
+ checkBuffer('version', HDPublicKey.VersionSize);
387
+ checkBuffer('depth', HDPublicKey.DepthSize);
388
+ checkBuffer('parentFingerPrint', HDPublicKey.ParentFingerPrintSize);
389
+ checkBuffer('childIndex', HDPublicKey.ChildIndexSize);
390
+ checkBuffer('chainCode', HDPublicKey.ChainCodeSize);
391
+ checkBuffer('publicKey', HDPublicKey.PublicKeySize);
392
+ if (arg.checksum && arg.checksum.length) {
393
+ checkBuffer('checksum', HDPublicKey.CheckSumSize);
394
+ }
395
+ };
396
+
397
+ HDPublicKey.fromString = function (arg) {
398
+ $.checkArgument(_.isString(arg), 'No valid string was provided');
399
+ return new HDPublicKey(arg);
400
+ };
401
+
402
+ HDPublicKey.fromObject = function (arg) {
403
+ $.checkArgument(_.isObject(arg), 'No valid argument was provided');
404
+ return new HDPublicKey(arg);
405
+ };
406
+
407
+ /**
408
+ * Returns the base58 checked representation of the public key
409
+ * @return {string} a string starting with "xpub..." in livenet
410
+ */
411
+ HDPublicKey.prototype.toString = function () {
412
+ return this.xpubkey;
413
+ };
414
+
415
+ /**
416
+ * Returns the console representation of this extended public key.
417
+ * @return string
418
+ */
419
+ HDPublicKey.prototype.inspect = function () {
420
+ return '<HDPublicKey: ' + this.xpubkey + '>';
421
+ };
422
+
423
+ /**
424
+ * Returns a plain JavaScript object with information to reconstruct a key.
425
+ *
426
+ * Fields are: <ul>
427
+ * <li> network: 'livenet' or 'testnet'
428
+ * <li> depth: a number from 0 to 255, the depth to the master extended key
429
+ * <li> fingerPrint: a number of 32 bits taken from the hash of the public key
430
+ * <li> fingerPrint: a number of 32 bits taken from the hash of this key's
431
+ * <li> parent's public key
432
+ * <li> childIndex: index with which this key was derived
433
+ * <li> chainCode: string in hexa encoding used for derivation
434
+ * <li> publicKey: string, hexa encoded, in compressed key format
435
+ * <li> checksum: this._buffers.checksum.readUInt32BE(0),
436
+ * <li> xpubkey: the string with the base58 representation of this extended key
437
+ * <li> checksum: the base58 checksum of xpubkey
438
+ * </ul>
439
+ */
440
+ HDPublicKey.prototype.toObject = HDPublicKey.prototype.toJSON = function toObject() {
441
+ return {
442
+ network: Network.get(this._buffers.version.readUInt32BE(0)).name,
443
+ depth: this._buffers.depth[0],
444
+ fingerPrint: this.fingerPrint.readUInt32BE(0),
445
+ parentFingerPrint: this._buffers.parentFingerPrint.readUInt32BE(0),
446
+ childIndex: this._buffers.childIndex.readUInt32BE(0),
447
+ chainCode: this._buffers.chainCode.toString('hex'),
448
+ publicKey: this.publicKey.toString(),
449
+ checksum: this._buffers.checksum.readUInt32BE(0),
450
+ xpubkey: this.xpubkey,
451
+ };
452
+ };
453
+
454
+ /**
455
+ * Create a HDPublicKey from a buffer argument
456
+ *
457
+ * @param {Buffer} arg
458
+ * @return {HDPublicKey}
459
+ */
460
+ HDPublicKey.fromBuffer = function (arg) {
461
+ return new HDPublicKey(arg);
462
+ };
463
+
464
+ /**
465
+ * Create a HDPublicKey from a hex string argument
466
+ *
467
+ * @param {Buffer} arg
468
+ * @return {HDPublicKey}
469
+ */
470
+ HDPublicKey.fromHex = function (hex) {
471
+ return HDPublicKey.fromBuffer(Buffer.from(hex, 'hex'));
472
+ };
473
+
474
+ /**
475
+ * Return a buffer representation of the xpubkey
476
+ *
477
+ * @return {Buffer}
478
+ */
479
+ HDPublicKey.prototype.toBuffer = function () {
480
+ return Buffer.from(this._buffers.xpubkey);
481
+ };
482
+
483
+ /**
484
+ * Return a hex string representation of the xpubkey
485
+ *
486
+ * @return {Buffer}
487
+ */
488
+ HDPublicKey.prototype.toHex = function () {
489
+ return this.toBuffer().toString('hex');
490
+ };
491
+
492
+ HDPublicKey.Hardened = 0x80000000;
493
+ HDPublicKey.RootElementAlias = ['m', 'M'];
494
+
495
+ HDPublicKey.VersionSize = 4;
496
+ HDPublicKey.DepthSize = 1;
497
+ HDPublicKey.ParentFingerPrintSize = 4;
498
+ HDPublicKey.ChildIndexSize = 4;
499
+ HDPublicKey.ChainCodeSize = 32;
500
+ HDPublicKey.PublicKeySize = 33;
501
+ HDPublicKey.CheckSumSize = 4;
502
+
503
+ HDPublicKey.DataSize = 78;
504
+ HDPublicKey.SerializedByteSize = 82;
505
+
506
+ HDPublicKey.VersionStart = 0;
507
+ HDPublicKey.VersionEnd = HDPublicKey.VersionStart + HDPublicKey.VersionSize;
508
+ HDPublicKey.DepthStart = HDPublicKey.VersionEnd;
509
+ HDPublicKey.DepthEnd = HDPublicKey.DepthStart + HDPublicKey.DepthSize;
510
+ HDPublicKey.ParentFingerPrintStart = HDPublicKey.DepthEnd;
511
+ HDPublicKey.ParentFingerPrintEnd =
512
+ HDPublicKey.ParentFingerPrintStart + HDPublicKey.ParentFingerPrintSize;
513
+ HDPublicKey.ChildIndexStart = HDPublicKey.ParentFingerPrintEnd;
514
+ HDPublicKey.ChildIndexEnd = HDPublicKey.ChildIndexStart + HDPublicKey.ChildIndexSize;
515
+ HDPublicKey.ChainCodeStart = HDPublicKey.ChildIndexEnd;
516
+ HDPublicKey.ChainCodeEnd = HDPublicKey.ChainCodeStart + HDPublicKey.ChainCodeSize;
517
+ HDPublicKey.PublicKeyStart = HDPublicKey.ChainCodeEnd;
518
+ HDPublicKey.PublicKeyEnd = HDPublicKey.PublicKeyStart + HDPublicKey.PublicKeySize;
519
+ HDPublicKey.ChecksumStart = HDPublicKey.PublicKeyEnd;
520
+ HDPublicKey.ChecksumEnd = HDPublicKey.ChecksumStart + HDPublicKey.CheckSumSize;
521
+
522
+ assert(HDPublicKey.PublicKeyEnd === HDPublicKey.DataSize);
523
+ assert(HDPublicKey.ChecksumEnd === HDPublicKey.SerializedByteSize);
524
+
525
+ module.exports = HDPublicKey;
@@ -0,0 +1,191 @@
1
+ 'use strict';
2
+
3
+ var _ = require('../util/_');
4
+ var PrivateKey = require('../privatekey');
5
+ var PublicKey = require('../publickey');
6
+ var Address = require('../address');
7
+ var BufferWriter = require('../encoding/bufferwriter');
8
+ var ECDSA = require('../crypto/ecdsa');
9
+ var Signature = require('../crypto/signature');
10
+ var sha256sha256 = require('../crypto/hash').sha256sha256;
11
+ var JSUtil = require('../util/js');
12
+ var $ = require('../util/preconditions');
13
+
14
+ /**
15
+ * constructs a new message to sign and verify.
16
+ *
17
+ * @param {String} message
18
+ * @returns {Message}
19
+ */
20
+ var Message = function Message(message) {
21
+ if (!(this instanceof Message)) {
22
+ return new Message(message);
23
+ }
24
+
25
+ $.checkArgument(
26
+ _.isString(message) || Buffer.isBuffer(message),
27
+ 'First argument should be a string or Buffer',
28
+ );
29
+
30
+ if (_.isString(message)) {
31
+ this.messageBuffer = Buffer.from(message);
32
+ }
33
+
34
+ if (Buffer.isBuffer(message)) {
35
+ this.messageBuffer = message;
36
+ }
37
+ return this;
38
+ };
39
+
40
+ Message.sign = function (message, privateKey) {
41
+ return new Message(message).sign(privateKey);
42
+ };
43
+
44
+ Message.verify = function (message, address, signature) {
45
+ return new Message(message).verify(address, signature);
46
+ };
47
+
48
+ Message.MAGIC_BYTES = Buffer.from('Bitcoin Signed Message:\n');
49
+
50
+ Message.prototype.magicHash = function magicHash() {
51
+ var prefix1 = BufferWriter.varintBufNum(Message.MAGIC_BYTES.length);
52
+ var prefix2 = BufferWriter.varintBufNum(this.messageBuffer.length);
53
+ var buf = Buffer.concat([prefix1, Message.MAGIC_BYTES, prefix2, this.messageBuffer]);
54
+ var hash = sha256sha256(buf);
55
+ return hash;
56
+ };
57
+
58
+ Message.prototype._sign = function _sign(privateKey) {
59
+ $.checkArgument(
60
+ privateKey instanceof PrivateKey,
61
+ 'First argument should be an instance of PrivateKey',
62
+ );
63
+ var hash = this.magicHash();
64
+ return ECDSA.signWithCalcI(hash, privateKey);
65
+ };
66
+
67
+ /**
68
+ * Will sign a message with a given bitcoin private key.
69
+ *
70
+ * @param {PrivateKey} privateKey - An instance of PrivateKey
71
+ * @returns {String} A base64 encoded compact signature
72
+ */
73
+ Message.prototype.sign = function sign(privateKey) {
74
+ var signature = this._sign(privateKey);
75
+ return signature.toCompact().toString('base64');
76
+ };
77
+
78
+ Message.prototype._verify = function _verify(publicKey, signature) {
79
+ $.checkArgument(
80
+ publicKey instanceof PublicKey,
81
+ 'First argument should be an instance of PublicKey',
82
+ );
83
+ $.checkArgument(
84
+ signature instanceof Signature,
85
+ 'Second argument should be an instance of Signature',
86
+ );
87
+ var hash = this.magicHash();
88
+ var verified = ECDSA.verify(hash, signature, publicKey);
89
+ if (!verified) {
90
+ this.error = 'The signature was invalid';
91
+ }
92
+ return verified;
93
+ };
94
+
95
+ /**
96
+ * Will return a boolean of the signature is valid for a given bitcoin address.
97
+ * If it isn't the specific reason is accessible via the "error" member.
98
+ *
99
+ * @param {Address|String} bitcoinAddress - A bitcoin address
100
+ * @param {String} signatureString - A base64 encoded compact signature
101
+ * @returns {Boolean}
102
+ */
103
+ Message.prototype.verify = function verify(bitcoinAddress, signatureString) {
104
+ $.checkArgument(bitcoinAddress);
105
+ $.checkArgument(signatureString && _.isString(signatureString));
106
+
107
+ if (_.isString(bitcoinAddress)) {
108
+ bitcoinAddress = Address.fromString(bitcoinAddress);
109
+ }
110
+ var signature = Signature.fromCompact(Buffer.from(signatureString, 'base64'));
111
+
112
+ // recover the public key
113
+ var ecdsa = new ECDSA();
114
+ ecdsa.hashbuf = this.magicHash();
115
+ ecdsa.sig = signature;
116
+ var publicKey = ecdsa.toPublicKey();
117
+
118
+ var signatureAddress = Address.fromPublicKey(publicKey, bitcoinAddress.network);
119
+
120
+ // check that the recovered address and specified address match
121
+ if (bitcoinAddress.toString() !== signatureAddress.toString()) {
122
+ this.error = 'The signature did not match the message digest';
123
+ return false;
124
+ }
125
+
126
+ return this._verify(publicKey, signature);
127
+ };
128
+
129
+ /**
130
+ * Instantiate a message from a message string
131
+ *
132
+ * @param {String} str - A string of the message
133
+ * @returns {Message} A new instance of a Message
134
+ */
135
+ Message.fromString = function (str) {
136
+ return new Message(str);
137
+ };
138
+
139
+ /**
140
+ * Instantiate a message from JSON
141
+ *
142
+ * @param {String} json - An JSON string or Object with keys: message
143
+ * @returns {Message} A new instance of a Message
144
+ */
145
+ Message.fromJSON = function fromJSON(json) {
146
+ if (JSUtil.isValidJSON(json)) {
147
+ json = JSON.parse(json);
148
+ }
149
+ return Message.fromObject(json);
150
+ };
151
+
152
+ /**
153
+ * @returns {Object} A plain object with the message information
154
+ */
155
+ Message.prototype.toObject = function toObject() {
156
+ return {
157
+ messageHex: this.messageBuffer.toString('hex'),
158
+ };
159
+ };
160
+
161
+ Message.fromObject = function (obj) {
162
+ let messageBuffer = Buffer.from(obj.messageHex, 'hex');
163
+ return new Message(messageBuffer);
164
+ };
165
+
166
+ /**
167
+ * @returns {String} A JSON representation of the message information
168
+ */
169
+ Message.prototype.toJSON = function toJSON() {
170
+ return JSON.stringify(this.toObject());
171
+ };
172
+
173
+ /**
174
+ * Will return a the string representation of the message
175
+ *
176
+ * @returns {String} Message
177
+ */
178
+ Message.prototype.toString = function () {
179
+ return this.messageBuffer.toString();
180
+ };
181
+
182
+ /**
183
+ * Will return a string formatted for the console
184
+ *
185
+ * @returns {String} Message
186
+ */
187
+ Message.prototype.inspect = function () {
188
+ return '<Message: ' + this.toString() + '>';
189
+ };
190
+
191
+ module.exports = Message;