UNPKG

4.87 kBJavaScriptView Raw
1'use strict';
2
3var BN = require('bn.js');
4var $ = require('../util/preconditions');
5var _ = require('lodash');
6
7var 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
15BN.Zero = new BN(0);
16BN.One = new BN(1);
17BN.Minus1 = new BN(-1);
18
19BN.fromNumber = function(n) {
20 $.checkArgument(_.isNumber(n));
21 return new BN(n);
22};
23
24BN.fromString = function(str, base) {
25 $.checkArgument(_.isString(str));
26 return new BN(str, base);
27};
28
29BN.fromBuffer = function(buf, opts) {
30 if (typeof opts !== 'undefined' && opts.endian === 'little') {
31 buf = reversebuf(buf);
32 }
33 var hex = buf.toString('hex');
34 var bn = new BN(hex, 16);
35 return bn;
36};
37
38/**
39 * Instantiate a BigNumber from a "signed magnitude buffer"
40 * (a buffer where the most significant bit represents the sign (0 = positive, -1 = negative))
41 */
42BN.fromSM = function(buf, opts) {
43 var ret;
44 if (buf.length === 0) {
45 return BN.fromBuffer(Buffer.from([0]));
46 }
47
48 var endian = 'big';
49 if (opts) {
50 endian = opts.endian;
51 }
52 if (endian === 'little') {
53 buf = reversebuf(buf);
54 }
55
56 if (buf[0] & 0x80) {
57 buf[0] = buf[0] & 0x7f;
58 ret = BN.fromBuffer(buf);
59 ret.neg().copy(ret);
60 } else {
61 ret = BN.fromBuffer(buf);
62 }
63 return ret;
64};
65
66
67BN.prototype.toNumber = function() {
68 return parseInt(this.toString(10), 10);
69};
70
71BN.prototype.toBuffer = function(opts) {
72 var buf, hex;
73 if (opts && opts.size) {
74 hex = this.toString(16, 2);
75 var natlen = hex.length / 2;
76 buf = Buffer.from(hex, 'hex');
77
78 if (natlen === opts.size) {
79 buf = buf;
80 } else if (natlen > opts.size) {
81 buf = BN.trim(buf, natlen);
82 } else if (natlen < opts.size) {
83 buf = BN.pad(buf, natlen, opts.size);
84 }
85 } else {
86 hex = this.toString(16, 2);
87 buf = Buffer.from(hex, 'hex');
88 }
89
90 if (typeof opts !== 'undefined' && opts.endian === 'little') {
91 buf = reversebuf(buf);
92 }
93
94 return buf;
95};
96
97BN.prototype.toSMBigEndian = function() {
98 var buf;
99 if (this.cmp(BN.Zero) === -1) {
100 buf = this.neg().toBuffer();
101 if (buf[0] & 0x80) {
102 buf = Buffer.concat([Buffer.from([0x80]), buf]);
103 } else {
104 buf[0] = buf[0] | 0x80;
105 }
106 } else {
107 buf = this.toBuffer();
108 if (buf[0] & 0x80) {
109 buf = Buffer.concat([Buffer.from([0x00]), buf]);
110 }
111 }
112
113 if (buf.length === 1 & buf[0] === 0) {
114 buf = Buffer.from([]);
115 }
116 return buf;
117};
118
119BN.prototype.toSM = function(opts) {
120 var endian = opts ? opts.endian : 'big';
121 var buf = this.toSMBigEndian();
122
123 if (endian === 'little') {
124 buf = reversebuf(buf);
125 }
126 return buf;
127};
128
129/**
130 * Create a BN from a "ScriptNum":
131 * This is analogous to the constructor for CScriptNum in bitcoind. Many ops in
132 * bitcoind's script interpreter use CScriptNum, which is not really a proper
133 * bignum. Instead, an error is thrown if trying to input a number bigger than
134 * 4 bytes. We copy that behavior here. A third argument, `size`, is provided to
135 * extend the hard limit of 4 bytes, as some usages require more than 4 bytes.
136 */
137BN.fromScriptNumBuffer = function(buf, fRequireMinimal, size) {
138 var nMaxNumSize = size || 4;
139 $.checkArgument(buf.length <= nMaxNumSize, new Error('script number overflow'));
140 if (fRequireMinimal && buf.length > 0) {
141 // Check that the number is encoded with the minimum possible
142 // number of bytes.
143 //
144 // If the most-significant-byte - excluding the sign bit - is zero
145 // then we're not minimal. Note how this test also rejects the
146 // negative-zero encoding, 0x80.
147 if ((buf[buf.length - 1] & 0x7f) === 0) {
148 // One exception: if there's more than one byte and the most
149 // significant bit of the second-most-significant-byte is set
150 // it would conflict with the sign bit. An example of this case
151 // is +-255, which encode to 0xff00 and 0xff80 respectively.
152 // (big-endian).
153 if (buf.length <= 1 || (buf[buf.length - 2] & 0x80) === 0) {
154 throw new Error('non-minimally encoded script number');
155 }
156 }
157 }
158 return BN.fromSM(buf, {
159 endian: 'little'
160 });
161};
162
163/**
164 * The corollary to the above, with the notable exception that we do not throw
165 * an error if the output is larger than four bytes. (Which can happen if
166 * performing a numerical operation that results in an overflow to more than 4
167 * bytes).
168 */
169BN.prototype.toScriptNumBuffer = function() {
170 return this.toSM({
171 endian: 'little'
172 });
173};
174
175BN.trim = function(buf, natlen) {
176 return buf.slice(natlen - buf.length, buf.length);
177};
178
179BN.pad = function(buf, natlen, size) {
180 var rbuf = Buffer.alloc(size);
181 for (var i = 0; i < buf.length; i++) {
182 rbuf[rbuf.length - 1 - i] = buf[buf.length - 1 - i];
183 }
184 for (i = 0; i < size - natlen; i++) {
185 rbuf[i] = 0;
186 }
187 return rbuf;
188};
189
190module.exports = BN;