From 7f348ca0bd691846a98fe449eabd10498f892960 Mon Sep 17 00:00:00 2001 From: "Ryan X. Charles" Date: Mon, 28 Apr 2014 18:00:59 -0400 Subject: [PATCH 1/2] Move BigNumber to internal ...no longer relies on Manuel's repo hostig a version of "bignum" that actually contained bignumber.js. This moves bignumber.js internally and removes bignum from the browser build process. Also adds a bitcore.Bignum that links to the right thing. In node, browser.Bignum is require('bignum'). And in the browser, bitcore.Bignum is is now Bignumber.js (same as before ... except bignumber.js is now inside bitcore). --- bitcore.js | 18 +- browser/bignum_config.js | 6 - browser/build.js | 8 +- lib/BIP32.js | 5 +- lib/Base58.js | 116 ++ lib/Bignum.js | 5 + lib/Block.js | 2 +- lib/Curve.js | 2 +- lib/Electrum.js | 2 +- lib/ScriptInterpreter.js | 2 +- lib/Transaction.js | 2 +- lib/TransactionBuilder.js | 2 +- lib/browser/Bignum.js | 2121 +++++++++++++++++++++++++++++++++++++ lib/browser/Key.js | 2 +- lib/browser/Point.js | 2 +- lib/node/Point.js | 2 +- package.json | 2 - test/test.Base58.js | 49 + test/test.Curve.js | 2 +- test/test.Key.js | 2 +- test/test.Point.js | 2 +- test/test.misc.js | 8 +- util/EncodedData.js | 2 +- util/VersionedData.js | 2 +- util/util.js | 2 +- 25 files changed, 2329 insertions(+), 39 deletions(-) delete mode 100644 browser/bignum_config.js create mode 100644 lib/Base58.js create mode 100644 lib/Bignum.js create mode 100644 lib/browser/Bignum.js create mode 100644 test/test.Base58.js diff --git a/bitcore.js b/bitcore.js index bb92336ae..061579fbe 100644 --- a/bitcore.js +++ b/bitcore.js @@ -10,8 +10,20 @@ var requireWhenAccessed = function(name, file) { Object.defineProperty(module.exports, name, {get: function() {return require(file)}}); }; -requireWhenAccessed('bignum', 'bignum'); -requireWhenAccessed('base58', 'base58-native'); +requireWhenAccessed('Bignum', './lib/Bignum'); +/* +Object.defineProperty(module.exports, 'bignum', {get: function() { + console.log('bignum (with a lower-case "b") is deprecated. Use bitcore.Bignum (capital "B") instead.'); + return require('./lib/Bignum'); +}}); +*/ +requireWhenAccessed('Base58', './lib/Base58'); +/* +Object.defineProperty(module.exports, 'base58', {get: function() { + console.log('base58 (with a lower-case "b") is deprecated. Use bitcore.Base58 (capital "B") instead.'); + return require('./lib/Base58'); +}}); +*/ requireWhenAccessed('bufferput', 'bufferput'); requireWhenAccessed('buffertools', 'buffertools'); requireWhenAccessed('Buffers.monkey', './patches/Buffers.monkey'); @@ -56,6 +68,6 @@ module.exports.Buffer = Buffer; if (typeof process.versions === 'undefined') { // Browser specific - module.exports.bignum.config({EXPONENTIAL_AT: 9999999, DECIMAL_PLACES: 0, ROUNDING_MODE: 1}); + module.exports.Bignum.config({EXPONENTIAL_AT: 9999999, DECIMAL_PLACES: 0, ROUNDING_MODE: 1}); } diff --git a/browser/bignum_config.js b/browser/bignum_config.js deleted file mode 100644 index 1710d22be..000000000 --- a/browser/bignum_config.js +++ /dev/null @@ -1,6 +0,0 @@ -require('bignum').config({ - EXPONENTIAL_AT: 9999999, - DECIMAL_PLACES: 0, - ROUNDING_MODE: 1, -}); - diff --git a/browser/build.js b/browser/build.js index 0b8b59f40..61f7ada0b 100644 --- a/browser/build.js +++ b/browser/build.js @@ -24,6 +24,8 @@ var pack = function (params) { var modules = [ 'lib/Address', + 'lib/Base58', + 'lib/Bignum', 'lib/BIP32', 'lib/Block', 'lib/Bloom', @@ -94,18 +96,12 @@ var createBitcore = function(opts) { }; var b = browserify(bopts); - b.require(opts.dir + 'browserify-bignum/bignumber.js', { - expose: 'bignum' - }); b.require(opts.dir + 'browserify-buffertools/buffertools.js', { expose: 'buffertools' }); b.require(opts.dir + 'bufferput', { expose: 'bufferput' }); - b.require(opts.dir + 'base58-native', { - expose: 'base58-native' - }); b.require(opts.dir + 'buffers', { expose: 'buffers' }); diff --git a/lib/BIP32.js b/lib/BIP32.js index 6484af02e..ba9699e34 100644 --- a/lib/BIP32.js +++ b/lib/BIP32.js @@ -1,11 +1,10 @@ var imports = require('soop').imports(); -var base58 = imports.base58 || require('base58-native').base58; +var base58 = imports.base58 || require('./Base58').base58; var coinUtil = imports.coinUtil || require('../util'); var Key = imports.Key || require('./Key'); var Point = imports.Point || require('./Point'); var SecureRandom = imports.SecureRandom || require('./SecureRandom'); -var bignum = imports.bignum || require('bignum'); -var crypto = require('crypto'); +var bignum = imports.bignum || require('./Bignum'); var networks = require('../networks'); var secp256k1_n = new bignum("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16); diff --git a/lib/Base58.js b/lib/Base58.js new file mode 100644 index 000000000..71f1c2311 --- /dev/null +++ b/lib/Base58.js @@ -0,0 +1,116 @@ +var crypto = require('crypto'); +var bignum = require('./Bignum'); + +var globalBuffer = new Buffer(1024); +var zerobuf = new Buffer(0); +var ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'; +var ALPHABET_ZERO = ALPHABET[0]; +var ALPHABET_BUF = new Buffer(ALPHABET, 'ascii'); +var ALPHABET_INV = {}; +for(var i=0; i < ALPHABET.length; i++) { + ALPHABET_INV[ALPHABET[i]] = i; +}; + +// Vanilla Base58 Encoding +var base58 = { + encode: function(buf) { + var str; + var x = bignum.fromBuffer(buf); + var r; + + if(buf.length < 512) { + str = globalBuffer; + } else { + str = new Buffer(buf.length << 1); + } + var i = str.length - 1; + while(x.gt(0)) { + r = x.mod(58); + x = x.div(58); + str[i] = ALPHABET_BUF[r.toNumber()]; + i--; + } + + // deal with leading zeros + var j=0; + while(buf[j] == 0) { + str[i] = ALPHABET_BUF[0]; + j++; i--; + } + + return str.slice(i+1,str.length).toString('ascii'); + }, + + decode: function(str) { + if(str.length == 0) return zerobuf; + var answer = bignum(0); + for(var i=0; i 0) { + var zb = new Buffer(i); + zb.fill(0); + if(i == str.length) return zb; + answer = answer.toBuffer(); + return Buffer.concat([zb, answer], i+answer.length); + } else { + return answer.toBuffer(); + } + }, +}; + +// Base58Check Encoding +function sha256(data) { + return new Buffer(crypto.createHash('sha256').update(data).digest('binary'), 'binary'); +}; + +function doubleSHA256(data) { + return sha256(sha256(data)); +}; + +var base58Check = { + encode: function(buf) { + var checkedBuf = new Buffer(buf.length + 4); + var hash = doubleSHA256(buf); + buf.copy(checkedBuf); + hash.copy(checkedBuf, buf.length); + return base58.encode(checkedBuf); + }, + + decode: function(s) { + var buf = base58.decode(s); + if (buf.length < 4) { + throw new Error("invalid input: too short"); + } + + var data = buf.slice(0, -4); + var csum = buf.slice(-4); + + var hash = doubleSHA256(data); + var hash4 = hash.slice(0, 4); + + if (csum.toString() != hash4.toString()) { + throw new Error("checksum mismatch"); + } + + return data; + }, +}; + +// if you frequently do base58 encodings with data larger +// than 512 bytes, you can use this method to expand the +// size of the reusable buffer +exports.setBuffer = function(buf) { + globalBuffer = buf; +}; + +exports.base58 = base58; +exports.base58Check = base58Check; +exports.encode = base58.encode; +exports.decode = base58.decode; diff --git a/lib/Bignum.js b/lib/Bignum.js new file mode 100644 index 000000000..274b28de2 --- /dev/null +++ b/lib/Bignum.js @@ -0,0 +1,5 @@ +if (process.versions) { + module.exports = require('bignum'); + return; +} +module.exports = require('./browser/Bignum'); diff --git a/lib/Block.js b/lib/Block.js index 57c6d4869..63f84c5ef 100644 --- a/lib/Block.js +++ b/lib/Block.js @@ -3,7 +3,7 @@ var imports = require('soop').imports(); var util = imports.util || require('../util'); var Debug1 = imports.Debug1 || function() {}; var Script = imports.Script || require('./Script'); -var Bignum = imports.Bignum || require('bignum'); +var Bignum = imports.Bignum || require('./Bignum'); var Binary = imports.Binary || require('binary'); var Step = imports.Step || require('step'); var buffertools = imports.buffertools || require('buffertools'); diff --git a/lib/Curve.js b/lib/Curve.js index f2d140d4a..e5ec4fb1e 100644 --- a/lib/Curve.js +++ b/lib/Curve.js @@ -1,6 +1,6 @@ "use strict"; var imports = require('soop'); -var bignum = imports.bignum || require('bignum'); +var bignum = imports.bignum || require('./Bignum'); var Point = imports.Point || require('./Point'); var n = bignum.fromBuffer(new Buffer("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 'hex'), {size: 32}); diff --git a/lib/Electrum.js b/lib/Electrum.js index 02457798f..284c3d4d6 100644 --- a/lib/Electrum.js +++ b/lib/Electrum.js @@ -2,7 +2,7 @@ var Key = require('./Key'), Point = require('./Point'), twoSha256 = require('../util').twoSha256, buffertools = require('buffertools'), - bignum = require('bignum'); + bignum = require('./Bignum'); /** * Pre-BIP32 Electrum public key derivation (electrum <2.0) diff --git a/lib/ScriptInterpreter.js b/lib/ScriptInterpreter.js index 1cb5abdb7..ce25d7b5a 100644 --- a/lib/ScriptInterpreter.js +++ b/lib/ScriptInterpreter.js @@ -4,7 +4,7 @@ var log = imports.log || require('../util/log'); var util = imports.util || require('../util'); var Opcode = imports.Opcode || require('./Opcode'); var buffertools = imports.buffertools || require('buffertools'); -var bignum = imports.bignum || require('bignum'); +var bignum = imports.bignum || require('./Bignum'); var Util = imports.Util || require('../util'); var Script = require('./Script'); var Key = require('./Key'); diff --git a/lib/Transaction.js b/lib/Transaction.js index d79b62780..35931120b 100644 --- a/lib/Transaction.js +++ b/lib/Transaction.js @@ -5,7 +5,7 @@ var Address = imports.Address || require('./Address'); var Script = imports.Script || require('./Script'); var ScriptInterpreter = imports.ScriptInterpreter || require('./ScriptInterpreter'); var util = imports.util || require('../util'); -var bignum = imports.bignum || require('bignum'); +var bignum = imports.bignum || require('./Bignum'); var Put = imports.Put || require('bufferput'); var Parser = imports.Parser || require('../util/BinaryParser'); var Step = imports.Step || require('step'); diff --git a/lib/TransactionBuilder.js b/lib/TransactionBuilder.js index c4172d1c3..815385a40 100644 --- a/lib/TransactionBuilder.js +++ b/lib/TransactionBuilder.js @@ -83,7 +83,7 @@ var imports = require('soop').imports(); var Address = imports.Address || require('./Address'); var Script = imports.Script || require('./Script'); var util = imports.util || require('../util'); -var bignum = imports.bignum || require('bignum'); +var bignum = imports.bignum || require('./Bignum'); var buffertools = imports.buffertools || require('buffertools'); var networks = imports.networks || require('../networks'); var WalletKey = imports.WalletKey || require('./WalletKey'); diff --git a/lib/browser/Bignum.js b/lib/browser/Bignum.js new file mode 100644 index 000000000..9a947d96e --- /dev/null +++ b/lib/browser/Bignum.js @@ -0,0 +1,2121 @@ +/* bignumber.js v1.3.0 https://github.com/MikeMcl/bignumber.js/LICENCE */ + +/*jslint bitwise: true, eqeq: true, plusplus: true, sub: true, white: true, maxerr: 500 */ +/*global module */ + +/* + bignumber.js v1.3.0 + A JavaScript library for arbitrary-precision arithmetic. + https://github.com/MikeMcl/bignumber.js + Copyright (c) 2012 Michael Mclaughlin + MIT Expat Licence +*/ + +/*********************************** DEFAULTS ************************************/ + +/* + * The default values below must be integers within the stated ranges (inclusive). + * Most of these values can be changed during run-time using BigNumber.config(). + */ + +/* + * The limit on the value of DECIMAL_PLACES, TO_EXP_NEG, TO_EXP_POS, MIN_EXP, + * MAX_EXP, and the argument to toFixed, toPrecision and toExponential, beyond + * which an exception is thrown (if ERRORS is true). + */ +var MAX = 1E9, // 0 to 1e+9 + + // Limit of magnitude of exponent argument to toPower. + MAX_POWER = 1E6, // 1 to 1e+6 + + // The maximum number of decimal places for operations involving division. + DECIMAL_PLACES = 20, // 0 to MAX + + /* + * The rounding mode used when rounding to the above decimal places, and when + * using toFixed, toPrecision and toExponential, and round (default value). + * UP 0 Away from zero. + * DOWN 1 Towards zero. + * CEIL 2 Towards +Infinity. + * FLOOR 3 Towards -Infinity. + * HALF_UP 4 Towards nearest neighbour. If equidistant, up. + * HALF_DOWN 5 Towards nearest neighbour. If equidistant, down. + * HALF_EVEN 6 Towards nearest neighbour. If equidistant, towards even neighbour. + * HALF_CEIL 7 Towards nearest neighbour. If equidistant, towards +Infinity. + * HALF_FLOOR 8 Towards nearest neighbour. If equidistant, towards -Infinity. + */ + ROUNDING_MODE = 4, // 0 to 8 + + // EXPONENTIAL_AT : [TO_EXP_NEG , TO_EXP_POS] + + // The exponent value at and beneath which toString returns exponential notation. + // Number type: -7 + TO_EXP_NEG = -7, // 0 to -MAX + + // The exponent value at and above which toString returns exponential notation. + // Number type: 21 + TO_EXP_POS = 21, // 0 to MAX + + // RANGE : [MIN_EXP, MAX_EXP] + + // The minimum exponent value, beneath which underflow to zero occurs. + // Number type: -324 (5e-324) + MIN_EXP = -MAX, // -1 to -MAX + + // The maximum exponent value, above which overflow to Infinity occurs. + // Number type: 308 (1.7976931348623157e+308) + MAX_EXP = MAX, // 1 to MAX + + // Whether BigNumber Errors are ever thrown. + // CHANGE parseInt to parseFloat if changing ERRORS to false. + ERRORS = true, // true or false + parse = parseInt, // parseInt or parseFloat + +/***********************************************************************************/ + + P = BigNumber.prototype, + DIGITS = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_', + outOfRange, + id = 0, + isValid = /^-?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i, + trim = String.prototype.trim || function () {return this.replace(/^\s+|\s+$/g, '')}, + ONE = BigNumber(1); + + +// CONSTRUCTOR + + +/* + * The exported function. + * Create and return a new instance of a BigNumber object. + * + * n {number|string|BigNumber} A numeric value. + * [b] {number} The base of n. Integer, 2 to 64 inclusive. + */ +function BigNumber( n, b ) { + var e, i, isNum, digits, valid, orig, + x = this; + + // Enable constructor usage without new. + if ( !(x instanceof BigNumber) ) { + return new BigNumber( n, b ) + } + + // Duplicate. + if ( n instanceof BigNumber ) { + id = 0; + + // e is undefined. + if ( b !== e ) { + n += '' + } else { + x['s'] = n['s']; + x['e'] = n['e']; + x['c'] = ( n = n['c'] ) ? n.slice() : n; + return; + } + } + + // Accept empty string as zero + if (n === '') n = 0; + + // If number, check if minus zero. + if ( typeof n != 'string' ) { + n = ( isNum = typeof n == 'number' || + Object.prototype.toString.call(n) == '[object Number]' ) && + n === 0 && 1 / n < 0 ? '-0' : n + ''; + } + + orig = n; + + if ( b === e && isValid.test(n) ) { + + // Determine sign. + x['s'] = n.charAt(0) == '-' ? ( n = n.slice(1), -1 ) : 1; + + // Either n is not a valid BigNumber or a base has been specified. + } else { + + // Enable exponential notation to be used with base 10 argument. + // Ensure return value is rounded to DECIMAL_PLACES as with other bases. + if ( b == 10 ) { + + return setMode( n, DECIMAL_PLACES, ROUNDING_MODE ); + } + + n = trim.call(n).replace( /^\+(?!-)/, '' ); + + x['s'] = n.charAt(0) == '-' ? ( n = n.replace( /^-(?!-)/, '' ), -1 ) : 1; + + if ( b != null ) { + + if ( ( b == (b | 0) || !ERRORS ) && + !( outOfRange = !( b >= 2 && b < 65 ) ) ) { + + digits = '[' + DIGITS.slice( 0, b = b | 0 ) + ']+'; + + // Before non-decimal number validity test and base conversion + // remove the `.` from e.g. '1.', and replace e.g. '.1' with '0.1'. + n = n.replace( /\.$/, '' ).replace( /^\./, '0.' ); + + // Any number in exponential form will fail due to the e+/-. + if ( valid = new RegExp( + '^' + digits + '(?:\\.' + digits + ')?$', b < 37 ? 'i' : '' ).test(n) ) { + + if ( isNum ) { + + if ( n.replace( /^0\.0*|\./, '' ).length > 15 ) { + + // 'new BigNumber() number type has more than 15 significant digits: {n}' + ifExceptionsThrow( orig, 0 ); + } + + // Prevent later check for length on converted number. + isNum = !isNum; + } + n = convert( n, 10, b, x['s'] ); + + } else if ( n != 'Infinity' && n != 'NaN' ) { + + // 'new BigNumber() not a base {b} number: {n}' + ifExceptionsThrow( orig, 1, b ); + n = 'NaN'; + } + } else { + + // 'new BigNumber() base not an integer: {b}' + // 'new BigNumber() base out of range: {b}' + ifExceptionsThrow( b, 2 ); + + // Ignore base. + valid = isValid.test(n); + } + } else { + valid = isValid.test(n); + } + + if ( !valid ) { + + // Infinity/NaN + x['c'] = x['e'] = null; + + // NaN + if ( n != 'Infinity' ) { + + // No exception on NaN. + if ( n != 'NaN' ) { + + // 'new BigNumber() not a number: {n}' + ifExceptionsThrow( orig, 3 ); + } + x['s'] = null; + } + id = 0; + + return; + } + } + + // Decimal point? + if ( ( e = n.indexOf('.') ) > -1 ) { + n = n.replace( '.', '' ); + } + + // Exponential form? + if ( ( i = n.search( /e/i ) ) > 0 ) { + + // Determine exponent. + if ( e < 0 ) { + e = i; + } + e += +n.slice( i + 1 ); + n = n.substring( 0, i ); + + } else if ( e < 0 ) { + + // Integer. + e = n.length; + } + + // Determine leading zeros. + for ( i = 0; n.charAt(i) == '0'; i++ ) { + } + + b = n.length; + + // Disallow numbers with over 15 significant digits if number type. + if ( isNum && b > 15 && n.slice(i).length > 15 ) { + + // 'new BigNumber() number type has more than 15 significant digits: {n}' + ifExceptionsThrow( orig, 0 ); + } + id = 0; + + // Overflow? + if ( ( e -= i + 1 ) > MAX_EXP ) { + + // Infinity. + x['c'] = x['e'] = null; + + // Zero or underflow? + } else if ( i == b || e < MIN_EXP ) { + + // Zero. + x['c'] = [ x['e'] = 0 ]; + } else { + + // Determine trailing zeros. + for ( ; n.charAt(--b) == '0'; ) { + } + + x['e'] = e; + x['c'] = []; + + // Convert string to array of digits (without leading and trailing zeros). + for ( e = 0; i <= b; x['c'][e++] = +n.charAt(i++) ) { + } + } +} + + +// CONSTRUCTOR PROPERTIES/METHODS + + +BigNumber['ROUND_UP'] = 0; +BigNumber['ROUND_DOWN'] = 1; +BigNumber['ROUND_CEIL'] = 2; +BigNumber['ROUND_FLOOR'] = 3; +BigNumber['ROUND_HALF_UP'] = 4; +BigNumber['ROUND_HALF_DOWN'] = 5; +BigNumber['ROUND_HALF_EVEN'] = 6; +BigNumber['ROUND_HALF_CEIL'] = 7; +BigNumber['ROUND_HALF_FLOOR'] = 8; + +/* + * Create an instance from a Buffer + */ +BigNumber['fromBuffer'] = function (buf, opts) { + + if (!opts) opts = {}; + + var endian = { 1 : 'big', '-1' : 'little' }[opts.endian] + || opts.endian || 'big' + ; + + var size = opts.size === 'auto' ? Math.ceil(buf.length) : (opts.size || 1); + + if (buf.length % size !== 0) { + throw new RangeError('Buffer length (' + buf.length + ')' + + ' must be a multiple of size (' + size + ')' + ); + } + + var hex = []; + for (var i = 0; i < buf.length; i += size) { + var chunk = []; + for (var j = 0; j < size; j++) { + chunk.push(buf[ + i + (endian === 'big' ? j : (size - j - 1)) + ]); + } + + hex.push(chunk + .map(function (c) { + return (c < 16 ? '0' : '') + c.toString(16); + }) + .join('') + ); + } + + return BigNumber(hex.join(''), 16); + +}; + +/* + * Configure infrequently-changing library-wide settings. + * + * Accept an object or an argument list, with one or many of the following + * properties or parameters respectively: + * [ DECIMAL_PLACES [, ROUNDING_MODE [, EXPONENTIAL_AT [, RANGE [, ERRORS ]]]]] + * + * E.g. + * BigNumber.config(20, 4) is equivalent to + * BigNumber.config({ DECIMAL_PLACES : 20, ROUNDING_MODE : 4 }) + * Ignore properties/parameters set to null or undefined. + * + * Return an object with the properties current values. + */ +BigNumber['config'] = function () { + var v, p, + i = 0, + r = {}, + a = arguments, + o = a[0], + c = 'config', + inRange = function ( n, lo, hi ) { + return !( ( outOfRange = n < lo || n > hi ) || + parse(n) != n && n !== 0 ); + }, + has = o && typeof o == 'object' + ? function () {if ( o.hasOwnProperty(p) ) return ( v = o[p] ) != null} + : function () {if ( a.length > i ) return ( v = a[i++] ) != null}; + + // [DECIMAL_PLACES] {number} Integer, 0 to MAX inclusive. + if ( has( p = 'DECIMAL_PLACES' ) ) { + + if ( inRange( v, 0, MAX ) ) { + DECIMAL_PLACES = v | 0; + } else { + + // 'config() DECIMAL_PLACES not an integer: {v}' + // 'config() DECIMAL_PLACES out of range: {v}' + ifExceptionsThrow( v, p, c ); + } + } + r[p] = DECIMAL_PLACES; + + // [ROUNDING_MODE] {number} Integer, 0 to 8 inclusive. + if ( has( p = 'ROUNDING_MODE' ) ) { + + if ( inRange( v, 0, 8 ) ) { + ROUNDING_MODE = v | 0; + } else { + + // 'config() ROUNDING_MODE not an integer: {v}' + // 'config() ROUNDING_MODE out of range: {v}' + ifExceptionsThrow( v, p, c ); + } + } + r[p] = ROUNDING_MODE; + + /* + * [EXPONENTIAL_AT] {number|number[]} Integer, -MAX to MAX inclusive or + * [ integer -MAX to 0 inclusive, 0 to MAX inclusive ]. + */ + if ( has( p = 'EXPONENTIAL_AT' ) ) { + + if ( inRange( v, -MAX, MAX ) ) { + TO_EXP_NEG = -( TO_EXP_POS = ~~( v < 0 ? -v : +v ) ); + } else if ( !outOfRange && v && inRange( v[0], -MAX, 0 ) && + inRange( v[1], 0, MAX ) ) { + TO_EXP_NEG = ~~v[0]; + TO_EXP_POS = ~~v[1]; + } else { + + // 'config() EXPONENTIAL_AT not an integer or not [integer, integer]: {v}' + // 'config() EXPONENTIAL_AT out of range or not [negative, positive: {v}' + ifExceptionsThrow( v, p, c, 1 ); + } + } + r[p] = [ TO_EXP_NEG, TO_EXP_POS ]; + + /* + * [RANGE][ {number|number[]} Non-zero integer, -MAX to MAX inclusive or + * [ integer -MAX to -1 inclusive, integer 1 to MAX inclusive ]. + */ + if ( has( p = 'RANGE' ) ) { + + if ( inRange( v, -MAX, MAX ) && ~~v ) { + MIN_EXP = -( MAX_EXP = ~~( v < 0 ? -v : +v ) ); + } else if ( !outOfRange && v && inRange( v[0], -MAX, -1 ) && + inRange( v[1], 1, MAX ) ) { + MIN_EXP = ~~v[0], MAX_EXP = ~~v[1]; + } else { + + // 'config() RANGE not a non-zero integer or not [integer, integer]: {v}' + // 'config() RANGE out of range or not [negative, positive: {v}' + ifExceptionsThrow( v, p, c, 1, 1 ); + } + } + r[p] = [ MIN_EXP, MAX_EXP ]; + + // [ERRORS] {boolean|number} true, false, 1 or 0. + if ( has( p = 'ERRORS' ) ) { + + if ( v === !!v || v === 1 || v === 0 ) { + parse = ( outOfRange = id = 0, ERRORS = !!v ) + ? parseInt + : parseFloat; + } else { + + // 'config() ERRORS not a boolean or binary digit: {v}' + ifExceptionsThrow( v, p, c, 0, 0, 1 ); + } + } + r[p] = ERRORS; + + return r; +}; + + +// PRIVATE FUNCTIONS + + +// Assemble error messages. Throw BigNumber Errors. +function ifExceptionsThrow( arg, i, j, isArray, isRange, isErrors) { + + if ( ERRORS ) { + var error, + method = ['new BigNumber', 'cmp', 'div', 'eq', 'gt', 'gte', 'lt', + 'lte', 'minus', 'mod', 'plus', 'times', 'toFr' + ][ id ? id < 0 ? -id : id : 1 / id < 0 ? 1 : 0 ] + '()', + message = outOfRange ? ' out of range' : ' not a' + + ( isRange ? ' non-zero' : 'n' ) + ' integer'; + + message = ( [ + method + ' number type has more than 15 significant digits', + method + ' not a base ' + j + ' number', + method + ' base' + message, + method + ' not a number' ][i] || + j + '() ' + i + ( isErrors + ? ' not a boolean or binary digit' + : message + ( isArray + ? ' or not [' + ( outOfRange + ? ' negative, positive' + : ' integer, integer' ) + ' ]' + : '' ) ) ) + ': ' + arg; + + outOfRange = id = 0; + error = new Error(message); + error['name'] = 'BigNumber Error'; + + throw error; + } +} + + +/* + * Convert a numeric string of baseIn to a numeric string of baseOut. + */ +function convert( nStr, baseOut, baseIn, sign ) { + var e, dvs, dvd, nArr, fracArr, fracBN; + + // Convert string of base bIn to an array of numbers of baseOut. + // Eg. strToArr('255', 10) where baseOut is 16, returns [15, 15]. + // Eg. strToArr('ff', 16) where baseOut is 10, returns [2, 5, 5]. + function strToArr( str, bIn ) { + var j, + i = 0, + strL = str.length, + arrL, + arr = [0]; + + for ( bIn = bIn || baseIn; i < strL; i++ ) { + + for ( arrL = arr.length, j = 0; j < arrL; arr[j] *= bIn, j++ ) { + } + + for ( arr[0] += DIGITS.indexOf( str.charAt(i) ), j = 0; + j < arr.length; + j++ ) { + + if ( arr[j] > baseOut - 1 ) { + + if ( arr[j + 1] == null ) { + arr[j + 1] = 0; + } + arr[j + 1] += arr[j] / baseOut ^ 0; + arr[j] %= baseOut; + } + } + } + + return arr.reverse(); + } + + // Convert array to string. + // E.g. arrToStr( [9, 10, 11] ) becomes '9ab' (in bases above 11). + function arrToStr( arr ) { + var i = 0, + arrL = arr.length, + str = ''; + + for ( ; i < arrL; str += DIGITS.charAt( arr[i++] ) ) { + } + + return str; + } + + if ( baseIn < 37 ) { + nStr = nStr.toLowerCase(); + } + + /* + * If non-integer convert integer part and fraction part separately. + * Convert the fraction part as if it is an integer than use division to + * reduce it down again to a value less than one. + */ + if ( ( e = nStr.indexOf( '.' ) ) > -1 ) { + + /* + * Calculate the power to which to raise the base to get the number + * to divide the fraction part by after it has been converted as an + * integer to the required base. + */ + e = nStr.length - e - 1; + + // Use toFixed to avoid possible exponential notation. + dvs = strToArr( new BigNumber(baseIn)['pow'](e)['toF'](), 10 ); + + nArr = nStr.split('.'); + + // Convert the base of the fraction part (as integer). + dvd = strToArr( nArr[1] ); + + // Convert the base of the integer part. + nArr = strToArr( nArr[0] ); + + // Result will be a BigNumber with a value less than 1. + fracBN = divide( dvd, dvs, dvd.length - dvs.length, sign, baseOut, + // Is least significant digit of integer part an odd number? + nArr[nArr.length - 1] & 1 ); + + fracArr = fracBN['c']; + + // e can be <= 0 ( if e == 0, fracArr is [0] or [1] ). + if ( e = fracBN['e'] ) { + + // Append zeros according to the exponent of the result. + for ( ; ++e; fracArr.unshift(0) ) { + } + + // Append the fraction part to the converted integer part. + nStr = arrToStr(nArr) + '.' + arrToStr(fracArr); + + // fracArr is [1]. + // Fraction digits rounded up, so increment last digit of integer part. + } else if ( fracArr[0] ) { + + if ( nArr[ e = nArr.length - 1 ] < baseOut - 1 ) { + ++nArr[e]; + nStr = arrToStr(nArr); + } else { + nStr = new BigNumber( arrToStr(nArr), + baseOut )['plus'](ONE)['toS'](baseOut); + } + + // fracArr is [0]. No fraction digits. + } else { + nStr = arrToStr(nArr); + } + } else { + + // Simple integer. Convert base. + nStr = arrToStr( strToArr(nStr) ); + } + + return nStr; +} + + +// Perform division in the specified base. Called by div and convert. +function divide( dvd, dvs, exp, s, base, isOdd ) { + var dvsL, dvsT, next, cmp, remI, + dvsZ = dvs.slice(), + dvdI = dvsL = dvs.length, + dvdL = dvd.length, + rem = dvd.slice( 0, dvsL ), + remL = rem.length, + quo = new BigNumber(ONE), + qc = quo['c'] = [], + qi = 0, + dig = DECIMAL_PLACES + ( quo['e'] = exp ) + 1; + + quo['s'] = s; + s = dig < 0 ? 0 : dig; + + // Add zeros to make remainder as long as divisor. + for ( ; remL++ < dvsL; rem.push(0) ) { + } + + // Create version of divisor with leading zero. + dvsZ.unshift(0); + + do { + + // 'next' is how many times the divisor goes into the current remainder. + for ( next = 0; next < base; next++ ) { + + // Compare divisor and remainder. + if ( dvsL != ( remL = rem.length ) ) { + cmp = dvsL > remL ? 1 : -1; + } else { + for ( remI = -1, cmp = 0; ++remI < dvsL; ) { + + if ( dvs[remI] != rem[remI] ) { + cmp = dvs[remI] > rem[remI] ? 1 : -1; + break; + } + } + } + + // Subtract divisor from remainder (if divisor < remainder). + if ( cmp < 0 ) { + + // Remainder cannot be more than one digit longer than divisor. + // Equalise lengths using divisor with extra leading zero? + for ( dvsT = remL == dvsL ? dvs : dvsZ; remL; ) { + + if ( rem[--remL] < dvsT[remL] ) { + + for ( remI = remL; + remI && !rem[--remI]; + rem[remI] = base - 1 ) { + } + --rem[remI]; + rem[remL] += base; + } + rem[remL] -= dvsT[remL]; + } + for ( ; !rem[0]; rem.shift() ) { + } + } else { + break; + } + } + + // Add the 'next' digit to the result array. + qc[qi++] = cmp ? next : ++next; + + // Update the remainder. + rem[0] && cmp + ? ( rem[remL] = dvd[dvdI] || 0 ) + : ( rem = [ dvd[dvdI] ] ); + + } while ( ( dvdI++ < dvdL || rem[0] != null ) && s-- ); + + // Leading zero? Do not remove if result is simply zero (qi == 1). + if ( !qc[0] && qi != 1 ) { + + // There can't be more than one zero. + --quo['e']; + qc.shift(); + } + + // Round? + if ( qi > dig ) { + rnd( quo, DECIMAL_PLACES, base, isOdd, rem[0] != null ); + } + + // Overflow? + if ( quo['e'] > MAX_EXP ) { + + // Infinity. + quo['c'] = quo['e'] = null; + + // Underflow? + } else if ( quo['e'] < MIN_EXP ) { + + // Zero. + quo['c'] = [quo['e'] = 0]; + } + + return quo; +} + + +/* + * Return a string representing the value of BigNumber n in normal or + * exponential notation rounded to the specified decimal places or + * significant digits. + * Called by toString, toExponential (exp 1), toFixed, and toPrecision (exp 2). + * d is the index (with the value in normal notation) of the digit that may be + * rounded up. + */ +function format( n, d, exp ) { + + // Initially, i is the number of decimal places required. + var i = d - (n = new BigNumber(n))['e'], + c = n['c']; + + // +-Infinity or NaN? + if ( !c ) { + return n['toS'](); + } + + // Round? + if ( c.length > ++d ) { + rnd( n, i, 10 ); + } + + // Recalculate d if toFixed as n['e'] may have changed if value rounded up. + i = c[0] == 0 ? i + 1 : exp ? d : n['e'] + i + 1; + + // Append zeros? + for ( ; c.length < i; c.push(0) ) { + } + i = n['e']; + + /* + * toPrecision returns exponential notation if the number of significant + * digits specified is less than the number of digits necessary to + * represent the integer part of the value in normal notation. + */ + return exp == 1 || exp == 2 && ( --d < i || i <= TO_EXP_NEG ) + + // Exponential notation. + ? ( n['s'] < 0 && c[0] ? '-' : '' ) + ( c.length > 1 + ? ( c.splice( 1, 0, '.' ), c.join('') ) + : c[0] ) + ( i < 0 ? 'e' : 'e+' ) + i + + // Normal notation. + : n['toS'](); +} + + +// Round if necessary. +// Called by divide, format, setMode and sqrt. +function rnd( x, dp, base, isOdd, r ) { + var xc = x['c'], + isNeg = x['s'] < 0, + half = base / 2, + i = x['e'] + dp + 1, + + // 'next' is the digit after the digit that may be rounded up. + next = xc[i], + + /* + * 'more' is whether there are digits after 'next'. + * E.g. + * 0.005 (e = -3) to be rounded to 0 decimal places (dp = 0) gives i = -2 + * The 'next' digit is zero, and there ARE 'more' digits after it. + * 0.5 (e = -1) dp = 0 gives i = 0 + * The 'next' digit is 5 and there are no 'more' digits after it. + */ + more = r || i < 0 || xc[i + 1] != null; + + r = ROUNDING_MODE < 4 + ? ( next != null || more ) && + ( ROUNDING_MODE == 0 || + ROUNDING_MODE == 2 && !isNeg || + ROUNDING_MODE == 3 && isNeg ) + : next > half || next == half && + ( ROUNDING_MODE == 4 || more || + + /* + * isOdd is used in base conversion and refers to the least significant + * digit of the integer part of the value to be converted. The fraction + * part is rounded by this method separately from the integer part. + */ + ROUNDING_MODE == 6 && ( xc[i - 1] & 1 || !dp && isOdd ) || + ROUNDING_MODE == 7 && !isNeg || + ROUNDING_MODE == 8 && isNeg ); + + if ( i < 1 || !xc[0] ) { + xc.length = 0; + xc.push(0); + + if ( r ) { + + // 1, 0.1, 0.01, 0.001, 0.0001 etc. + xc[0] = 1; + x['e'] = -dp; + } else { + + // Zero. + x['e'] = 0; + } + + return x; + } + + // Remove any digits after the required decimal places. + xc.length = i--; + + // Round up? + if ( r ) { + + // Rounding up may mean the previous digit has to be rounded up and so on. + for ( --base; ++xc[i] > base; ) { + xc[i] = 0; + + if ( !i-- ) { + ++x['e']; + xc.unshift(1); + } + } + } + + // Remove trailing zeros. + for ( i = xc.length; !xc[--i]; xc.pop() ) { + } + + return x; +} + + +// Round after setting the appropriate rounding mode. +// Handles ceil, floor and round. +function setMode( x, dp, rm ) { + var r = ROUNDING_MODE; + + ROUNDING_MODE = rm; + x = new BigNumber(x); + x['c'] && rnd( x, dp, 10 ); + ROUNDING_MODE = r; + + return x; +} + + +// PROTOTYPE/INSTANCE METHODS + + +/* + * Return a new BigNumber whose value is the absolute value of this BigNumber. + */ +P['abs'] = P['absoluteValue'] = function () { + var x = new BigNumber(this); + + if ( x['s'] < 0 ) { + x['s'] = 1; + } + + return x; +}; + +/* + * Return the bit length of the number. + */ +P['bitLength'] = function () { + return this.toString(2).length; +}; + + +/* + * Return a new BigNumber whose value is the value of this BigNumber + * rounded to a whole number in the direction of Infinity. + */ +P['ceil'] = function () { + return setMode( this, 0, 2 ); +}; + + +/* + * Return + * 1 if the value of this BigNumber is greater than the value of BigNumber(y, b), + * -1 if the value of this BigNumber is less than the value of BigNumber(y, b), + * 0 if they have the same value, + * or null if the value of either is NaN. + */ +P['comparedTo'] = P['cmp'] = function ( y, b ) { + var a, + x = this, + xc = x['c'], + yc = ( id = -id, y = new BigNumber( y, b ) )['c'], + i = x['s'], + j = y['s'], + k = x['e'], + l = y['e']; + + // Either NaN? + if ( !i || !j ) { + return null; + } + + a = xc && !xc[0], b = yc && !yc[0]; + + // Either zero? + if ( a || b ) { + return a ? b ? 0 : -j : i; + } + + // Signs differ? + if ( i != j ) { + return i; + } + + // Either Infinity? + if ( a = i < 0, b = k == l, !xc || !yc ) { + return b ? 0 : !xc ^ a ? 1 : -1; + } + + // Compare exponents. + if ( !b ) { + return k > l ^ a ? 1 : -1; + } + + // Compare digit by digit. + for ( i = -1, + j = ( k = xc.length ) < ( l = yc.length ) ? k : l; + ++i < j; ) { + + if ( xc[i] != yc[i] ) { + return xc[i] > yc[i] ^ a ? 1 : -1; + } + } + // Compare lengths. + return k == l ? 0 : k > l ^ a ? 1 : -1; +}; + + +/* + * n / 0 = I + * n / N = N + * n / I = 0 + * 0 / n = 0 + * 0 / 0 = N + * 0 / N = N + * 0 / I = 0 + * N / n = N + * N / 0 = N + * N / N = N + * N / I = N + * I / n = I + * I / 0 = I + * I / N = N + * I / I = N + * + * Return a new BigNumber whose value is the value of this BigNumber + * divided by the value of BigNumber(y, b), rounded according to + * DECIMAL_PLACES and ROUNDING_MODE. + */ +P['dividedBy'] = P['div'] = function ( y, b ) { + var xc = this['c'], + xe = this['e'], + xs = this['s'], + yc = ( id = 2, y = new BigNumber( y, b ) )['c'], + ye = y['e'], + ys = y['s'], + s = xs == ys ? 1 : -1; + + // Either NaN/Infinity/0? + return !xe && ( !xc || !xc[0] ) || !ye && ( !yc || !yc[0] ) + + // Either NaN? + ? new BigNumber( !xs || !ys || + + // Both 0 or both Infinity? + ( xc ? yc && xc[0] == yc[0] : !yc ) + + // Return NaN. + ? NaN + + // x is 0 or y is Infinity? + : xc && xc[0] == 0 || !yc + + // Return +-0. + ? s * 0 + + // y is 0. Return +-Infinity. + : s / 0 ) + + : divide( xc, yc, xe - ye, s, 10 ); +}; + + +/* + * Return true if the value of this BigNumber is equal to the value of + * BigNumber(n, b), otherwise returns false. + */ +P['equals'] = P['eq'] = function ( n, b ) { + id = 3; + return this['cmp']( n, b ) === 0; +}; + + +/* + * Return a new BigNumber whose value is the value of this BigNumber + * rounded to a whole number in the direction of -Infinity. + */ +P['floor'] = function () { + return setMode( this, 0, 3 ); +}; + + +/* + * Return true if the value of this BigNumber is greater than the value of + * BigNumber(n, b), otherwise returns false. + */ +P['greaterThan'] = P['gt'] = function ( n, b ) { + id = 4; + return this['cmp']( n, b ) > 0; +}; + + +/* + * Return true if the value of this BigNumber is greater than or equal to + * the value of BigNumber(n, b), otherwise returns false. + */ +P['greaterThanOrEqualTo'] = P['gte'] = function ( n, b ) { + id = 5; + return ( b = this['cmp']( n, b ) ) == 1 || b === 0; +}; + + +/* + * Return true if the value of this BigNumber is a finite number, otherwise + * returns false. + */ +P['isFinite'] = P['isF'] = function () { + return !!this['c']; +}; + + +/* + * Return true if the value of this BigNumber is NaN, otherwise returns + * false. + */ +P['isNaN'] = function () { + return !this['s']; +}; + + +/* + * Return true if the value of this BigNumber is negative, otherwise + * returns false. + */ +P['isNegative'] = P['isNeg'] = function () { + return this['s'] < 0; +}; + + +/* + * Return true if the value of this BigNumber is 0 or -0, otherwise returns + * false. + */ +P['isZero'] = P['isZ'] = function () { + return !!this['c'] && this['c'][0] == 0; +}; + + +/* + * Return true if the value of this BigNumber is less than the value of + * BigNumber(n, b), otherwise returns false. + */ +P['lessThan'] = P['lt'] = function ( n, b ) { + id = 6; + return this['cmp']( n, b ) < 0; +}; + + +/* + * Return true if the value of this BigNumber is less than or equal to the + * value of BigNumber(n, b), otherwise returns false. + */ +P['lessThanOrEqualTo'] = P['lte'] = P['le'] = function ( n, b ) { + id = 7; + return ( b = this['cmp']( n, b ) ) == -1 || b === 0; +}; + + +/* + * n - 0 = n + * n - N = N + * n - I = -I + * 0 - n = -n + * 0 - 0 = 0 + * 0 - N = N + * 0 - I = -I + * N - n = N + * N - 0 = N + * N - N = N + * N - I = N + * I - n = I + * I - 0 = I + * I - N = N + * I - I = N + * + * Return a new BigNumber whose value is the value of this BigNumber minus + * the value of BigNumber(y, b). + */ +P['minus'] = P['sub'] = function ( y, b ) { + var d, i, j, xLTy, + x = this, + a = x['s']; + + b = ( id = 8, y = new BigNumber( y, b ) )['s']; + + // Either NaN? + if ( !a || !b ) { + return new BigNumber(NaN); + } + + // Signs differ? + if ( a != b ) { + return y['s'] = -b, x['plus'](y); + } + + var xc = x['c'], + xe = x['e'], + yc = y['c'], + ye = y['e']; + + if ( !xe || !ye ) { + + // Either Infinity? + if ( !xc || !yc ) { + return xc ? ( y['s'] = -b, y ) : new BigNumber( yc ? x : NaN ); + } + + // Either zero? + if ( !xc[0] || !yc[0] ) { + + // y is non-zero? + return yc[0] + ? ( y['s'] = -b, y ) + + // x is non-zero? + : new BigNumber( xc[0] + ? x + + // Both are zero. + // IEEE 754 (2008) 6.3: n - n = -0 when rounding to -Infinity + : ROUNDING_MODE == 3 ? -0 : 0 ); + } + } + + // Determine which is the bigger number. + // Prepend zeros to equalise exponents. + if ( xc = xc.slice(), a = xe - ye ) { + d = ( xLTy = a < 0 ) ? ( a = -a, xc ) : ( ye = xe, yc ); + + for ( d.reverse(), b = a; b--; d.push(0) ) { + } + d.reverse(); + } else { + + // Exponents equal. Check digit by digit. + j = ( ( xLTy = xc.length < yc.length ) ? xc : yc ).length; + + for ( a = b = 0; b < j; b++ ) { + + if ( xc[b] != yc[b] ) { + xLTy = xc[b] < yc[b]; + break; + } + } + } + + // x < y? Point xc to the array of the bigger number. + if ( xLTy ) { + d = xc, xc = yc, yc = d; + y['s'] = -y['s']; + } + + /* + * Append zeros to xc if shorter. No need to add zeros to yc if shorter + * as subtraction only needs to start at yc.length. + */ + if ( ( b = -( ( j = xc.length ) - yc.length ) ) > 0 ) { + + for ( ; b--; xc[j++] = 0 ) { + } + } + + // Subtract yc from xc. + for ( b = yc.length; b > a; ){ + + if ( xc[--b] < yc[b] ) { + + for ( i = b; i && !xc[--i]; xc[i] = 9 ) { + } + --xc[i]; + xc[b] += 10; + } + xc[b] -= yc[b]; + } + + // Remove trailing zeros. + for ( ; xc[--j] == 0; xc.pop() ) { + } + + // Remove leading zeros and adjust exponent accordingly. + for ( ; xc[0] == 0; xc.shift(), --ye ) { + } + + /* + * No need to check for Infinity as +x - +y != Infinity && -x - -y != Infinity + * when neither x or y are Infinity. + */ + + // Underflow? + if ( ye < MIN_EXP || !xc[0] ) { + + /* + * Following IEEE 754 (2008) 6.3, + * n - n = +0 but n - n = -0 when rounding towards -Infinity. + */ + if ( !xc[0] ) { + y['s'] = ROUNDING_MODE == 3 ? -1 : 1; + } + + // Result is zero. + xc = [ye = 0]; + } + + return y['c'] = xc, y['e'] = ye, y; +}; + + +/* + * n % 0 = N + * n % N = N + * 0 % n = 0 + * -0 % n = -0 + * 0 % 0 = N + * 0 % N = N + * N % n = N + * N % 0 = N + * N % N = N + * + * Return a new BigNumber whose value is the value of this BigNumber modulo + * the value of BigNumber(y, b). + */ +P['modulo'] = P['mod'] = function ( y, b ) { + var x = this, + xc = x['c'], + yc = ( id = 9, y = new BigNumber( y, b ) )['c'], + i = x['s'], + j = y['s']; + + // Is x or y NaN, or y zero? + b = !i || !j || yc && !yc[0]; + + if ( b || xc && !xc[0] ) { + return new BigNumber( b ? NaN : x ); + } + + x['s'] = y['s'] = 1; + b = y['cmp'](x) == 1; + x['s'] = i, y['s'] = j; + + return b + ? new BigNumber(x) + : ( i = DECIMAL_PLACES, j = ROUNDING_MODE, + DECIMAL_PLACES = 0, ROUNDING_MODE = 1, + x = x['div'](y), + DECIMAL_PLACES = i, ROUNDING_MODE = j, + this['minus']( x['times'](y) ) ); +}; + + +/* + * Return a new BigNumber whose value is the value of this BigNumber + * negated, i.e. multiplied by -1. + */ +P['negated'] = P['neg'] = function () { + var x = new BigNumber(this); + + return x['s'] = -x['s'] || null, x; +}; + + +/* + * n + 0 = n + * n + N = N + * n + I = I + * 0 + n = n + * 0 + 0 = 0 + * 0 + N = N + * 0 + I = I + * N + n = N + * N + 0 = N + * N + N = N + * N + I = N + * I + n = I + * I + 0 = I + * I + N = N + * I + I = I + * + * Return a new BigNumber whose value is the value of this BigNumber plus + * the value of BigNumber(y, b). + */ +P['plus'] = P['add'] = function ( y, b ) { + var d, + x = this, + a = x['s']; + + b = ( id = 10, y = new BigNumber( y, b ) )['s']; + + // Either NaN? + if ( !a || !b ) { + return new BigNumber(NaN); + } + + // Signs differ? + if ( a != b ) { + return y['s'] = -b, x['minus'](y); + } + + var xe = x['e'], + xc = x['c'], + ye = y['e'], + yc = y['c']; + + if ( !xe || !ye ) { + + // Either Infinity? + if ( !xc || !yc ) { + + // Return +-Infinity. + return new BigNumber( a / 0 ); + } + + // Either zero? + if ( !xc[0] || !yc[0] ) { + + // y is non-zero? + return yc[0] + ? y + + // x is non-zero? + : new BigNumber( xc[0] + ? x + + // Both are zero. Return zero. + : a * 0 ); + } + } + + // Prepend zeros to equalise exponents. + // Note: Faster to use reverse then do unshifts. + if ( xc = xc.slice(), a = xe - ye ) { + d = a > 0 ? ( ye = xe, yc ) : ( a = -a, xc ); + + for ( d.reverse(); a--; d.push(0) ) { + } + d.reverse(); + } + + // Point xc to the longer array. + if ( xc.length - yc.length < 0 ) { + d = yc, yc = xc, xc = d; + } + + /* + * Only start adding at yc.length - 1 as the + * further digits of xc can be left as they are. + */ + for ( a = yc.length, b = 0; a; + b = ( xc[--a] = xc[a] + yc[a] + b ) / 10 ^ 0, xc[a] %= 10 ) { + } + + // No need to check for zero, as +x + +y != 0 && -x + -y != 0 + + if ( b ) { + xc.unshift(b); + + // Overflow? (MAX_EXP + 1 possible) + if ( ++ye > MAX_EXP ) { + + // Infinity. + xc = ye = null; + } + } + + // Remove trailing zeros. + for ( a = xc.length; xc[--a] == 0; xc.pop() ) { + } + + return y['c'] = xc, y['e'] = ye, y; +}; + + +/* + * Return a BigNumber whose value is the value of this BigNumber raised to + * the power e. If e is negative round according to DECIMAL_PLACES and + * ROUNDING_MODE. + * + * e {number} Integer, -MAX_POWER to MAX_POWER inclusive. + */ +P['toPower'] = P['pow'] = function ( e ) { + + // e to integer, avoiding NaN or Infinity becoming 0. + var i = e * 0 == 0 ? e | 0 : e, + x = new BigNumber(this), + y = new BigNumber(ONE); + + // Use Math.pow? + // Pass +-Infinity for out of range exponents. + if ( ( ( ( outOfRange = e < -MAX_POWER || e > MAX_POWER ) && + (i = e * 1 / 0) ) || + + /* + * Any exponent that fails the parse becomes NaN. + * + * Include 'e !== 0' because on Opera -0 == parseFloat(-0) is false, + * despite -0 === parseFloat(-0) && -0 == parseFloat('-0') is true. + */ + parse(e) != e && e !== 0 && !(i = NaN) ) && + + // 'pow() exponent not an integer: {e}' + // 'pow() exponent out of range: {e}' + !ifExceptionsThrow( e, 'exponent', 'pow' ) || + + // Pass zero to Math.pow, as any value to the power zero is 1. + !i ) { + + // i is +-Infinity, NaN or 0. + return new BigNumber( Math.pow( x['toS'](), i ) ); + } + + for ( i = i < 0 ? -i : i; ; ) { + + if ( i & 1 ) { + y = y['times'](x); + } + i >>= 1; + + if ( !i ) { + break; + } + x = x['times'](x); + } + + return e < 0 ? ONE['div'](y) : y; +}; + + +/* + * Return a BigNumber whose value is the value of this BigNumber raised to + * the power m modulo n. + * + * m {BigNumber} the value to take the power of + * n {BigNumber} the value to modulo by + */ +P['powm'] = function ( m, n ) { + return this.pow(m).mod(n); +}; + + +/* + * Return a new BigNumber whose value is the value of this BigNumber + * rounded to a maximum of dp decimal places using rounding mode rm, or to + * 0 and ROUNDING_MODE respectively if omitted. + * + * [dp] {number} Integer, 0 to MAX inclusive. + * [rm] {number} Integer, 0 to 8 inclusive. + */ +P['round'] = function ( dp, rm ) { + + dp = dp == null || ( ( ( outOfRange = dp < 0 || dp > MAX ) || + parse(dp) != dp ) && + + // 'round() decimal places out of range: {dp}' + // 'round() decimal places not an integer: {dp}' + !ifExceptionsThrow( dp, 'decimal places', 'round' ) ) + ? 0 + : dp | 0; + + rm = rm == null || ( ( ( outOfRange = rm < 0 || rm > 8 ) || + + // Include '&& rm !== 0' because with Opera -0 == parseFloat(-0) is false. + parse(rm) != rm && rm !== 0 ) && + + // 'round() mode not an integer: {rm}' + // 'round() mode out of range: {rm}' + !ifExceptionsThrow( rm, 'mode', 'round' ) ) + ? ROUNDING_MODE + : rm | 0; + + return setMode( this, dp, rm ); +}; + + +/* + * sqrt(-n) = N + * sqrt( N) = N + * sqrt(-I) = N + * sqrt( I) = I + * sqrt( 0) = 0 + * sqrt(-0) = -0 + * + * Return a new BigNumber whose value is the square root of the value of + * this BigNumber, rounded according to DECIMAL_PLACES and ROUNDING_MODE. + */ +P['squareRoot'] = P['sqrt'] = function () { + var n, r, re, t, + x = this, + c = x['c'], + s = x['s'], + e = x['e'], + dp = DECIMAL_PLACES, + rm = ROUNDING_MODE, + half = new BigNumber('0.5'); + + // Negative/NaN/Infinity/zero? + if ( s !== 1 || !c || !c[0] ) { + + return new BigNumber( !s || s < 0 && ( !c || c[0] ) + ? NaN + : c ? x : 1 / 0 ); + } + + // Initial estimate. + s = Math.sqrt( x['toS']() ); + ROUNDING_MODE = 1; + + /* + Math.sqrt underflow/overflow? + Pass x to Math.sqrt as integer, then adjust the exponent of the result. + */ + if ( s == 0 || s == 1 / 0 ) { + n = c.join(''); + + if ( !( n.length + e & 1 ) ) { + n += '0'; + } + r = new BigNumber( Math.sqrt(n) + '' ); + + // r may still not be finite. + if ( !r['c'] ) { + r['c'] = [1]; + } + r['e'] = ( ( ( e + 1 ) / 2 ) | 0 ) - ( e < 0 || e & 1 ); + } else { + r = new BigNumber( n = s.toString() ); + } + re = r['e']; + s = re + ( DECIMAL_PLACES += 4 ); + + if ( s < 3 ) { + s = 0; + } + e = s; + + // Newton-Raphson iteration. + for ( ; ; ) { + t = r; + r = half['times']( t['plus']( x['div'](t) ) ); + + if ( t['c'].slice( 0, s ).join('') === r['c'].slice( 0, s ).join('') ) { + c = r['c']; + + /* + The exponent of r may here be one less than the final result + exponent (re), e.g 0.0009999 (e-4) --> 0.001 (e-3), so adjust + s so the rounding digits are indexed correctly. + */ + s = s - ( n && r['e'] < re ); + + /* + The 4th rounding digit may be in error by -1 so if the 4 rounding + digits are 9999 or 4999 (i.e. approaching a rounding boundary) + continue the iteration. + */ + if ( c[s] == 9 && c[s - 1] == 9 && c[s - 2] == 9 && + ( c[s - 3] == 9 || n && c[s - 3] == 4 ) ) { + + /* + If 9999 on first run through, check to see if rounding up + gives the exact result as the nines may infinitely repeat. + */ + if ( n && c[s - 3] == 9 ) { + t = r['round']( dp, 0 ); + + if ( t['times'](t)['eq'](x) ) { + ROUNDING_MODE = rm; + DECIMAL_PLACES = dp; + + return t; + } + } + DECIMAL_PLACES += 4; + s += 4; + n = ''; + } else { + + /* + If the rounding digits are null, 0000 or 5000, check for an + exact result. If not, then there are further digits so + increment the 1st rounding digit to ensure correct rounding. + */ + if ( !c[e] && !c[e - 1] && !c[e - 2] && + ( !c[e - 3] || c[e - 3] == 5 ) ) { + + // Truncate to the first rounding digit. + if ( c.length > e - 2 ) { + c.length = e - 2; + } + + if ( !r['times'](r)['eq'](x) ) { + + while ( c.length < e - 3 ) { + c.push(0); + } + c[e - 3]++; + } + } + ROUNDING_MODE = rm; + rnd( r, DECIMAL_PLACES = dp, 10 ); + + return r; + } + } + } +}; + + +/* + * n * 0 = 0 + * n * N = N + * n * I = I + * 0 * n = 0 + * 0 * 0 = 0 + * 0 * N = N + * 0 * I = N + * N * n = N + * N * 0 = N + * N * N = N + * N * I = N + * I * n = I + * I * 0 = N + * I * N = N + * I * I = I + * + * Return a new BigNumber whose value is the value of this BigNumber times + * the value of BigNumber(y, b). + */ +P['times'] = P['mul'] = function ( y, b ) { + var c, + x = this, + xc = x['c'], + yc = ( id = 11, y = new BigNumber( y, b ) )['c'], + i = x['e'], + j = y['e'], + a = x['s']; + + y['s'] = a == ( b = y['s'] ) ? 1 : -1; + + // Either NaN/Infinity/0? + if ( !i && ( !xc || !xc[0] ) || !j && ( !yc || !yc[0] ) ) { + + // Either NaN? + return new BigNumber( !a || !b || + + // x is 0 and y is Infinity or y is 0 and x is Infinity? + xc && !xc[0] && !yc || yc && !yc[0] && !xc + + // Return NaN. + ? NaN + + // Either Infinity? + : !xc || !yc + + // Return +-Infinity. + ? y['s'] / 0 + + // x or y is 0. Return +-0. + : y['s'] * 0 ); + } + y['e'] = i + j; + + if ( ( a = xc.length ) < ( b = yc.length ) ) { + c = xc, xc = yc, yc = c, j = a, a = b, b = j; + } + + for ( j = a + b, c = []; j--; c.push(0) ) { + } + + // Multiply! + for ( i = b - 1; i > -1; i-- ) { + + for ( b = 0, j = a + i; + j > i; + b = c[j] + yc[i] * xc[j - i - 1] + b, + c[j--] = b % 10 | 0, + b = b / 10 | 0 ) { + } + + if ( b ) { + c[j] = ( c[j] + b ) % 10; + } + } + + b && ++y['e']; + + // Remove any leading zero. + !c[0] && c.shift(); + + // Remove trailing zeros. + for ( j = c.length; !c[--j]; c.pop() ) { + } + + // No zero check needed as only x * 0 == 0 etc. + + // Overflow? + y['c'] = y['e'] > MAX_EXP + + // Infinity. + ? ( y['e'] = null ) + + // Underflow? + : y['e'] < MIN_EXP + + // Zero. + ? [ y['e'] = 0 ] + + // Neither. + : c; + + return y; +}; + +/* + * Return a buffer containing the + */ +P['toBuffer'] = function ( opts ) { + + if (typeof opts === 'string') { + if (opts !== 'mpint') return 'Unsupported Buffer representation'; + + var abs = this.abs(); + var buf = abs.toBuffer({ size : 1, endian : 'big' }); + var len = buf.length === 1 && buf[0] === 0 ? 0 : buf.length; + if (buf[0] & 0x80) len ++; + + var ret = new Buffer(4 + len); + if (len > 0) buf.copy(ret, 4 + (buf[0] & 0x80 ? 1 : 0)); + if (buf[0] & 0x80) ret[4] = 0; + + ret[0] = len & (0xff << 24); + ret[1] = len & (0xff << 16); + ret[2] = len & (0xff << 8); + ret[3] = len & (0xff << 0); + + // two's compliment for negative integers: + var isNeg = this.lt(0); + if (isNeg) { + for (var i = 4; i < ret.length; i++) { + ret[i] = 0xff - ret[i]; + } + } + ret[4] = (ret[4] & 0x7f) | (isNeg ? 0x80 : 0); + if (isNeg) ret[ret.length - 1] ++; + + return ret; + } + + if (!opts) opts = {}; + + var endian = { 1 : 'big', '-1' : 'little' }[opts.endian] + || opts.endian || 'big' + ; + + var hex = this.toString(16); + if (hex.charAt(0) === '-') throw new Error( + 'converting negative numbers to Buffers not supported yet' + ); + + var size = opts.size === 'auto' ? Math.ceil(hex.length / 2) : (opts.size || 1); + + var len = Math.ceil(hex.length / (2 * size)) * size; + var buf = new Buffer(len); + + // zero-pad the hex string so the chunks are all `size` long + while (hex.length < 2 * len) hex = '0' + hex; + + var hx = hex + .split(new RegExp('(.{' + (2 * size) + '})')) + .filter(function (s) { return s.length > 0 }) + ; + + hx.forEach(function (chunk, i) { + for (var j = 0; j < size; j++) { + var ix = i * size + (endian === 'big' ? j : size - j - 1); + buf[ix] = parseInt(chunk.slice(j*2,j*2+2), 16); + } + }); + + return buf; +}; + +/* + * Return a string representing the value of this BigNumber in exponential + * notation to dp fixed decimal places and rounded using ROUNDING_MODE if + * necessary. + * + * [dp] {number} Integer, 0 to MAX inclusive. + */ +P['toExponential'] = P['toE'] = function ( dp ) { + + return format( this, + ( dp == null || ( ( outOfRange = dp < 0 || dp > MAX ) || + + /* + * Include '&& dp !== 0' because with Opera -0 == parseFloat(-0) is + * false, despite -0 == parseFloat('-0') && 0 == -0 being true. + */ + parse(dp) != dp && dp !== 0 ) && + + // 'toE() decimal places not an integer: {dp}' + // 'toE() decimal places out of range: {dp}' + !ifExceptionsThrow( dp, 'decimal places', 'toE' ) ) && this['c'] + ? this['c'].length - 1 + : dp | 0, 1 ); +}; + + +/* + * Return a string representing the value of this BigNumber in normal + * notation to dp fixed decimal places and rounded using ROUNDING_MODE if + * necessary. + * + * Note: as with JavaScript's number type, (-0).toFixed(0) is '0', + * but e.g. (-0.00001).toFixed(0) is '-0'. + * + * [dp] {number} Integer, 0 to MAX inclusive. + */ +P['toFixed'] = P['toF'] = function ( dp ) { + var n, str, d, + x = this; + + if ( !( dp == null || ( ( outOfRange = dp < 0 || dp > MAX ) || + parse(dp) != dp && dp !== 0 ) && + + // 'toF() decimal places not an integer: {dp}' + // 'toF() decimal places out of range: {dp}' + !ifExceptionsThrow( dp, 'decimal places', 'toF' ) ) ) { + d = x['e'] + ( dp | 0 ); + } + + n = TO_EXP_NEG, dp = TO_EXP_POS; + TO_EXP_NEG = -( TO_EXP_POS = 1 / 0 ); + + // Note: str is initially undefined. + if ( d == str ) { + str = x['toS'](); + } else { + str = format( x, d ); + + // (-0).toFixed() is '0', but (-0.1).toFixed() is '-0'. + // (-0).toFixed(1) is '0.0', but (-0.01).toFixed(1) is '-0.0'. + if ( x['s'] < 0 && x['c'] ) { + + // As e.g. -0 toFixed(3), will wrongly be returned as -0.000 from toString. + if ( !x['c'][0] ) { + str = str.replace(/^-/, ''); + + // As e.g. -0.5 if rounded to -0 will cause toString to omit the minus sign. + } else if ( str.indexOf('-') < 0 ) { + str = '-' + str; + } + } + } + TO_EXP_NEG = n, TO_EXP_POS = dp; + + return str; +}; + + +/* + * Return a string array representing the value of this BigNumber as a + * simple fraction with an integer numerator and an integer denominator. + * The denominator will be a positive non-zero value less than or equal to + * the specified maximum denominator. If a maximum denominator is not + * specified, the denominator will be the lowest value necessary to + * represent the number exactly. + * + * [maxD] {number|string|BigNumber} Integer >= 1 and < Infinity. + */ +P['toFraction'] = P['toFr'] = function ( maxD ) { + var q, frac, n0, d0, d2, n, e, + n1 = d0 = new BigNumber(ONE), + d1 = n0 = new BigNumber('0'), + x = this, + xc = x['c'], + exp = MAX_EXP, + dp = DECIMAL_PLACES, + rm = ROUNDING_MODE, + d = new BigNumber(ONE); + + // NaN, Infinity. + if ( !xc ) { + return x['toS'](); + } + + e = d['e'] = xc.length - x['e'] - 1; + + // If max denominator is undefined or null... + if ( maxD == null || + + // or NaN... + ( !( id = 12, n = new BigNumber(maxD) )['s'] || + + // or less than 1, or Infinity... + ( outOfRange = n['cmp'](n1) < 0 || !n['c'] ) || + + // or not an integer... + ( ERRORS && n['e'] < n['c'].length - 1 ) ) && + + // 'toFr() max denominator not an integer: {maxD}' + // 'toFr() max denominator out of range: {maxD}' + !ifExceptionsThrow( maxD, 'max denominator', 'toFr' ) || + + // or greater than the maxD needed to specify the value exactly... + ( maxD = n )['cmp'](d) > 0 ) { + + // d is e.g. 10, 100, 1000, 10000... , n1 is 1. + maxD = e > 0 ? d : n1; + } + + MAX_EXP = 1 / 0; + n = new BigNumber( xc.join('') ); + + for ( DECIMAL_PLACES = 0, ROUNDING_MODE = 1; ; ) { + q = n['div'](d); + d2 = d0['plus']( q['times'](d1) ); + + if ( d2['cmp'](maxD) == 1 ) { + break; + } + + d0 = d1, d1 = d2; + + n1 = n0['plus']( q['times']( d2 = n1 ) ); + n0 = d2; + + d = n['minus']( q['times']( d2 = d ) ); + n = d2; + } + + d2 = maxD['minus'](d0)['div'](d1); + n0 = n0['plus']( d2['times'](n1) ); + d0 = d0['plus']( d2['times'](d1) ); + + n0['s'] = n1['s'] = x['s']; + + DECIMAL_PLACES = e * 2; + ROUNDING_MODE = rm; + + // Determine which fraction is closer to x, n0 / d0 or n1 / d1? + frac = n1['div'](d1)['minus'](x)['abs']()['cmp']( + n0['div'](d0)['minus'](x)['abs']() ) < 1 + ? [ n1['toS'](), d1['toS']() ] + : [ n0['toS'](), d0['toS']() ]; + + return MAX_EXP = exp, DECIMAL_PLACES = dp, frac; +}; + + +/* + * Return a string representing the value of this BigNumber to sd significant + * digits and rounded using ROUNDING_MODE if necessary. + * If sd is less than the number of digits necessary to represent the integer + * part of the value in normal notation, then use exponential notation. + * + * sd {number} Integer, 1 to MAX inclusive. + */ +P['toPrecision'] = P['toP'] = function ( sd ) { + + /* + * ERRORS true: Throw if sd not undefined, null or an integer in range. + * ERRORS false: Ignore sd if not a number or not in range. + * Truncate non-integers. + */ + return sd == null || ( ( ( outOfRange = sd < 1 || sd > MAX ) || + parse(sd) != sd ) && + + // 'toP() precision not an integer: {sd}' + // 'toP() precision out of range: {sd}' + !ifExceptionsThrow( sd, 'precision', 'toP' ) ) + ? this['toS']() + : format( this, --sd | 0, 2 ); +}; + + +/* + * Return a string representing the value of this BigNumber in base b, or + * base 10 if b is omitted. If a base is specified, including base 10, + * round according to DECIMAL_PLACES and ROUNDING_MODE. + * If a base is not specified, and this BigNumber has a positive exponent + * that is equal to or greater than TO_EXP_POS, or a negative exponent equal + * to or less than TO_EXP_NEG, return exponential notation. + * + * [b] {number} Integer, 2 to 64 inclusive. + */ +P['toString'] = P['toS'] = function ( b ) { + var u, str, strL, + x = this, + xe = x['e']; + + // Infinity or NaN? + if ( xe === null ) { + str = x['s'] ? 'Infinity' : 'NaN'; + + // Exponential format? + } else if ( b === u && ( xe <= TO_EXP_NEG || xe >= TO_EXP_POS ) ) { + return format( x, x['c'].length - 1, 1 ); + } else { + str = x['c'].join(''); + + // Negative exponent? + if ( xe < 0 ) { + + // Prepend zeros. + for ( ; ++xe; str = '0' + str ) { + } + str = '0.' + str; + + // Positive exponent? + } else if ( strL = str.length, xe > 0 ) { + + if ( ++xe > strL ) { + + // Append zeros. + for ( xe -= strL; xe-- ; str += '0' ) { + } + } else if ( xe < strL ) { + str = str.slice( 0, xe ) + '.' + str.slice(xe); + } + + // Exponent zero. + } else { + if ( u = str.charAt(0), strL > 1 ) { + str = u + '.' + str.slice(1); + + // Avoid '-0' + } else if ( u == '0' ) { + return u; + } + } + + if ( b != null ) { + + if ( !( outOfRange = !( b >= 2 && b < 65 ) ) && + ( b == (b | 0) || !ERRORS ) ) { + str = convert( str, b | 0, 10, x['s'] ); + + // Avoid '-0' + if ( str == '0' ) { + return str; + } + } else { + + // 'toS() base not an integer: {b}' + // 'toS() base out of range: {b}' + ifExceptionsThrow( b, 'base', 'toS' ); + } + } + + } + + return x['s'] < 0 ? '-' + str : str; +}; + +P['toNumber'] = function () { + return parseInt(this['toString'](), 10); +}; + + +/* + * Return as toString, but do not accept a base argument. + */ +P['valueOf'] = function () { + return this['toS'](); +}; + + +// Add aliases for BigDecimal methods. +//P['add'] = P['plus']; +//P['subtract'] = P['minus']; +//P['multiply'] = P['times']; +//P['divide'] = P['div']; +//P['remainder'] = P['mod']; +//P['compareTo'] = P['cmp']; +//P['negate'] = P['neg']; + + +// EXPORT +module.exports = BigNumber; diff --git a/lib/browser/Key.js b/lib/browser/Key.js index e5df2644a..212a52d2e 100644 --- a/lib/browser/Key.js +++ b/lib/browser/Key.js @@ -1,7 +1,7 @@ var ECKey = require('../../browser/vendor-bundle.js').ECKey; var SecureRandom = require('../SecureRandom'); var Curve = require('../Curve'); -var bignum = require('bignum'); +var bignum = require('../Bignum'); var Key = function() { this._pub = null; diff --git a/lib/browser/Point.js b/lib/browser/Point.js index 8c6c085f8..4e5a14ac6 100644 --- a/lib/browser/Point.js +++ b/lib/browser/Point.js @@ -2,7 +2,7 @@ var imports = require('soop').imports(); var Key = imports.Key || require('./Key'); -var bignum = imports.bignum || require('bignum'); +var bignum = imports.bignum || require('../Bignum'); var assert = require('assert'); var ECPointFp = require('../../browser/vendor-bundle.js').ECPointFp; var ECFieldElementFp = require('../../browser/vendor-bundle.js').ECFieldElementFp; diff --git a/lib/node/Point.js b/lib/node/Point.js index 64d4dd7f8..76a04cbf7 100644 --- a/lib/node/Point.js +++ b/lib/node/Point.js @@ -1,7 +1,7 @@ "use strict"; var imports = require('soop').imports(); -var bignum = imports.bignum || require('bignum'); +var bignum = imports.bignum || require('../Bignum'); var CPPKey = imports.CPPKey || require('bindings')('KeyModule').Key; var assert = require('assert'); diff --git a/package.json b/package.json index 3585c617b..c860cd59e 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,6 @@ "dependencies": { "jssha": "=1.5.0", "soop": "=0.1.5", - "base58-native": "=0.1.3", "bindings": "=1.1.1", "bufferput": "git://github.com/bitpay/node-bufferput.git", "bignum": "=0.6.2", @@ -65,7 +64,6 @@ "browserify": "=3.40.0", "browser-pack": "=2.0.1", "commander": "=2.1.0", - "browserify-bignum": "git://github.com/maraoz/browserify-bignum.git", "browserify-buffertools": "git://github.com/maraoz/browserify-buffertools.git", "socks5-client": "~0.3.6", "brfs": "=1.0.0", diff --git a/test/test.Base58.js b/test/test.Base58.js new file mode 100644 index 000000000..edc9227a2 --- /dev/null +++ b/test/test.Base58.js @@ -0,0 +1,49 @@ +var assert = require('assert'); +var base58 = require('../lib/Base58').base58; +var base58Check = require('../lib/Base58').base58Check; + +var testData = [ + ["61", "2g", "C2dGTwc"], + ["626262", "a3gV", "4jF5uERJAK"], + ["636363", "aPEr", "4mT4krqUYJ"], + ["73696d706c792061206c6f6e6720737472696e67", "2cFupjhnEsSn59qHXstmK2ffpLv2", "BXF1HuEUCqeVzZdrKeJjG74rjeXxqJ7dW"], + ["00eb15231dfceb60925886b67d065299925915aeb172c06647", "1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L", "13REmUhe2ckUKy1FvM7AMCdtyYq831yxM3QeyEu4"], + ["516b6fcd0f", "ABnLTmg", "237LSrY9NUUas"], + ["bf4f89001e670274dd", "3SEo3LWLoPntC", "GwDDDeduj1jpykc27e"], + ["572e4794", "3EFU7m", "FamExfqCeza"], + ["ecac89cad93923c02321", "EJDM8drfXA6uyA", "2W1Yd5Zu6WGyKVtHGMrH"], + ["10c8511e", "Rt5zm", "3op3iuGMmhs"], + ["00000000000000000000", "1111111111", "111111111146Momb"], + ["", "", "3QJmnh"] +]; + +//suite('basic'); + +test('allData', function() { + base58.encodeTest = function(raw, b58str) { + assert.equal(base58.encode(raw), b58str); + }; + + base58.decodeTest = function(raw, b58str) { + assert.equal(raw.toString('hex'), base58.decode(b58str).toString('hex')); + }; + + base58Check.encodeTest = function(raw, b58str) { + assert.equal(base58Check.encode(raw), b58str); + }; + + base58Check.decodeTest = function(raw, b58str) { + assert.equal(raw.toString('hex'), base58Check.decode(b58str).toString('hex')); + }; + + testData.forEach(function(datum) { + var raw = new Buffer(datum[0], 'hex'); + var b58 = datum[1]; + var b58Check = datum[2]; + + base58.encodeTest(raw, b58); + base58.decodeTest(raw, b58); + base58Check.encodeTest(raw, b58Check); + base58Check.decodeTest(raw, b58Check); + }); +}); diff --git a/test/test.Curve.js b/test/test.Curve.js index 211645060..bb6ba049b 100644 --- a/test/test.Curve.js +++ b/test/test.Curve.js @@ -4,7 +4,7 @@ var chai = chai || require('chai'); var bitcore = bitcore || require('../bitcore'); var coinUtil = coinUtil || bitcore.util; var buffertools = require('buffertools'); -var bignum = require('bignum'); +var bignum = bitcore.Bignum; var should = chai.should(); var assert = chai.assert; diff --git a/test/test.Key.js b/test/test.Key.js index d2bef6105..2bd397c92 100644 --- a/test/test.Key.js +++ b/test/test.Key.js @@ -8,7 +8,7 @@ var assert = chai.assert; var Key = bitcore.Key; var Point = bitcore.Point; -var bignum = require('bignum'); +var bignum = bitcore.Bignum; describe('Key', function() { it('should initialize the main object', function() { diff --git a/test/test.Point.js b/test/test.Point.js index 4ca45a556..9ec2ff7c2 100644 --- a/test/test.Point.js +++ b/test/test.Point.js @@ -4,7 +4,7 @@ var chai = chai || require('chai'); var bitcore = bitcore || require('../bitcore'); var coinUtil = coinUtil || bitcore.util; var buffertools = require('buffertools'); -var bignum = require('bignum'); +var bignum = bitcore.Bignum; var should = chai.should(); var assert = chai.assert; diff --git a/test/test.misc.js b/test/test.misc.js index f3da0b852..f67642788 100644 --- a/test/test.misc.js +++ b/test/test.misc.js @@ -9,8 +9,8 @@ var should = chai.should(); var testdata = testdata || require('./testdata'); -var bignum = bitcore.bignum; -var base58 = bitcore.base58; +var bignum = bitcore.Bignum; +var base58 = bitcore.Base58; var base58Check = base58.base58Check; var Address = bitcore.Address; @@ -81,7 +81,7 @@ describe('Miscelaneous stuff', function() { }); // bignum it('should initialze the bignum object', function() { - should.exist(bitcore.bignum); + should.exist(bitcore.Bignum); }); it('should create a bignum from string', function() { var n = bignum('9832087987979879879879879879879879879879879879'); @@ -96,7 +96,7 @@ describe('Miscelaneous stuff', function() { // base58 it('should initialze the base58 object', function() { - should.exist(bitcore.base58); + should.exist(bitcore.Base58); }); it('should obtain the same string in base58 roundtrip', function() { var m = 'mqqa8xSMVDyf9QxihGnPtap6Mh6qemUkcu'; diff --git a/util/EncodedData.js b/util/EncodedData.js index 2736fc174..18bf3ad54 100644 --- a/util/EncodedData.js +++ b/util/EncodedData.js @@ -1,5 +1,5 @@ var imports = require('soop').imports(); -var base58 = imports.base58 || require('base58-native').base58Check; +var base58 = imports.base58 || require('../lib/Base58').base58Check; // Constructor. Takes the following forms: diff --git a/util/VersionedData.js b/util/VersionedData.js index ac7555919..3ed357d61 100644 --- a/util/VersionedData.js +++ b/util/VersionedData.js @@ -1,5 +1,5 @@ var imports = require('soop').imports(); -var base58 = imports.base58 || require('base58-native').base58Check; +var base58 = imports.base58 || require('../lib/Base58').base58Check; var parent = imports.parent || require('./EncodedData'); diff --git a/util/util.js b/util/util.js index a59df4b35..ab5220920 100644 --- a/util/util.js +++ b/util/util.js @@ -1,5 +1,5 @@ var crypto = require('crypto'); -var bignum = require('bignum'); +var bignum = require('../lib/Bignum'); var Binary = require('binary'); var Put = require('bufferput'); var buffertools = require('buffertools'); From fff988da94fb29ef037220e91f4f724d0ddaa031 Mon Sep 17 00:00:00 2001 From: "Ryan X. Charles" Date: Mon, 28 Apr 2014 18:28:32 -0400 Subject: [PATCH 2/2] add deprecated bitcore.bignum and bitcore.base58 (the non-deprecated versions are bitcore.Bignum and bitcore.Base58) --- bitcore.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/bitcore.js b/bitcore.js index 061579fbe..4a6af689a 100644 --- a/bitcore.js +++ b/bitcore.js @@ -11,19 +11,15 @@ var requireWhenAccessed = function(name, file) { }; requireWhenAccessed('Bignum', './lib/Bignum'); -/* Object.defineProperty(module.exports, 'bignum', {get: function() { console.log('bignum (with a lower-case "b") is deprecated. Use bitcore.Bignum (capital "B") instead.'); return require('./lib/Bignum'); }}); -*/ requireWhenAccessed('Base58', './lib/Base58'); -/* Object.defineProperty(module.exports, 'base58', {get: function() { console.log('base58 (with a lower-case "b") is deprecated. Use bitcore.Base58 (capital "B") instead.'); return require('./lib/Base58'); }}); -*/ requireWhenAccessed('bufferput', 'bufferput'); requireWhenAccessed('buffertools', 'buffertools'); requireWhenAccessed('Buffers.monkey', './patches/Buffers.monkey');