UNPKG

11.2 kBJavaScriptView Raw
1/**
2 * Big Number
3 * ==========
4 *
5 * Since javascript numbers are only precise up to 53 bits, and bitcoin is
6 * based on cryptography that uses 256 bit numbers, we must use a big number
7 * library. The library we use at the moment is Fedor Indutny's bn.js library.
8 * Since big numbers are extremely useful, we provide some very basic wrappers
9 * for his big number class and expose it. The wrappers merely allow you to do,
10 * say, bn.cmp(num) instead of just bn.cmp(bn), which is nice. The primary way
11 * to use this is:
12 * const bn = Bn(str) // str is base 10
13 * const bn = Bn(num)
14 * const bn = Bn().fromBuffer(buf)
15 * const bn = Bn().fromSm(buf); // sign+magnitude format, first bit is sign
16 *
17 * For little endian, pass in an options value:
18 * const bn = Bn().fromBuffer(buf, {endian: 'little'})
19 * const bn = Bn().fromSm(buf, {endian: 'little'})
20 *
21 * Getting output:
22 * const str = Bn().toString() // produces base 10 string
23 * const buf = Bn().toBuffer() // produces buffer representation
24 * const buf = Bn().toBuffer({size: 32}) //produced 32 byte buffer
25 */
26'use strict'
27
28import _Bn from 'bn.js'
29
30function Bn (n, base, ...rest) {
31 if (!(this instanceof Bn)) {
32 return new Bn(n, base, ...rest)
33 }
34 _Bn.call(this, n, base, ...rest)
35}
36
37Object.keys(_Bn).forEach(function (key) {
38 Bn[key] = _Bn[key]
39})
40Bn.prototype = Object.create(_Bn.prototype)
41Bn.prototype.constructor = Bn
42
43function reverseBuf (buf) {
44 const buf2 = Buffer.alloc(buf.length)
45 for (let i = 0; i < buf.length; i++) {
46 buf2[i] = buf[buf.length - 1 - i]
47 }
48 return buf2
49}
50
51Bn.prototype.fromHex = function (hex, opts) {
52 return this.fromBuffer(Buffer.from(hex, 'hex'), opts)
53}
54
55Bn.prototype.toHex = function (opts) {
56 return this.toBuffer(opts).toString('hex')
57}
58
59Bn.prototype.toJSON = function () {
60 return this.toString()
61}
62
63Bn.prototype.fromJSON = function (str) {
64 const bn = Bn(str)
65 bn.copy(this)
66 return this
67}
68
69Bn.prototype.fromNumber = function (n) {
70 const bn = Bn(n)
71 bn.copy(this)
72 return this
73}
74
75Bn.prototype.toNumber = function () {
76 return parseInt(this.toString(10), 10)
77}
78
79Bn.prototype.fromString = function (str, base) {
80 const bn = Bn(str, base)
81 bn.copy(this)
82 return this
83}
84
85Bn.fromBuffer = function (buf, opts = { endian: 'big' }) {
86 if (opts.endian === 'little') {
87 buf = reverseBuf(buf)
88 }
89 const hex = buf.toString('hex')
90 const bn = new Bn(hex, 16)
91 return bn
92}
93
94Bn.prototype.fromBuffer = function (buf, opts) {
95 const bn = Bn.fromBuffer(buf, opts)
96 bn.copy(this)
97
98 return this
99}
100
101Bn.prototype.toBuffer = function (opts = { size: undefined, endian: 'big' }) {
102 let buf
103 if (opts.size) {
104 const hex = this.toString(16, 2)
105 const natlen = hex.length / 2
106 buf = Buffer.from(hex, 'hex')
107
108 if (natlen === opts.size) {
109 // pass
110 } else if (natlen > opts.size) {
111 buf = buf.slice(natlen - buf.length, buf.length)
112 } else if (natlen < opts.size) {
113 const rbuf = Buffer.alloc(opts.size)
114 for (let i = 0; i < buf.length; i++) {
115 rbuf[rbuf.length - 1 - i] = buf[buf.length - 1 - i]
116 }
117 for (let i = 0; i < opts.size - natlen; i++) {
118 rbuf[i] = 0
119 }
120 buf = rbuf
121 }
122 } else {
123 const hex = this.toString(16, 2)
124 buf = Buffer.from(hex, 'hex')
125 }
126
127 if (opts.endian === 'little') {
128 buf = reverseBuf(buf)
129 }
130 const longzero = Buffer.from([0])
131 if (Buffer.compare(buf, longzero) === 0) {
132 return Buffer.from([])
133 }
134 return buf
135}
136
137Bn.prototype.toFastBuffer = Bn.prototype.toBuffer
138
139Bn.fromFastBuffer = Bn.fromBuffer
140Bn.prototype.fromFastBuffer = Bn.prototype.fromBuffer
141
142/**
143 * Signed magnitude buffer. Most significant bit represents sign (0 = positive,
144 * 1 = negative).
145 */
146Bn.prototype.fromSm = function (buf, opts = { endian: 'big' }) {
147 if (buf.length === 0) {
148 this.fromBuffer(Buffer.from([0]))
149 }
150
151 const endian = opts.endian
152 if (endian === 'little') {
153 buf = reverseBuf(buf)
154 }
155
156 if (buf[0] & 0x80) {
157 buf[0] = buf[0] & 0x7f
158 this.fromBuffer(buf)
159 this.neg().copy(this)
160 } else {
161 this.fromBuffer(buf)
162 }
163 return this
164}
165
166Bn.prototype.toSm = function (opts = { endian: 'big' }) {
167 const endian = opts.endian
168
169 let buf
170 if (this.cmp(0) === -1) {
171 buf = this.neg().toBuffer()
172 if (buf[0] & 0x80) {
173 buf = Buffer.concat([Buffer.from([0x80]), buf])
174 } else {
175 buf[0] = buf[0] | 0x80
176 }
177 } else {
178 buf = this.toBuffer()
179 if (buf[0] & 0x80) {
180 buf = Buffer.concat([Buffer.from([0x00]), buf])
181 }
182 }
183
184 if ((buf.length === 1) & (buf[0] === 0)) {
185 buf = Buffer.from([])
186 }
187
188 if (endian === 'little') {
189 buf = reverseBuf(buf)
190 }
191
192 return buf
193}
194
195/**
196 * Produce a Bn from the "bits" value in a blockheader. Analagous to Bitcoin
197 * Core's uint256 SetCompact method. bits is assumed to be UInt32.
198 */
199Bn.prototype.fromBits = function (bits, opts = { strict: false }) {
200 // To performed bitwise operations in javascript, we need to convert to a
201 // signed 32 bit value.
202 let buf = Buffer.alloc(4)
203 buf.writeUInt32BE(bits, 0)
204 bits = buf.readInt32BE(0)
205 if (opts.strict && bits & 0x00800000) {
206 throw new Error('negative bit set')
207 }
208 const nsize = bits >> 24
209 const nword = bits & 0x007fffff
210 buf = Buffer.alloc(4)
211 buf.writeInt32BE(nword)
212 if (nsize <= 3) {
213 buf = buf.slice(1, nsize + 1)
214 } else {
215 const fill = Buffer.alloc(nsize - 3)
216 fill.fill(0)
217 buf = Buffer.concat([buf, fill])
218 }
219 this.fromBuffer(buf)
220 if (bits & 0x00800000) {
221 Bn(0)
222 .sub(this)
223 .copy(this)
224 }
225 return this
226}
227
228/**
229 * Convert Bn to the "bits" value in a blockheader. Analagous to Bitcoin
230 * Core's uint256 GetCompact method. bits is a UInt32.
231 */
232Bn.prototype.toBits = function () {
233 let buf
234 if (this.lt(0)) {
235 buf = this.neg().toBuffer()
236 } else {
237 buf = this.toBuffer()
238 }
239 let nsize = buf.length
240 let nword
241 if (nsize > 3) {
242 nword = Buffer.concat([Buffer.from([0]), buf.slice(0, 3)]).readUInt32BE(0)
243 } else if (nsize <= 3) {
244 const blank = Buffer.alloc(3 - nsize + 1)
245 blank.fill(0)
246 nword = Buffer.concat([blank, buf.slice(0, nsize)]).readUInt32BE(0)
247 }
248 if (nword & 0x00800000) {
249 // The most significant bit denotes sign. Do not want unless number is
250 // actually negative.
251 nword >>= 8
252 nsize++
253 }
254 if (this.lt(0)) {
255 nword |= 0x00800000
256 }
257 const bits = (nsize << 24) | nword
258 // convert bits to UInt32 before returning
259 buf = Buffer.alloc(4)
260 buf.writeInt32BE(bits, 0)
261 return buf.readUInt32BE(0)
262}
263
264// This is analogous to the constructor for CScriptNum in bitcoind. Many ops
265// in bitcoind's script interpreter use CScriptNum, which is not really a
266// proper bignum. Instead, an error is thrown if trying to input a number
267// bigger than 4 bytes. We copy that behavior here. There is one exception -
268// in CHECKLOCKTIMEVERIFY, the numbers are allowed to be up to 5 bytes long.
269// We allow for setting that variable here for use in CHECKLOCKTIMEVERIFY.
270Bn.prototype.fromScriptNumBuffer = function (
271 buf,
272 fRequireMinimal,
273 nMaxNumSize
274) {
275 if (nMaxNumSize === undefined) {
276 nMaxNumSize = 4
277 }
278 if (buf.length > nMaxNumSize) {
279 throw new Error('script number overflow')
280 }
281 if (fRequireMinimal && buf.length > 0) {
282 // Check that the number is encoded with the minimum possible
283 // number of bytes.
284 //
285 // If the most-significant-byte - excluding the sign bit - is zero
286 // then we're not minimal. Note how this test also rejects the
287 // negative-zero encoding, 0x80.
288 if ((buf[buf.length - 1] & 0x7f) === 0) {
289 // One exception: if there's more than one byte and the most
290 // significant bit of the second-most-significant-byte is set
291 // it would conflict with the sign bit. An example of this case
292 // is +-255, which encode to 0xff00 and 0xff80 respectively.
293 // (big-endian).
294 if (buf.length <= 1 || (buf[buf.length - 2] & 0x80) === 0) {
295 throw new Error('non-minimally encoded script number')
296 }
297 }
298 }
299 return this.fromSm(buf, { endian: 'little' })
300}
301
302// The corollary to the above, with the notable exception that we do not throw
303// an error if the output is larger than four bytes. (Which can happen if
304// performing a numerical operation that results in an overflow to more than 4
305// bytes).
306Bn.prototype.toScriptNumBuffer = function (buf) {
307 return this.toSm({ endian: 'little' })
308}
309
310Bn.prototype.neg = function () {
311 const _neg = _Bn.prototype.neg.call(this)
312 const neg = Object.create(Bn.prototype)
313 _neg.copy(neg)
314 return neg
315}
316
317Bn.prototype.add = function (bn) {
318 const _bn = _Bn.prototype.add.call(this, bn)
319 bn = Object.create(Bn.prototype)
320 _bn.copy(bn)
321 return bn
322}
323
324Bn.prototype.sub = function (bn) {
325 const _bn = _Bn.prototype.sub.call(this, bn)
326 bn = Object.create(Bn.prototype)
327 _bn.copy(bn)
328 return bn
329}
330
331Bn.prototype.mul = function (bn) {
332 const _bn = _Bn.prototype.mul.call(this, bn)
333 bn = Object.create(Bn.prototype)
334 _bn.copy(bn)
335 return bn
336}
337
338/**
339 * to be used if this is positive.
340 */
341Bn.prototype.mod = function (bn) {
342 const _bn = _Bn.prototype.mod.call(this, bn)
343 bn = Object.create(Bn.prototype)
344 _bn.copy(bn)
345 return bn
346}
347
348/**
349 * to be used if this is negative.
350 */
351Bn.prototype.umod = function (bn) {
352 const _bn = _Bn.prototype.umod.call(this, bn)
353 bn = Object.create(Bn.prototype)
354 _bn.copy(bn)
355 return bn
356}
357
358Bn.prototype.invm = function (bn) {
359 const _bn = _Bn.prototype.invm.call(this, bn)
360 bn = Object.create(Bn.prototype)
361 _bn.copy(bn)
362 return bn
363}
364
365Bn.prototype.div = function (bn) {
366 const _bn = _Bn.prototype.div.call(this, bn)
367 bn = Object.create(Bn.prototype)
368 _bn.copy(bn)
369 return bn
370}
371
372Bn.prototype.ushln = function (bits) {
373 const _bn = _Bn.prototype.ushln.call(this, bits)
374 const bn = Object.create(Bn.prototype)
375 _bn.copy(bn)
376 return bn
377}
378
379Bn.prototype.ushrn = function (bits) {
380 const _bn = _Bn.prototype.ushrn.call(this, bits)
381 const bn = Object.create(Bn.prototype)
382 _bn.copy(bn)
383 return bn
384}
385
386Bn.prototype.cmp = function (bn) {
387 return _Bn.prototype.cmp.call(this, bn)
388}
389
390/**
391 * All the standard big number operations operate on other big numbers. e.g.,
392 * bn1.add(bn2). But it is frequenly valuble to add numbers or strings, e.g.
393 * bn.add(5) or bn.add('5'). The decorator wraps all methods where this would
394 * be convenient and makes that possible.
395 */
396function decorate (name) {
397 Bn.prototype['_' + name] = Bn.prototype[name]
398 const f = function (b) {
399 if (typeof b === 'string') {
400 b = new Bn(b)
401 } else if (typeof b === 'number') {
402 b = new Bn(b.toString())
403 }
404 return this['_' + name](b)
405 }
406 Bn.prototype[name] = f
407}
408
409Bn.prototype.eq = function (b) {
410 return this.cmp(b) === 0
411}
412
413Bn.prototype.neq = function (b) {
414 return this.cmp(b) !== 0
415}
416
417Bn.prototype.gt = function (b) {
418 return this.cmp(b) > 0
419}
420
421Bn.prototype.geq = function (b) {
422 return this.cmp(b) >= 0
423}
424
425Bn.prototype.lt = function (b) {
426 return this.cmp(b) < 0
427}
428
429Bn.prototype.leq = function (b) {
430 return this.cmp(b) <= 0
431}
432
433decorate('add')
434decorate('sub')
435decorate('mul')
436decorate('mod')
437decorate('invm')
438decorate('div')
439decorate('cmp')
440decorate('gt')
441decorate('geq')
442decorate('lt')
443decorate('leq')
444
445export { Bn }