@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
package/lib/crypto/bn.js
ADDED
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var BN = require('../bn');
|
|
4
|
+
var $ = require('../util/preconditions');
|
|
5
|
+
var _ = require('../util/_');
|
|
6
|
+
|
|
7
|
+
var reversebuf = function (buf) {
|
|
8
|
+
var buf2 = Buffer.alloc(buf.length);
|
|
9
|
+
for (var i = 0; i < buf.length; i++) {
|
|
10
|
+
buf2[i] = buf[buf.length - 1 - i];
|
|
11
|
+
}
|
|
12
|
+
return buf2;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
BN.Zero = new BN(0);
|
|
16
|
+
BN.One = new BN(1);
|
|
17
|
+
BN.Minus1 = new BN(-1);
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Convert a number into a big number.
|
|
21
|
+
*
|
|
22
|
+
* @param {number} n Any positive or negative integer.
|
|
23
|
+
*/
|
|
24
|
+
BN.fromNumber = function (n) {
|
|
25
|
+
$.checkArgument(_.isNumber(n));
|
|
26
|
+
return BN.fromString(n.toString(16), 16)
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Convert a string number into a big number.
|
|
31
|
+
*
|
|
32
|
+
* @param {string} str Any positive or negative integer formatted as a string.
|
|
33
|
+
* @param {number} base The base of the number, defaults to 10.
|
|
34
|
+
*/
|
|
35
|
+
BN.fromString = function (str, base) {
|
|
36
|
+
$.checkArgument(_.isString(str));
|
|
37
|
+
return new BN(str, base);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Convert a buffer (such as a 256 bit binary private key) into a big number.
|
|
42
|
+
* Sometimes these numbers can be formatted either as 'big endian' or 'little
|
|
43
|
+
* endian', and so there is an opts parameter that lets you specify which
|
|
44
|
+
* endianness is specified.
|
|
45
|
+
*
|
|
46
|
+
* @param {Buffer} buf A buffer number, such as a 256 bit hash or key.
|
|
47
|
+
* @param {Object} opts With a property 'endian' that can be either 'big' or 'little'. Defaults big endian (most significant digit first).
|
|
48
|
+
*/
|
|
49
|
+
BN.fromBuffer = function (buf, opts) {
|
|
50
|
+
if (typeof opts !== 'undefined' && opts.endian === 'little') {
|
|
51
|
+
buf = reversebuf(buf);
|
|
52
|
+
}
|
|
53
|
+
var hex = buf.toString('hex');
|
|
54
|
+
var bn = new BN(hex, 16);
|
|
55
|
+
return bn;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Instantiate a BigNumber from a "signed magnitude buffer". (a buffer where the
|
|
60
|
+
* most significant bit represents the sign (0 = positive, 1 = negative)
|
|
61
|
+
*
|
|
62
|
+
* @param {Buffer} buf A buffer number, such as a 256 bit hash or key.
|
|
63
|
+
* @param {Object} opts With a property 'endian' that can be either 'big' or 'little'. Defaults big endian (most significant digit first).
|
|
64
|
+
*/
|
|
65
|
+
BN.fromSM = function (buf, opts) {
|
|
66
|
+
var ret;
|
|
67
|
+
if (buf.length === 0) {
|
|
68
|
+
return BN.fromBuffer(Buffer.from([0]));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
var endian = 'big';
|
|
72
|
+
if (opts) {
|
|
73
|
+
endian = opts.endian;
|
|
74
|
+
}
|
|
75
|
+
if (endian === 'little') {
|
|
76
|
+
buf = reversebuf(buf);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (buf[0] & 0x80) {
|
|
80
|
+
buf[0] = buf[0] & 0x7f;
|
|
81
|
+
ret = BN.fromBuffer(buf);
|
|
82
|
+
ret.neg().copy(ret);
|
|
83
|
+
} else {
|
|
84
|
+
ret = BN.fromBuffer(buf);
|
|
85
|
+
}
|
|
86
|
+
return ret;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Convert a big number into a number.
|
|
91
|
+
*/
|
|
92
|
+
BN.prototype.toNumber = function () {
|
|
93
|
+
return parseInt(this.toString(10), 10);
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Convert a big number into a buffer. This is somewhat ambiguous, so there is
|
|
98
|
+
* an opts parameter that let's you specify the endianness or the size.
|
|
99
|
+
* opts.endian can be either 'big' or 'little' and opts.size can be any
|
|
100
|
+
* sufficiently large number of bytes. If you always want to create a 32 byte
|
|
101
|
+
* big endian number, then specify opts = { endian: 'big', size: 32 }
|
|
102
|
+
*
|
|
103
|
+
* @param {Object} opts Defaults to { endian: 'big', size: 32 }
|
|
104
|
+
*/
|
|
105
|
+
BN.prototype.toBuffer = function (opts) {
|
|
106
|
+
var buf, hex;
|
|
107
|
+
if (opts && opts.size) {
|
|
108
|
+
hex = this.toString(16, 2);
|
|
109
|
+
var natlen = hex.length / 2;
|
|
110
|
+
buf = Buffer.from(hex, 'hex');
|
|
111
|
+
|
|
112
|
+
if (natlen === opts.size) {
|
|
113
|
+
// buf = buf
|
|
114
|
+
} else if (natlen > opts.size) {
|
|
115
|
+
buf = BN.trim(buf, natlen);
|
|
116
|
+
} else if (natlen < opts.size) {
|
|
117
|
+
buf = BN.pad(buf, natlen, opts.size);
|
|
118
|
+
}
|
|
119
|
+
} else {
|
|
120
|
+
hex = this.toString(16, 2);
|
|
121
|
+
buf = Buffer.from(hex, 'hex');
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (typeof opts !== 'undefined' && opts.endian === 'little') {
|
|
125
|
+
buf = reversebuf(buf);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return buf;
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* For big numbers that are either positive or negative, you can convert to
|
|
133
|
+
* "sign magnitude" format whereby the first bit specifies whether the number is
|
|
134
|
+
* positive or negative.
|
|
135
|
+
*/
|
|
136
|
+
BN.prototype.toSMBigEndian = function () {
|
|
137
|
+
var buf;
|
|
138
|
+
if (this.cmp(BN.Zero) === -1) {
|
|
139
|
+
buf = this.neg().toBuffer();
|
|
140
|
+
if (buf[0] & 0x80) {
|
|
141
|
+
buf = Buffer.concat([Buffer.from([0x80]), buf]);
|
|
142
|
+
} else {
|
|
143
|
+
buf[0] = buf[0] | 0x80;
|
|
144
|
+
}
|
|
145
|
+
} else {
|
|
146
|
+
buf = this.toBuffer();
|
|
147
|
+
if (buf[0] & 0x80) {
|
|
148
|
+
buf = Buffer.concat([Buffer.from([0x00]), buf]);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if ((buf.length === 1) & (buf[0] === 0)) {
|
|
153
|
+
buf = Buffer.from([]);
|
|
154
|
+
}
|
|
155
|
+
return buf;
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* For big numbers that are either positive or negative, you can convert to
|
|
160
|
+
* "sign magnitude" format whereby the first bit specifies whether the number is
|
|
161
|
+
* positive or negative.
|
|
162
|
+
*
|
|
163
|
+
* @param {Object} opts Defaults to { endian: 'big' }
|
|
164
|
+
*/
|
|
165
|
+
BN.prototype.toSM = function (opts) {
|
|
166
|
+
var endian = opts ? opts.endian : 'big';
|
|
167
|
+
var buf = this.toSMBigEndian();
|
|
168
|
+
|
|
169
|
+
if (endian === 'little') {
|
|
170
|
+
buf = reversebuf(buf);
|
|
171
|
+
}
|
|
172
|
+
return buf;
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Create a BN from a "ScriptNum": This is analogous to the constructor for
|
|
177
|
+
* CScriptNum in bitcoind. Many ops in bitcoind's script interpreter use
|
|
178
|
+
* CScriptNum, which is not really a proper bignum. Instead, an error is thrown
|
|
179
|
+
* if trying to input a number bigger than 4 bytes. We copy that behavior here.
|
|
180
|
+
* A third argument, `size`, is provided to extend the hard limit of 4 bytes, as
|
|
181
|
+
* some usages require more than 4 bytes.
|
|
182
|
+
*
|
|
183
|
+
* @param {Buffer} buf A buffer of a number.
|
|
184
|
+
* @param {boolean} fRequireMinimal Whether to require minimal size encoding.
|
|
185
|
+
* @param {number} size The maximum size.
|
|
186
|
+
*/
|
|
187
|
+
BN.fromScriptNumBuffer = function (buf, fRequireMinimal, size) {
|
|
188
|
+
var nMaxNumSize = size || Number.MAX_SAFE_INTEGER;
|
|
189
|
+
$.checkArgument(buf.length <= nMaxNumSize, new Error('script number overflow'));
|
|
190
|
+
if (fRequireMinimal && buf.length > 0) {
|
|
191
|
+
// Check that the number is encoded with the minimum possible
|
|
192
|
+
// number of bytes.
|
|
193
|
+
//
|
|
194
|
+
// If the most-significant-byte - excluding the sign bit - is zero
|
|
195
|
+
// then we're not minimal. Note how this test also rejects the
|
|
196
|
+
// negative-zero encoding, 0x80.
|
|
197
|
+
if ((buf[buf.length - 1] & 0x7f) === 0) {
|
|
198
|
+
// One exception: if there's more than one byte and the most
|
|
199
|
+
// significant bit of the second-most-significant-byte is set
|
|
200
|
+
// it would conflict with the sign bit. An example of this case
|
|
201
|
+
// is +-255, which encode to 0xff00 and 0xff80 respectively.
|
|
202
|
+
// (big-endian).
|
|
203
|
+
if (buf.length <= 1 || (buf[buf.length - 2] & 0x80) === 0) {
|
|
204
|
+
throw new Error('non-minimally encoded script number');
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return BN.fromSM(buf, {
|
|
209
|
+
endian: 'little',
|
|
210
|
+
});
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* The corollary to the above, with the notable exception that we do not throw
|
|
215
|
+
* an error if the output is larger than four bytes. (Which can happen if
|
|
216
|
+
* performing a numerical operation that results in an overflow to more than 4
|
|
217
|
+
* bytes).
|
|
218
|
+
*/
|
|
219
|
+
BN.prototype.toScriptNumBuffer = function () {
|
|
220
|
+
return this.toSM({
|
|
221
|
+
endian: 'little',
|
|
222
|
+
});
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Trims a buffer if it starts with zeros.
|
|
227
|
+
*
|
|
228
|
+
* @param {Buffer} buf A buffer formatted number.
|
|
229
|
+
* @param {number} natlen The natural length of the number.
|
|
230
|
+
*/
|
|
231
|
+
BN.trim = function (buf, natlen) {
|
|
232
|
+
return buf.slice(natlen - buf.length, buf.length);
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Adds extra zeros to the start of a number.
|
|
237
|
+
*
|
|
238
|
+
* @param {Buffer} buf A buffer formatted number.
|
|
239
|
+
* @param {number} natlen The natural length of the number.
|
|
240
|
+
* @param {number} size How big to pad the number in bytes.
|
|
241
|
+
*/
|
|
242
|
+
BN.pad = function (buf, natlen, size) {
|
|
243
|
+
var rbuf = Buffer.alloc(size);
|
|
244
|
+
for (var i = 0; i < buf.length; i++) {
|
|
245
|
+
rbuf[rbuf.length - 1 - i] = buf[buf.length - 1 - i];
|
|
246
|
+
}
|
|
247
|
+
for (i = 0; i < size - natlen; i++) {
|
|
248
|
+
rbuf[i] = 0;
|
|
249
|
+
}
|
|
250
|
+
return rbuf;
|
|
251
|
+
};
|
|
252
|
+
/**
|
|
253
|
+
* Convert a big number into a hex string. This is somewhat ambiguous, so there
|
|
254
|
+
* is an opts parameter that let's you specify the endianness or the size.
|
|
255
|
+
* opts.endian can be either 'big' or 'little' and opts.size can be any
|
|
256
|
+
* sufficiently large number of bytes. If you always want to create a 32 byte
|
|
257
|
+
* big endian number, then specify opts = { endian: 'big', size: 32 }
|
|
258
|
+
*
|
|
259
|
+
* @param {Object} opts Defaults to { endian: 'big', size: 32 }
|
|
260
|
+
*/
|
|
261
|
+
BN.prototype.toHex = function (...args) {
|
|
262
|
+
return this.toBuffer(...args).toString('hex');
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Convert a hex string (such as a 256 bit binary private key) into a big
|
|
267
|
+
* number. Sometimes these numbers can be formatted either as 'big endian' or
|
|
268
|
+
* 'little endian', and so there is an opts parameter that lets you specify
|
|
269
|
+
* which endianness is specified.
|
|
270
|
+
*
|
|
271
|
+
* @param {Buffer} buf A buffer number, such as a 256 bit hash or key.
|
|
272
|
+
* @param {Object} opts With a property 'endian' that can be either 'big' or 'little'. Defaults big endian (most significant digit first).
|
|
273
|
+
*/
|
|
274
|
+
BN.fromHex = function (hex, ...args) {
|
|
275
|
+
return BN.fromBuffer(Buffer.from(hex, 'hex'), ...args);
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
module.exports = BN;
|
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var BN = require('./bn');
|
|
4
|
+
var Point = require('./point');
|
|
5
|
+
var Signature = require('./signature');
|
|
6
|
+
var PublicKey = require('../publickey');
|
|
7
|
+
var Random = require('./random');
|
|
8
|
+
var Hash = require('./hash');
|
|
9
|
+
var _ = require('../util/_');
|
|
10
|
+
var $ = require('../util/preconditions');
|
|
11
|
+
|
|
12
|
+
var ECDSA = function ECDSA(obj) {
|
|
13
|
+
if (!(this instanceof ECDSA)) {
|
|
14
|
+
return new ECDSA(obj);
|
|
15
|
+
}
|
|
16
|
+
if (obj) {
|
|
17
|
+
this.set(obj);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
ECDSA.prototype.set = function (obj) {
|
|
22
|
+
this.hashbuf = obj.hashbuf || this.hashbuf;
|
|
23
|
+
this.endian = obj.endian || this.endian; // the endianness of hashbuf
|
|
24
|
+
this.privkey = obj.privkey || this.privkey;
|
|
25
|
+
this.pubkey = obj.pubkey || (this.privkey ? this.privkey.publicKey : this.pubkey);
|
|
26
|
+
this.sig = obj.sig || this.sig;
|
|
27
|
+
this.k = obj.k || this.k;
|
|
28
|
+
this.verified = obj.verified || this.verified;
|
|
29
|
+
return this;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
ECDSA.prototype.privkey2pubkey = function () {
|
|
33
|
+
this.pubkey = this.privkey.toPublicKey();
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
ECDSA.prototype.calci = function () {
|
|
37
|
+
for (var i = 0; i < 4; i++) {
|
|
38
|
+
this.sig.i = i;
|
|
39
|
+
var Qprime;
|
|
40
|
+
try {
|
|
41
|
+
Qprime = this.toPublicKey();
|
|
42
|
+
} catch (e) {
|
|
43
|
+
console.error(e);
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (Qprime.point.eq(this.pubkey.point)) {
|
|
48
|
+
this.sig.compressed = this.pubkey.compressed;
|
|
49
|
+
return this;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
this.sig.i = undefined;
|
|
54
|
+
throw new Error('Unable to find valid recovery factor');
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
ECDSA.fromString = function (str) {
|
|
58
|
+
var obj = JSON.parse(str);
|
|
59
|
+
return new ECDSA(obj);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
ECDSA.prototype.randomK = function () {
|
|
63
|
+
var N = Point.getN();
|
|
64
|
+
var k;
|
|
65
|
+
do {
|
|
66
|
+
k = BN.fromBuffer(Random.getRandomBuffer(32));
|
|
67
|
+
} while (!(k.lt(N) && k.gt(BN.Zero)));
|
|
68
|
+
this.k = k;
|
|
69
|
+
return this;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
// https://tools.ietf.org/html/rfc6979#section-3.2
|
|
73
|
+
ECDSA.prototype.deterministicK = function (badrs) {
|
|
74
|
+
// if r or s were invalid when this function was used in signing,
|
|
75
|
+
// we do not want to actually compute r, s here for efficiency, so,
|
|
76
|
+
// we can increment badrs. explained at end of RFC 6979 section 3.2
|
|
77
|
+
if (_.isUndefined(badrs)) {
|
|
78
|
+
badrs = 0;
|
|
79
|
+
}
|
|
80
|
+
var v = Buffer.alloc(32);
|
|
81
|
+
v.fill(0x01);
|
|
82
|
+
var k = Buffer.alloc(32);
|
|
83
|
+
k.fill(0x00);
|
|
84
|
+
var x = this.privkey.bn.toBuffer({
|
|
85
|
+
size: 32,
|
|
86
|
+
});
|
|
87
|
+
var hashbuf = this.endian === 'little' ? Buffer.from(this.hashbuf).reverse() : this.hashbuf;
|
|
88
|
+
k = Hash.sha256hmac(Buffer.concat([v, Buffer.from([0x00]), x, hashbuf]), k);
|
|
89
|
+
v = Hash.sha256hmac(v, k);
|
|
90
|
+
k = Hash.sha256hmac(Buffer.concat([v, Buffer.from([0x01]), x, hashbuf]), k);
|
|
91
|
+
v = Hash.sha256hmac(v, k);
|
|
92
|
+
v = Hash.sha256hmac(v, k);
|
|
93
|
+
var T = BN.fromBuffer(v);
|
|
94
|
+
var N = Point.getN();
|
|
95
|
+
|
|
96
|
+
// also explained in 3.2, we must ensure T is in the proper range (0, N)
|
|
97
|
+
for (var i = 0; i < badrs || !(T.lt(N) && T.gt(BN.Zero)); i++) {
|
|
98
|
+
k = Hash.sha256hmac(Buffer.concat([v, Buffer.from([0x00])]), k);
|
|
99
|
+
v = Hash.sha256hmac(v, k);
|
|
100
|
+
v = Hash.sha256hmac(v, k);
|
|
101
|
+
T = BN.fromBuffer(v);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
this.k = T;
|
|
105
|
+
return this;
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
// Information about public key recovery:
|
|
109
|
+
// https://bitcointalk.org/index.php?topic=6430.0
|
|
110
|
+
// http://stackoverflow.com/questions/19665491/how-do-i-get-an-ecdsa-public-key-from-just-a-bitcoin-signature-sec1-4-1-6-k
|
|
111
|
+
ECDSA.prototype.toPublicKey = function () {
|
|
112
|
+
var i = this.sig.i;
|
|
113
|
+
$.checkArgument(
|
|
114
|
+
i === 0 || i === 1 || i === 2 || i === 3,
|
|
115
|
+
new Error('i must be equal to 0, 1, 2, or 3'),
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
var e = BN.fromBuffer(this.hashbuf);
|
|
119
|
+
var r = this.sig.r;
|
|
120
|
+
var s = this.sig.s;
|
|
121
|
+
|
|
122
|
+
// A set LSB signifies that the y-coordinate is odd
|
|
123
|
+
var isYOdd = i & 1;
|
|
124
|
+
|
|
125
|
+
// The more significant bit specifies whether we should use the
|
|
126
|
+
// first or second candidate key.
|
|
127
|
+
var isSecondKey = i >> 1;
|
|
128
|
+
|
|
129
|
+
var n = Point.getN();
|
|
130
|
+
var G = Point.getG();
|
|
131
|
+
|
|
132
|
+
// 1.1 Let x = r + jn
|
|
133
|
+
var x = isSecondKey ? r.add(n) : r;
|
|
134
|
+
var R = Point.fromX(isYOdd, x);
|
|
135
|
+
|
|
136
|
+
// 1.4 Check that nR is at infinity
|
|
137
|
+
var nR = R.mul(n);
|
|
138
|
+
|
|
139
|
+
if (!nR.isInfinity()) {
|
|
140
|
+
throw new Error('nR is not a valid curve point');
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Compute -e from e
|
|
144
|
+
var eNeg = e.neg().umod(n);
|
|
145
|
+
|
|
146
|
+
// 1.6.1 Compute Q = r^-1 (sR - eG)
|
|
147
|
+
// Q = r^-1 (sR + -eG)
|
|
148
|
+
var rInv = r.invm(n);
|
|
149
|
+
|
|
150
|
+
// var Q = R.multiplyTwo(s, G, eNeg).mul(rInv);
|
|
151
|
+
var Q = R.mul(s).add(G.mul(eNeg)).mul(rInv);
|
|
152
|
+
|
|
153
|
+
var pubkey = PublicKey.fromPoint(Q, this.sig.compressed);
|
|
154
|
+
|
|
155
|
+
return pubkey;
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
ECDSA.prototype.sigError = function () {
|
|
159
|
+
if (!Buffer.isBuffer(this.hashbuf) || this.hashbuf.length !== 32) {
|
|
160
|
+
return 'hashbuf must be a 32 byte buffer';
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
var r = this.sig.r;
|
|
164
|
+
var s = this.sig.s;
|
|
165
|
+
if (!(r.gt(BN.Zero) && r.lt(Point.getN())) || !(s.gt(BN.Zero) && s.lt(Point.getN()))) {
|
|
166
|
+
return 'r and s not in range';
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
var e = BN.fromBuffer(
|
|
170
|
+
this.hashbuf,
|
|
171
|
+
this.endian
|
|
172
|
+
? {
|
|
173
|
+
endian: this.endian,
|
|
174
|
+
}
|
|
175
|
+
: undefined,
|
|
176
|
+
);
|
|
177
|
+
var n = Point.getN();
|
|
178
|
+
var sinv = s.invm(n);
|
|
179
|
+
var u1 = sinv.mul(e).umod(n);
|
|
180
|
+
var u2 = sinv.mul(r).umod(n);
|
|
181
|
+
|
|
182
|
+
var p = Point.getG().mulAdd(u1, this.pubkey.point, u2);
|
|
183
|
+
if (p.isInfinity()) {
|
|
184
|
+
return 'p is infinity';
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (p.getX().umod(n).cmp(r) !== 0) {
|
|
188
|
+
return 'Invalid signature';
|
|
189
|
+
} else {
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
ECDSA.toLowS = function (s) {
|
|
195
|
+
// enforce low s
|
|
196
|
+
// see BIP 62, "low S values in signatures"
|
|
197
|
+
if (
|
|
198
|
+
s.gt(
|
|
199
|
+
BN.fromBuffer(
|
|
200
|
+
Buffer.from('7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0', 'hex'),
|
|
201
|
+
),
|
|
202
|
+
)
|
|
203
|
+
) {
|
|
204
|
+
s = Point.getN().sub(s);
|
|
205
|
+
}
|
|
206
|
+
return s;
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
ECDSA.prototype._findSignature = function (d, e) {
|
|
210
|
+
var N = Point.getN();
|
|
211
|
+
var G = Point.getG();
|
|
212
|
+
// try different values of k until r, s are valid
|
|
213
|
+
var badrs = 0;
|
|
214
|
+
var k, Q, r, s;
|
|
215
|
+
do {
|
|
216
|
+
if (!this.k || badrs > 0) {
|
|
217
|
+
this.deterministicK(badrs);
|
|
218
|
+
}
|
|
219
|
+
badrs++;
|
|
220
|
+
k = this.k;
|
|
221
|
+
Q = G.mul(k);
|
|
222
|
+
r = new BN(1).mul(Q.x.umod(N));
|
|
223
|
+
s = k
|
|
224
|
+
.invm(N)
|
|
225
|
+
.mul(e.add(d.mul(r)))
|
|
226
|
+
.umod(N);
|
|
227
|
+
} while (r.cmp(BN.Zero) <= 0 || s.cmp(BN.Zero) <= 0);
|
|
228
|
+
|
|
229
|
+
s = ECDSA.toLowS(s);
|
|
230
|
+
return {
|
|
231
|
+
s: s,
|
|
232
|
+
r: r,
|
|
233
|
+
};
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
ECDSA.prototype.sign = function () {
|
|
237
|
+
var hashbuf = this.hashbuf;
|
|
238
|
+
var privkey = this.privkey;
|
|
239
|
+
var d = privkey.bn;
|
|
240
|
+
|
|
241
|
+
$.checkState(hashbuf && privkey && d, new Error('invalid parameters'));
|
|
242
|
+
$.checkState(
|
|
243
|
+
Buffer.isBuffer(hashbuf) && hashbuf.length === 32,
|
|
244
|
+
new Error('hashbuf must be a 32 byte buffer'),
|
|
245
|
+
);
|
|
246
|
+
|
|
247
|
+
var e = BN.fromBuffer(
|
|
248
|
+
hashbuf,
|
|
249
|
+
this.endian
|
|
250
|
+
? {
|
|
251
|
+
endian: this.endian,
|
|
252
|
+
}
|
|
253
|
+
: undefined,
|
|
254
|
+
);
|
|
255
|
+
|
|
256
|
+
var obj = this._findSignature(d, e);
|
|
257
|
+
obj.compressed = this.pubkey.compressed;
|
|
258
|
+
|
|
259
|
+
this.sig = new Signature(obj);
|
|
260
|
+
return this;
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
ECDSA.prototype.signRandomK = function () {
|
|
264
|
+
this.randomK();
|
|
265
|
+
return this.sign();
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
ECDSA.prototype.toString = function () {
|
|
269
|
+
var obj = {};
|
|
270
|
+
if (this.hashbuf) {
|
|
271
|
+
obj.hashbuf = this.hashbuf.toString('hex');
|
|
272
|
+
}
|
|
273
|
+
if (this.privkey) {
|
|
274
|
+
obj.privkey = this.privkey.toString();
|
|
275
|
+
}
|
|
276
|
+
if (this.pubkey) {
|
|
277
|
+
obj.pubkey = this.pubkey.toString();
|
|
278
|
+
}
|
|
279
|
+
if (this.sig) {
|
|
280
|
+
obj.sig = this.sig.toString();
|
|
281
|
+
}
|
|
282
|
+
if (this.k) {
|
|
283
|
+
obj.k = this.k.toString();
|
|
284
|
+
}
|
|
285
|
+
return JSON.stringify(obj);
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
ECDSA.prototype.verify = function () {
|
|
289
|
+
if (!this.sigError()) {
|
|
290
|
+
this.verified = true;
|
|
291
|
+
} else {
|
|
292
|
+
this.verified = false;
|
|
293
|
+
}
|
|
294
|
+
return this;
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
ECDSA.sign = function (hashbuf, privkey, endian) {
|
|
298
|
+
return ECDSA()
|
|
299
|
+
.set({
|
|
300
|
+
hashbuf: hashbuf,
|
|
301
|
+
endian: endian,
|
|
302
|
+
privkey: privkey,
|
|
303
|
+
})
|
|
304
|
+
.sign().sig;
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
ECDSA.signWithCalcI = function (hashbuf, privkey, endian) {
|
|
308
|
+
return ECDSA()
|
|
309
|
+
.set({
|
|
310
|
+
hashbuf: hashbuf,
|
|
311
|
+
endian: endian,
|
|
312
|
+
privkey: privkey,
|
|
313
|
+
})
|
|
314
|
+
.sign()
|
|
315
|
+
.calci().sig;
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
ECDSA.signRandomK = function (hashbuf, privkey, endian) {
|
|
319
|
+
return ECDSA()
|
|
320
|
+
.set({
|
|
321
|
+
hashbuf: hashbuf,
|
|
322
|
+
endian: endian,
|
|
323
|
+
privkey: privkey,
|
|
324
|
+
})
|
|
325
|
+
.signRandomK().sig;
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
ECDSA.verify = function (hashbuf, sig, pubkey, endian) {
|
|
329
|
+
return ECDSA()
|
|
330
|
+
.set({
|
|
331
|
+
hashbuf: hashbuf,
|
|
332
|
+
endian: endian,
|
|
333
|
+
sig: sig,
|
|
334
|
+
pubkey: pubkey,
|
|
335
|
+
})
|
|
336
|
+
.verify().verified;
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
module.exports = ECDSA;
|