// BigInteger monkey patching BigInteger.valueOf = nbv; /** * Returns a byte array representation of the big integer. * * This returns the absolute of the contained value in big endian * form. A value of zero results in an empty array. */ BigInteger.prototype.toByteArrayUnsigned = function () { var ba = this.abs().toByteArray(); if (ba.length) { if (ba[0] == 0) { ba = ba.slice(1); } return ba.map(function (v) { return (v < 0) ? v + 256 : v; }); } else { // Empty array, nothing to do return ba; } }; /** * Turns a byte array into a big integer. * * This function will interpret a byte array as a big integer in big * endian notation and ignore leading zeros. */ BigInteger.fromByteArrayUnsigned = function (ba) { if (!ba.length) { return ba.valueOf(0); } else if (ba[0] & 0x80) { // Prepend a zero so the BigInteger class doesn't mistake this // for a negative integer. return new BigInteger([0].concat(ba)); } else { return new BigInteger(ba); } }; /** * Converts big integer to signed byte representation. * * The format for this value uses a the most significant bit as a sign * bit. If the most significant bit is already occupied by the * absolute value, an extra byte is prepended and the sign bit is set * there. * * Examples: * * 0 => 0x00 * 1 => 0x01 * -1 => 0x81 * 127 => 0x7f * -127 => 0xff * 128 => 0x0080 * -128 => 0x8080 * 255 => 0x00ff * -255 => 0x80ff * 16300 => 0x3fac * -16300 => 0xbfac * 62300 => 0x00f35c * -62300 => 0x80f35c */ BigInteger.prototype.toByteArraySigned = function () { var val = this.abs().toByteArrayUnsigned(); var neg = this.compareTo(BigInteger.ZERO) < 0; if (neg) { if (val[0] & 0x80) { val.unshift(0x80); } else { val[0] |= 0x80; } } else { if (val[0] & 0x80) { val.unshift(0x00); } } return val; }; /** * Parse a signed big integer byte representation. * * For details on the format please see BigInteger.toByteArraySigned. */ BigInteger.fromByteArraySigned = function (ba) { // Check for negative value if (ba[0] & 0x80) { // Remove sign bit ba[0] &= 0x7f; return BigInteger.fromByteArrayUnsigned(ba).negate(); } else { return BigInteger.fromByteArrayUnsigned(ba); } }; // Console ignore var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"]; if ("undefined" == typeof window.console) window.console = {}; for (var i = 0; i < names.length; ++i) if ("undefined" == typeof window.console[names[i]]) window.console[names[i]] = function() {}; // Bitcoin utility functions Bitcoin.Util = { /** * Cross-browser compatibility version of Array.isArray. */ isArray: Array.isArray || function(o) { return Object.prototype.toString.call(o) === '[object Array]'; }, /** * Create an array of a certain length filled with a specific value. */ makeFilledArray: function (len, val) { var array = []; var i = 0; while (i < len) { array[i++] = val; } return array; }, /** * Turn an integer into a "var_int". * * "var_int" is a variable length integer used by Bitcoin's binary format. * * Returns a byte array. */ numToVarInt: function (i) { if (i < 0xfd) { // unsigned char return [i]; } else if (i < 0x10000) { // unsigned short (LE) return [0xfd, i & 255 , i >>> 8]; } else if (i < 0x100000000) { // unsigned int (LE) return [0xfe].concat(Crypto.util.wordsToBytes([i]).reverse()); } else { throw 'quadword not implemented' // unsigned long long (LE) //return [0xff].concat(Crypto.util.wordsToBytes([i >>> 32, i])); } }, /** * Parse a Bitcoin value byte array, returning a BigInteger. */ valueToBigInt: function (valueBuffer) { if (valueBuffer instanceof BigInteger) return valueBuffer; // Prepend zero byte to prevent interpretation as negative integer return BigInteger.fromByteArrayUnsigned(valueBuffer); }, /** * Format a Bitcoin value as a string. * * Takes a BigInteger or byte-array and returns that amount of Bitcoins in a * nice standard formatting. * * Examples: * 12.3555 * 0.1234 * 900.99998888 * 34.00 */ formatValue: function (valueBuffer) { var value = this.valueToBigInt(valueBuffer).toString(); var integerPart = value.length > 8 ? value.substr(0, value.length-8) : '0'; var decimalPart = value.length > 8 ? value.substr(value.length-8) : value; while (decimalPart.length < 8) decimalPart = "0"+decimalPart; decimalPart = decimalPart.replace(/0*$/, ''); while (decimalPart.length < 2) decimalPart += "0"; return integerPart+"."+decimalPart; }, /** * Parse a floating point string as a Bitcoin value. * * Keep in mind that parsing user input is messy. You should always display * the parsed value back to the user to make sure we understood his input * correctly. */ parseValue: function (valueString) { // TODO: Detect other number formats (e.g. comma as decimal separator) var valueComp = valueString.split('.'); var integralPart = valueComp[0]; var fractionalPart = valueComp[1] || "0"; while (fractionalPart.length < 8) fractionalPart += "0"; fractionalPart = fractionalPart.replace(/^0+/g, ''); var value = BigInteger.valueOf(parseInt(integralPart)); value = value.multiply(BigInteger.valueOf(100000000)); value = value.add(BigInteger.valueOf(parseInt(fractionalPart))); return value; }, /** * Calculate RIPEMD160(SHA256(data)). * * Takes an arbitrary byte array as inputs and returns the hash as a byte * array. */ sha256ripe160: function (data) { return Crypto.RIPEMD160(Crypto.SHA256(data, {asBytes: true}), {asBytes: true}); } }; for (var i in Crypto.util) { if (Crypto.util.hasOwnProperty(i)) { Bitcoin.Util[i] = Crypto.util[i]; } }