6603 lines
184 KiB
JavaScript
6603 lines
184 KiB
JavaScript
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.ethers = f()}})(function(){var define,module,exports;return (function(){function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s}return e})()({1:[function(require,module,exports){
|
|
'use strict';
|
|
|
|
var Interface = require('./interface.js');
|
|
|
|
var utils = (function() {
|
|
return {
|
|
defineProperty: require('../utils/properties.js').defineProperty,
|
|
|
|
getAddress: require('../utils/address.js').getAddress,
|
|
|
|
bigNumberify: require('../utils/bignumber.js').bigNumberify,
|
|
|
|
hexlify: require('../utils/convert.js').hexlify,
|
|
};
|
|
})();
|
|
|
|
var errors = require('../utils/errors');
|
|
|
|
var allowedTransactionKeys = {
|
|
data: true, from: true, gasLimit: true, gasPrice:true, nonce: true, to: true, value: true
|
|
}
|
|
|
|
function copyObject(object) {
|
|
var result = {};
|
|
for (var key in object) {
|
|
result[key] = object[key];
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
function Contract(addressOrName, contractInterface, signerOrProvider) {
|
|
if (!(this instanceof Contract)) { throw new Error('missing new'); }
|
|
|
|
// @TODO: Maybe still check the addressOrName looks like a valid address or name?
|
|
//address = utils.getAddress(address);
|
|
|
|
if (!(contractInterface instanceof Interface)) {
|
|
contractInterface = new Interface(contractInterface);
|
|
}
|
|
|
|
if (!signerOrProvider) { throw new Error('missing signer or provider'); }
|
|
|
|
var signer = signerOrProvider;
|
|
var provider = null;
|
|
|
|
if (signerOrProvider.provider) {
|
|
provider = signerOrProvider.provider;
|
|
} else {
|
|
provider = signerOrProvider;
|
|
signer = null;
|
|
}
|
|
|
|
utils.defineProperty(this, 'address', addressOrName);
|
|
utils.defineProperty(this, 'interface', contractInterface);
|
|
utils.defineProperty(this, 'signer', signer);
|
|
utils.defineProperty(this, 'provider', provider);
|
|
|
|
var addressPromise = provider.resolveName(addressOrName);
|
|
|
|
function runMethod(method, estimateOnly) {
|
|
return function() {
|
|
var transaction = {}
|
|
|
|
var params = Array.prototype.slice.call(arguments);
|
|
|
|
// If 1 extra parameter was passed in, it contains overrides
|
|
if (params.length === method.inputs.types.length + 1 && typeof(params[params.length - 1]) === 'object') {
|
|
transaction = copyObject(params.pop());
|
|
|
|
// Check for unexpected keys (e.g. using "gas" instead of "gasLimit")
|
|
for (var key in transaction) {
|
|
if (!allowedTransactionKeys[key]) {
|
|
throw new Error('unknown transaction override ' + key);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check overrides make sense
|
|
['data', 'to'].forEach(function(key) {
|
|
if (transaction[key] != null) {
|
|
throw new Error('cannot override ' + key) ;
|
|
}
|
|
});
|
|
|
|
var call = method.apply(contractInterface, params);
|
|
|
|
// Send to the contract address
|
|
transaction.to = addressOrName;
|
|
|
|
// Set the transaction data
|
|
transaction.data = call.data;
|
|
|
|
switch (call.type) {
|
|
case 'call':
|
|
|
|
// Call (constant functions) always cost 0 ether
|
|
if (estimateOnly) {
|
|
return Promise.resolve(new utils.bigNumberify(0));
|
|
}
|
|
|
|
// Check overrides make sense
|
|
['gasLimit', 'gasPrice', 'value'].forEach(function(key) {
|
|
if (transaction[key] != null) {
|
|
throw new Error('call cannot override ' + key) ;
|
|
}
|
|
});
|
|
|
|
var fromPromise = null;
|
|
if (transaction.from == null && signer && signer.getAddress) {
|
|
fromPromise = signer.getAddress();
|
|
if (!(fromPromise instanceof Promise)) {
|
|
fromPromise = Promise.resolve(fromPromise);
|
|
}
|
|
} else {
|
|
fromPromise = Promise.resolve(null);
|
|
}
|
|
|
|
return fromPromise.then(function(address) {
|
|
if (address) {
|
|
transaction.from = utils.getAddress(address);
|
|
}
|
|
return provider.call(transaction);
|
|
|
|
}).then(function(value) {
|
|
try {
|
|
var result = call.parse(value);
|
|
} catch (error) {
|
|
if (value === '0x' && method.outputs.types.length > 0) {
|
|
errors.throwError('call exception', errors.CALL_EXCEPTION, {
|
|
address: addressOrName,
|
|
method: call.signature,
|
|
value: params
|
|
});
|
|
}
|
|
throw error;
|
|
}
|
|
if (method.outputs.types.length === 1) {
|
|
result = result[0];
|
|
}
|
|
return result;
|
|
});
|
|
|
|
case 'transaction':
|
|
if (!signer) { return Promise.reject(new Error('missing signer')); }
|
|
|
|
// Make sure they aren't overriding something they shouldn't
|
|
if (transaction.from != null) {
|
|
throw new Error('transaction cannot override from') ;
|
|
}
|
|
|
|
// Only computing the transaction estimate
|
|
if (estimateOnly) {
|
|
if (signer && signer.estimateGas) {
|
|
return signer.estimateGas(transaction);
|
|
}
|
|
|
|
return provider.estimateGas(transaction)
|
|
}
|
|
|
|
// If the signer supports sendTrasaction, use it
|
|
if (signer.sendTransaction) {
|
|
return signer.sendTransaction(transaction);
|
|
}
|
|
|
|
if (!signer.sign) {
|
|
return Promise.reject(new Error('custom signer does not support signing'));
|
|
}
|
|
|
|
if (transaction.gasLimit == null) {
|
|
transaction.gasLimit = signer.defaultGasLimit || 2000000;
|
|
}
|
|
|
|
var noncePromise = null;
|
|
if (transaction.nonce) {
|
|
noncePromise = Promise.resolve(transaction.nonce)
|
|
} else if (signer.getTransactionCount) {
|
|
noncePromise = signer.getTransactionCount();
|
|
if (!(noncePromise instanceof Promise)) {
|
|
noncePromise = Promise.resolve(noncePromise);
|
|
}
|
|
} else {
|
|
var addressPromise = signer.getAddress();
|
|
if (!(addressPromise instanceof Promise)) {
|
|
addressPromise = Promise.resolve(addressPromise);
|
|
}
|
|
noncePromise = addressPromise.then(function(address) {
|
|
return provider.getTransactionCount(address, 'pending');
|
|
});
|
|
}
|
|
|
|
var gasPricePromise = null;
|
|
if (transaction.gasPrice) {
|
|
gasPricePromise = Promise.resolve(transaction.gasPrice);
|
|
} else {
|
|
gasPricePromise = provider.getGasPrice();
|
|
}
|
|
|
|
return Promise.all([
|
|
noncePromise,
|
|
gasPricePromise
|
|
|
|
]).then(function(results) {
|
|
transaction.nonce = results[0];
|
|
transaction.gasPrice = results[1];
|
|
return signer.sign(transaction);
|
|
|
|
}).then(function(signedTransaction) {
|
|
return provider.sendTransaction(signedTransaction);
|
|
});
|
|
}
|
|
};
|
|
}
|
|
|
|
var estimate = {};
|
|
utils.defineProperty(this, 'estimate', estimate);
|
|
|
|
var functions = {};
|
|
utils.defineProperty(this, 'functions', functions);
|
|
|
|
var events = {};
|
|
utils.defineProperty(this, 'events', events);
|
|
|
|
Object.keys(contractInterface.functions).forEach(function(methodName) {
|
|
var method = contractInterface.functions[methodName];
|
|
|
|
var run = runMethod(method, false);
|
|
|
|
if (this[methodName] == null) {
|
|
utils.defineProperty(this, methodName, run);
|
|
} else {
|
|
console.log('WARNING: Multiple definitions for ' + method);
|
|
}
|
|
|
|
if (functions[method] == null) {
|
|
utils.defineProperty(functions, methodName, run);
|
|
utils.defineProperty(estimate, methodName, runMethod(method, true));
|
|
}
|
|
}, this);
|
|
|
|
Object.keys(contractInterface.events).forEach(function(eventName) {
|
|
var eventInfo = contractInterface.events[eventName];
|
|
|
|
var eventCallback = null;
|
|
|
|
function handleEvent(log) {
|
|
addressPromise.then(function(address) {
|
|
|
|
// Not meant for us (the topics just has the same name)
|
|
if (address != log.address) { return; }
|
|
|
|
try {
|
|
var result = eventInfo.parse(log.topics, log.data);
|
|
|
|
// Some useful things to have with the log
|
|
log.args = result;
|
|
log.event = eventName;
|
|
log.parse = eventInfo.parse;
|
|
log.removeListener = function() {
|
|
provider.removeListener(eventInfo.topics, handleEvent);
|
|
}
|
|
|
|
log.getBlock = function() { return provider.getBlock(log.blockHash);; }
|
|
log.getTransaction = function() { return provider.getTransaction(log.transactionHash); }
|
|
log.getTransactionReceipt = function() { return provider.getTransactionReceipt(log.transactionHash); }
|
|
log.eventSignature = eventInfo.signature;
|
|
|
|
eventCallback.apply(log, Array.prototype.slice.call(result));
|
|
} catch (error) {
|
|
console.log(error);
|
|
}
|
|
});
|
|
}
|
|
|
|
var property = {
|
|
enumerable: true,
|
|
get: function() {
|
|
return eventCallback;
|
|
},
|
|
set: function(value) {
|
|
if (!value) { value = null; }
|
|
|
|
if (!value && eventCallback) {
|
|
provider.removeListener(eventInfo.topics, handleEvent);
|
|
|
|
} else if (value && !eventCallback) {
|
|
provider.on(eventInfo.topics, handleEvent);
|
|
}
|
|
|
|
eventCallback = value;
|
|
}
|
|
};
|
|
|
|
var propertyName = 'on' + eventName.toLowerCase();
|
|
if (this[propertyName] == null) {
|
|
Object.defineProperty(this, propertyName, property);
|
|
}
|
|
|
|
Object.defineProperty(events, eventName, property);
|
|
|
|
}, this);
|
|
}
|
|
|
|
utils.defineProperty(Contract.prototype, 'connect', function(signerOrProvider) {
|
|
return new Contract(this.address, this.interface, signerOrProvider);
|
|
});
|
|
|
|
utils.defineProperty(Contract, 'getDeployTransaction', function(bytecode, contractInterface) {
|
|
|
|
if (!(contractInterface instanceof Interface)) {
|
|
contractInterface = new Interface(contractInterface);
|
|
}
|
|
|
|
var args = Array.prototype.slice.call(arguments);
|
|
args.splice(1, 1);
|
|
|
|
return {
|
|
data: contractInterface.deployFunction.apply(contractInterface, args).bytecode
|
|
}
|
|
});
|
|
|
|
module.exports = Contract;
|
|
|
|
},{"../utils/address.js":9,"../utils/bignumber.js":10,"../utils/convert.js":11,"../utils/errors":12,"../utils/properties.js":14,"./interface.js":3}],2:[function(require,module,exports){
|
|
'use strict';
|
|
|
|
var Contract = require('./contract.js');
|
|
var Interface = require('./interface.js');
|
|
|
|
module.exports = {
|
|
Contract: Contract,
|
|
Interface: Interface,
|
|
}
|
|
|
|
|
|
},{"./contract.js":1,"./interface.js":3}],3:[function(require,module,exports){
|
|
'use strict';
|
|
|
|
// See: https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI
|
|
|
|
var utils = (function() {
|
|
var AbiCoder = require('../utils/abi-coder');
|
|
var convert = require('../utils/convert');
|
|
var properties = require('../utils/properties');
|
|
var utf8 = require('../utils/utf8');
|
|
|
|
return {
|
|
defineFrozen: properties.defineFrozen,
|
|
defineProperty: properties.defineProperty,
|
|
|
|
coder: AbiCoder.defaultCoder,
|
|
parseSignature: AbiCoder.parseSignature,
|
|
|
|
arrayify: convert.arrayify,
|
|
concat: convert.concat,
|
|
isHexString: convert.isHexString,
|
|
|
|
toUtf8Bytes: utf8.toUtf8Bytes,
|
|
|
|
keccak256: require('../utils/keccak256'),
|
|
};
|
|
})();
|
|
|
|
var errors = require('../utils/errors');
|
|
|
|
function parseParams(params) {
|
|
var names = [];
|
|
var types = [];
|
|
|
|
params.forEach(function(param) {
|
|
if (param.components != null) {
|
|
if (param.type.substring(0, 5) !== 'tuple') {
|
|
throw new Error('internal error; report on GitHub');
|
|
}
|
|
var suffix = '';
|
|
var arrayBracket = param.type.indexOf('[');
|
|
if (arrayBracket >= 0) { suffix = param.type.substring(arrayBracket); }
|
|
|
|
var result = parseParams(param.components);
|
|
names.push({ name: (param.name || null), names: result.names });
|
|
types.push('tuple(' + result.types.join(',') + ')' + suffix)
|
|
} else {
|
|
names.push(param.name || null);
|
|
types.push(param.type);
|
|
}
|
|
});
|
|
|
|
return {
|
|
names: names,
|
|
types: types
|
|
}
|
|
}
|
|
|
|
function populateDescription(object, items) {
|
|
for (var key in items) {
|
|
utils.defineProperty(object, key, items[key]);
|
|
}
|
|
return object;
|
|
}
|
|
|
|
/**
|
|
* - bytecode (optional; only for deploy)
|
|
* - type ("deploy")
|
|
*/
|
|
function DeployDescription() { }
|
|
|
|
/**
|
|
* - name
|
|
* - signature
|
|
* - sighash
|
|
* -
|
|
* -
|
|
* -
|
|
* -
|
|
* - type: ("call" | "transaction")
|
|
*/
|
|
function FunctionDescription() { }
|
|
|
|
/**
|
|
* - anonymous
|
|
* - name
|
|
* - signature
|
|
* - parse
|
|
* - topics
|
|
* - inputs
|
|
* - type ("event")
|
|
*/
|
|
function EventDescription() { }
|
|
|
|
function Indexed(value) {
|
|
utils.defineProperty(this, 'indexed', true);
|
|
utils.defineProperty(this, 'hash', value);
|
|
}
|
|
|
|
function Result() {}
|
|
|
|
function Interface(abi) {
|
|
if (!(this instanceof Interface)) { throw new Error('missing new'); }
|
|
|
|
if (typeof(abi) === 'string') {
|
|
try {
|
|
abi = JSON.parse(abi);
|
|
} catch (error) {
|
|
errors.throwError('could not parse ABI JSON', errors.INVALID_ARGUMENT, {
|
|
arg: 'abi',
|
|
errorMessage: error.message,
|
|
value: abi
|
|
});
|
|
}
|
|
}
|
|
|
|
var _abi = [];
|
|
abi.forEach(function(fragment) {
|
|
if (typeof(fragment) === 'string') {
|
|
fragment = utils.parseSignature(fragment);
|
|
}
|
|
_abi.push(fragment);
|
|
});
|
|
|
|
utils.defineFrozen(this, 'abi', _abi);
|
|
|
|
var methods = {}, events = {}, deploy = null;
|
|
|
|
utils.defineProperty(this, 'functions', methods);
|
|
utils.defineProperty(this, 'events', events);
|
|
|
|
function addMethod(method) {
|
|
switch (method.type) {
|
|
case 'constructor':
|
|
var func = (function() {
|
|
var inputParams = parseParams(method.inputs);
|
|
|
|
var func = function(bytecode) {
|
|
if (!utils.isHexString(bytecode)) {
|
|
errors.throwError('invalid contract bytecode', errors.INVALID_ARGUMENT, {
|
|
arg: 'bytecode',
|
|
type: typeof(bytecode),
|
|
value: bytecode
|
|
});
|
|
}
|
|
|
|
var params = Array.prototype.slice.call(arguments, 1);
|
|
if (params.length < inputParams.types.length) {
|
|
errors.throwError('missing constructor argument', errors.MISSING_ARGUMENT, {
|
|
arg: (inputParams.names[params.length] || 'unknown'),
|
|
count: params.length,
|
|
expectedCount: inputParams.types.length
|
|
});
|
|
} else if (params.length > inputParams.types.length) {
|
|
errors.throwError('too many constructor arguments', errors.UNEXPECTED_ARGUMENT, {
|
|
count: params.length,
|
|
expectedCount: inputParams.types.length
|
|
});
|
|
}
|
|
|
|
try {
|
|
var encodedParams = utils.coder.encode(method.inputs, params)
|
|
} catch (error) {
|
|
errors.throwError('invalid constructor argument', errors.INVALID_ARGUMENT, {
|
|
arg: error.arg,
|
|
reason: error.reason,
|
|
value: error.value
|
|
});
|
|
}
|
|
|
|
var result = {
|
|
bytecode: bytecode + encodedParams.substring(2),
|
|
type: 'deploy'
|
|
}
|
|
|
|
return populateDescription(new DeployDescription(), result);
|
|
}
|
|
|
|
utils.defineFrozen(func, 'inputs', inputParams);
|
|
utils.defineProperty(func, 'payable', (method.payable == null || !!method.payable))
|
|
|
|
return func;
|
|
})();
|
|
|
|
if (!deploy) { deploy = func; }
|
|
|
|
break;
|
|
|
|
case 'function':
|
|
var func = (function() {
|
|
var inputParams = parseParams(method.inputs);
|
|
var outputParams = parseParams(method.outputs);
|
|
|
|
var signature = '(' + inputParams.types.join(',') + ')';
|
|
signature = signature.replace(/tuple/g, '');
|
|
signature = method.name + signature;
|
|
|
|
var parse = function(data) {
|
|
try {
|
|
return utils.coder.decode(method.outputs, utils.arrayify(data));
|
|
} catch(error) {
|
|
errors.throwError('invalid data for function output', errors.INVALID_ARGUMENT, {
|
|
arg: 'data',
|
|
errorArg: error.arg,
|
|
errorValue: error.value,
|
|
value: data,
|
|
reason: error.reason
|
|
});
|
|
}
|
|
};
|
|
|
|
var sighash = utils.keccak256(utils.toUtf8Bytes(signature)).substring(0, 10);
|
|
var func = function() {
|
|
var result = {
|
|
name: method.name,
|
|
signature: signature,
|
|
sighash: sighash,
|
|
type: ((method.constant) ? 'call': 'transaction')
|
|
};
|
|
|
|
var params = Array.prototype.slice.call(arguments, 0);
|
|
|
|
if (params.length < inputParams.types.length) {
|
|
errors.throwError('missing input argument', errors.MISSING_ARGUMENT, {
|
|
arg: (inputParams.names[params.length] || 'unknown'),
|
|
count: params.length,
|
|
expectedCount: inputParams.types.length,
|
|
name: method.name
|
|
});
|
|
} else if (params.length > inputParams.types.length) {
|
|
errors.throwError('too many input arguments', errors.UNEXPECTED_ARGUMENT, {
|
|
count: params.length,
|
|
expectedCount: inputParams.types.length
|
|
});
|
|
}
|
|
|
|
try {
|
|
var encodedParams = utils.coder.encode(method.inputs, params);
|
|
} catch (error) {
|
|
errors.throwError('invalid input argument', errors.INVALID_ARGUMENT, {
|
|
arg: error.arg,
|
|
reason: error.reason,
|
|
value: error.value
|
|
});
|
|
}
|
|
|
|
result.data = sighash + encodedParams.substring(2);
|
|
result.parse = parse;
|
|
|
|
return populateDescription(new FunctionDescription(), result);
|
|
}
|
|
|
|
utils.defineFrozen(func, 'inputs', inputParams);
|
|
utils.defineFrozen(func, 'outputs', outputParams);
|
|
|
|
utils.defineProperty(func, 'payable', (method.payable == null || !!method.payable))
|
|
|
|
utils.defineProperty(func, 'parseResult', parse);
|
|
|
|
utils.defineProperty(func, 'signature', signature);
|
|
utils.defineProperty(func, 'sighash', sighash);
|
|
|
|
return func;
|
|
})();
|
|
|
|
// Expose the first (and hopefully unique named function
|
|
if (method.name && methods[method.name] == null) {
|
|
utils.defineProperty(methods, method.name, func);
|
|
}
|
|
|
|
// Expose all methods by their signature, for overloaded functions
|
|
if (methods[func.signature] == null) {
|
|
utils.defineProperty(methods, func.signature, func);
|
|
}
|
|
|
|
break;
|
|
|
|
case 'event':
|
|
var func = (function() {
|
|
var inputParams = parseParams(method.inputs);
|
|
|
|
var signature = '(' + inputParams.types.join(',') + ')';
|
|
signature = signature.replace(/tuple/g, '');
|
|
signature = method.name + signature;
|
|
|
|
var result = {
|
|
anonymous: (!!method.anonymous),
|
|
name: method.name,
|
|
signature: signature,
|
|
type: 'event'
|
|
};
|
|
|
|
result.parse = function(topics, data) {
|
|
if (data == null) {
|
|
data = topics;
|
|
topics = null;
|
|
}
|
|
|
|
// Strip the signature off of non-anonymous topics
|
|
if (topics != null && !method.anonymous) { topics = topics.slice(1); }
|
|
|
|
var inputIndexed = [], inputNonIndexed = [];
|
|
var inputDynamic = [];
|
|
method.inputs.forEach(function(param, index) {
|
|
|
|
if (param.indexed) {
|
|
if (param.type === 'string' || param.type === 'bytes' || param.type.indexOf('[') >= 0 || param.type.substring(0, 5) === 'tuple') {
|
|
inputIndexed.push({ type: 'bytes32', name: (param.name || '')});
|
|
inputDynamic.push(true);
|
|
} else {
|
|
inputIndexed.push(param);
|
|
inputDynamic.push(false);
|
|
}
|
|
} else {
|
|
inputNonIndexed.push(param);
|
|
inputDynamic.push(false);
|
|
}
|
|
});
|
|
|
|
if (topics != null) {
|
|
var resultIndexed = utils.coder.decode(
|
|
inputIndexed,
|
|
utils.concat(topics)
|
|
);
|
|
}
|
|
|
|
var resultNonIndexed = utils.coder.decode(
|
|
inputNonIndexed,
|
|
utils.arrayify(data)
|
|
);
|
|
|
|
var result = new Result();
|
|
var nonIndexedIndex = 0, indexedIndex = 0;
|
|
method.inputs.forEach(function(input, index) {
|
|
if (input.indexed) {
|
|
if (topics == null) {
|
|
result[index] = new Indexed(null);
|
|
|
|
} else if (inputDynamic[index]) {
|
|
result[index] = new Indexed(resultIndexed[indexedIndex++]);
|
|
} else {
|
|
result[index] = resultIndexed[indexedIndex++];
|
|
}
|
|
} else {
|
|
result[index] = resultNonIndexed[nonIndexedIndex++];
|
|
}
|
|
if (input.name) { result[input.name] = result[index]; }
|
|
});
|
|
|
|
result.length = method.inputs.length;
|
|
|
|
return result;
|
|
};
|
|
|
|
var func = populateDescription(new EventDescription(), result)
|
|
utils.defineFrozen(func, 'topics', [ utils.keccak256(utils.toUtf8Bytes(signature)) ]);
|
|
utils.defineFrozen(func, 'inputs', inputParams);
|
|
return func;
|
|
})();
|
|
|
|
// Expose the first (and hopefully unique) event name
|
|
if (method.name && events[method.name] == null) {
|
|
utils.defineProperty(events, method.name, func);
|
|
}
|
|
|
|
// Expose all events by their signature, for overloaded functions
|
|
if (methods[func.signature] == null) {
|
|
utils.defineProperty(methods, func.signature, func);
|
|
}
|
|
|
|
break;
|
|
|
|
case 'fallback':
|
|
// Nothing to do for fallback
|
|
break;
|
|
|
|
default:
|
|
console.log('WARNING: unsupported ABI type - ' + method.type);
|
|
break;
|
|
}
|
|
};
|
|
|
|
_abi.forEach(addMethod, this);
|
|
|
|
// If there wasn't a constructor, create the default constructor
|
|
if (!deploy) {
|
|
addMethod({type: 'constructor', inputs: []});
|
|
}
|
|
|
|
utils.defineProperty(this, 'deployFunction', deploy);
|
|
}
|
|
|
|
utils.defineProperty(Interface.prototype, 'parseTransaction', function(tx) {
|
|
var sighash = tx.data.substring(0, 10).toLowerCase();
|
|
for (var name in this.functions) {
|
|
if (name.indexOf('(') === -1) { continue; }
|
|
var func = this.functions[name];
|
|
if (func.sighash === sighash) {
|
|
var result = utils.coder.decode(func.inputs.types, '0x' + tx.data.substring(10));
|
|
return {
|
|
args: result,
|
|
signature: func.signature,
|
|
sighash: func.sighash,
|
|
parse: func.parseResult,
|
|
value: tx.value,
|
|
};
|
|
}
|
|
}
|
|
return null;
|
|
});
|
|
|
|
module.exports = Interface;
|
|
|
|
},{"../utils/abi-coder":8,"../utils/convert":11,"../utils/errors":12,"../utils/keccak256":13,"../utils/properties":14,"../utils/utf8":16}],4:[function(require,module,exports){
|
|
(function (module, exports) {
|
|
'use strict';
|
|
|
|
// Utils
|
|
function assert (val, msg) {
|
|
if (!val) throw new Error(msg || 'Assertion failed');
|
|
}
|
|
|
|
// Could use `inherits` module, but don't want to move from single file
|
|
// architecture yet.
|
|
function inherits (ctor, superCtor) {
|
|
ctor.super_ = superCtor;
|
|
var TempCtor = function () {};
|
|
TempCtor.prototype = superCtor.prototype;
|
|
ctor.prototype = new TempCtor();
|
|
ctor.prototype.constructor = ctor;
|
|
}
|
|
|
|
// BN
|
|
|
|
function BN (number, base, endian) {
|
|
if (BN.isBN(number)) {
|
|
return number;
|
|
}
|
|
|
|
this.negative = 0;
|
|
this.words = null;
|
|
this.length = 0;
|
|
|
|
// Reduction context
|
|
this.red = null;
|
|
|
|
if (number !== null) {
|
|
if (base === 'le' || base === 'be') {
|
|
endian = base;
|
|
base = 10;
|
|
}
|
|
|
|
this._init(number || 0, base || 10, endian || 'be');
|
|
}
|
|
}
|
|
if (typeof module === 'object') {
|
|
module.exports = BN;
|
|
} else {
|
|
exports.BN = BN;
|
|
}
|
|
|
|
BN.BN = BN;
|
|
BN.wordSize = 26;
|
|
|
|
var Buffer;
|
|
try {
|
|
Buffer = require('buffer').Buffer;
|
|
} catch (e) {
|
|
}
|
|
|
|
BN.isBN = function isBN (num) {
|
|
if (num instanceof BN) {
|
|
return true;
|
|
}
|
|
|
|
return num !== null && typeof num === 'object' &&
|
|
num.constructor.wordSize === BN.wordSize && Array.isArray(num.words);
|
|
};
|
|
|
|
BN.max = function max (left, right) {
|
|
if (left.cmp(right) > 0) return left;
|
|
return right;
|
|
};
|
|
|
|
BN.min = function min (left, right) {
|
|
if (left.cmp(right) < 0) return left;
|
|
return right;
|
|
};
|
|
|
|
BN.prototype._init = function init (number, base, endian) {
|
|
if (typeof number === 'number') {
|
|
return this._initNumber(number, base, endian);
|
|
}
|
|
|
|
if (typeof number === 'object') {
|
|
return this._initArray(number, base, endian);
|
|
}
|
|
|
|
if (base === 'hex') {
|
|
base = 16;
|
|
}
|
|
assert(base === (base | 0) && base >= 2 && base <= 36);
|
|
|
|
number = number.toString().replace(/\s+/g, '');
|
|
var start = 0;
|
|
if (number[0] === '-') {
|
|
start++;
|
|
}
|
|
|
|
if (base === 16) {
|
|
this._parseHex(number, start);
|
|
} else {
|
|
this._parseBase(number, base, start);
|
|
}
|
|
|
|
if (number[0] === '-') {
|
|
this.negative = 1;
|
|
}
|
|
|
|
this.strip();
|
|
|
|
if (endian !== 'le') return;
|
|
|
|
this._initArray(this.toArray(), base, endian);
|
|
};
|
|
|
|
BN.prototype._initNumber = function _initNumber (number, base, endian) {
|
|
if (number < 0) {
|
|
this.negative = 1;
|
|
number = -number;
|
|
}
|
|
if (number < 0x4000000) {
|
|
this.words = [ number & 0x3ffffff ];
|
|
this.length = 1;
|
|
} else if (number < 0x10000000000000) {
|
|
this.words = [
|
|
number & 0x3ffffff,
|
|
(number / 0x4000000) & 0x3ffffff
|
|
];
|
|
this.length = 2;
|
|
} else {
|
|
assert(number < 0x20000000000000); // 2 ^ 53 (unsafe)
|
|
this.words = [
|
|
number & 0x3ffffff,
|
|
(number / 0x4000000) & 0x3ffffff,
|
|
1
|
|
];
|
|
this.length = 3;
|
|
}
|
|
|
|
if (endian !== 'le') return;
|
|
|
|
// Reverse the bytes
|
|
this._initArray(this.toArray(), base, endian);
|
|
};
|
|
|
|
BN.prototype._initArray = function _initArray (number, base, endian) {
|
|
// Perhaps a Uint8Array
|
|
assert(typeof number.length === 'number');
|
|
if (number.length <= 0) {
|
|
this.words = [ 0 ];
|
|
this.length = 1;
|
|
return this;
|
|
}
|
|
|
|
this.length = Math.ceil(number.length / 3);
|
|
this.words = new Array(this.length);
|
|
for (var i = 0; i < this.length; i++) {
|
|
this.words[i] = 0;
|
|
}
|
|
|
|
var j, w;
|
|
var off = 0;
|
|
if (endian === 'be') {
|
|
for (i = number.length - 1, j = 0; i >= 0; i -= 3) {
|
|
w = number[i] | (number[i - 1] << 8) | (number[i - 2] << 16);
|
|
this.words[j] |= (w << off) & 0x3ffffff;
|
|
this.words[j + 1] = (w >>> (26 - off)) & 0x3ffffff;
|
|
off += 24;
|
|
if (off >= 26) {
|
|
off -= 26;
|
|
j++;
|
|
}
|
|
}
|
|
} else if (endian === 'le') {
|
|
for (i = 0, j = 0; i < number.length; i += 3) {
|
|
w = number[i] | (number[i + 1] << 8) | (number[i + 2] << 16);
|
|
this.words[j] |= (w << off) & 0x3ffffff;
|
|
this.words[j + 1] = (w >>> (26 - off)) & 0x3ffffff;
|
|
off += 24;
|
|
if (off >= 26) {
|
|
off -= 26;
|
|
j++;
|
|
}
|
|
}
|
|
}
|
|
return this.strip();
|
|
};
|
|
|
|
function parseHex (str, start, end) {
|
|
var r = 0;
|
|
var len = Math.min(str.length, end);
|
|
for (var i = start; i < len; i++) {
|
|
var c = str.charCodeAt(i) - 48;
|
|
|
|
r <<= 4;
|
|
|
|
// 'a' - 'f'
|
|
if (c >= 49 && c <= 54) {
|
|
r |= c - 49 + 0xa;
|
|
|
|
// 'A' - 'F'
|
|
} else if (c >= 17 && c <= 22) {
|
|
r |= c - 17 + 0xa;
|
|
|
|
// '0' - '9'
|
|
} else {
|
|
r |= c & 0xf;
|
|
}
|
|
}
|
|
return r;
|
|
}
|
|
|
|
BN.prototype._parseHex = function _parseHex (number, start) {
|
|
// Create possibly bigger array to ensure that it fits the number
|
|
this.length = Math.ceil((number.length - start) / 6);
|
|
this.words = new Array(this.length);
|
|
for (var i = 0; i < this.length; i++) {
|
|
this.words[i] = 0;
|
|
}
|
|
|
|
var j, w;
|
|
// Scan 24-bit chunks and add them to the number
|
|
var off = 0;
|
|
for (i = number.length - 6, j = 0; i >= start; i -= 6) {
|
|
w = parseHex(number, i, i + 6);
|
|
this.words[j] |= (w << off) & 0x3ffffff;
|
|
// NOTE: `0x3fffff` is intentional here, 26bits max shift + 24bit hex limb
|
|
this.words[j + 1] |= w >>> (26 - off) & 0x3fffff;
|
|
off += 24;
|
|
if (off >= 26) {
|
|
off -= 26;
|
|
j++;
|
|
}
|
|
}
|
|
if (i + 6 !== start) {
|
|
w = parseHex(number, start, i + 6);
|
|
this.words[j] |= (w << off) & 0x3ffffff;
|
|
this.words[j + 1] |= w >>> (26 - off) & 0x3fffff;
|
|
}
|
|
this.strip();
|
|
};
|
|
|
|
function parseBase (str, start, end, mul) {
|
|
var r = 0;
|
|
var len = Math.min(str.length, end);
|
|
for (var i = start; i < len; i++) {
|
|
var c = str.charCodeAt(i) - 48;
|
|
|
|
r *= mul;
|
|
|
|
// 'a'
|
|
if (c >= 49) {
|
|
r += c - 49 + 0xa;
|
|
|
|
// 'A'
|
|
} else if (c >= 17) {
|
|
r += c - 17 + 0xa;
|
|
|
|
// '0' - '9'
|
|
} else {
|
|
r += c;
|
|
}
|
|
}
|
|
return r;
|
|
}
|
|
|
|
BN.prototype._parseBase = function _parseBase (number, base, start) {
|
|
// Initialize as zero
|
|
this.words = [ 0 ];
|
|
this.length = 1;
|
|
|
|
// Find length of limb in base
|
|
for (var limbLen = 0, limbPow = 1; limbPow <= 0x3ffffff; limbPow *= base) {
|
|
limbLen++;
|
|
}
|
|
limbLen--;
|
|
limbPow = (limbPow / base) | 0;
|
|
|
|
var total = number.length - start;
|
|
var mod = total % limbLen;
|
|
var end = Math.min(total, total - mod) + start;
|
|
|
|
var word = 0;
|
|
for (var i = start; i < end; i += limbLen) {
|
|
word = parseBase(number, i, i + limbLen, base);
|
|
|
|
this.imuln(limbPow);
|
|
if (this.words[0] + word < 0x4000000) {
|
|
this.words[0] += word;
|
|
} else {
|
|
this._iaddn(word);
|
|
}
|
|
}
|
|
|
|
if (mod !== 0) {
|
|
var pow = 1;
|
|
word = parseBase(number, i, number.length, base);
|
|
|
|
for (i = 0; i < mod; i++) {
|
|
pow *= base;
|
|
}
|
|
|
|
this.imuln(pow);
|
|
if (this.words[0] + word < 0x4000000) {
|
|
this.words[0] += word;
|
|
} else {
|
|
this._iaddn(word);
|
|
}
|
|
}
|
|
};
|
|
|
|
BN.prototype.copy = function copy (dest) {
|
|
dest.words = new Array(this.length);
|
|
for (var i = 0; i < this.length; i++) {
|
|
dest.words[i] = this.words[i];
|
|
}
|
|
dest.length = this.length;
|
|
dest.negative = this.negative;
|
|
dest.red = this.red;
|
|
};
|
|
|
|
BN.prototype.clone = function clone () {
|
|
var r = new BN(null);
|
|
this.copy(r);
|
|
return r;
|
|
};
|
|
|
|
BN.prototype._expand = function _expand (size) {
|
|
while (this.length < size) {
|
|
this.words[this.length++] = 0;
|
|
}
|
|
return this;
|
|
};
|
|
|
|
// Remove leading `0` from `this`
|
|
BN.prototype.strip = function strip () {
|
|
while (this.length > 1 && this.words[this.length - 1] === 0) {
|
|
this.length--;
|
|
}
|
|
return this._normSign();
|
|
};
|
|
|
|
BN.prototype._normSign = function _normSign () {
|
|
// -0 = 0
|
|
if (this.length === 1 && this.words[0] === 0) {
|
|
this.negative = 0;
|
|
}
|
|
return this;
|
|
};
|
|
|
|
BN.prototype.inspect = function inspect () {
|
|
return (this.red ? '<BN-R: ' : '<BN: ') + this.toString(16) + '>';
|
|
};
|
|
|
|
/*
|
|
|
|
var zeros = [];
|
|
var groupSizes = [];
|
|
var groupBases = [];
|
|
|
|
var s = '';
|
|
var i = -1;
|
|
while (++i < BN.wordSize) {
|
|
zeros[i] = s;
|
|
s += '0';
|
|
}
|
|
groupSizes[0] = 0;
|
|
groupSizes[1] = 0;
|
|
groupBases[0] = 0;
|
|
groupBases[1] = 0;
|
|
var base = 2 - 1;
|
|
while (++base < 36 + 1) {
|
|
var groupSize = 0;
|
|
var groupBase = 1;
|
|
while (groupBase < (1 << BN.wordSize) / base) {
|
|
groupBase *= base;
|
|
groupSize += 1;
|
|
}
|
|
groupSizes[base] = groupSize;
|
|
groupBases[base] = groupBase;
|
|
}
|
|
|
|
*/
|
|
|
|
var zeros = [
|
|
'',
|
|
'0',
|
|
'00',
|
|
'000',
|
|
'0000',
|
|
'00000',
|
|
'000000',
|
|
'0000000',
|
|
'00000000',
|
|
'000000000',
|
|
'0000000000',
|
|
'00000000000',
|
|
'000000000000',
|
|
'0000000000000',
|
|
'00000000000000',
|
|
'000000000000000',
|
|
'0000000000000000',
|
|
'00000000000000000',
|
|
'000000000000000000',
|
|
'0000000000000000000',
|
|
'00000000000000000000',
|
|
'000000000000000000000',
|
|
'0000000000000000000000',
|
|
'00000000000000000000000',
|
|
'000000000000000000000000',
|
|
'0000000000000000000000000'
|
|
];
|
|
|
|
var groupSizes = [
|
|
0, 0,
|
|
25, 16, 12, 11, 10, 9, 8,
|
|
8, 7, 7, 7, 7, 6, 6,
|
|
6, 6, 6, 6, 6, 5, 5,
|
|
5, 5, 5, 5, 5, 5, 5,
|
|
5, 5, 5, 5, 5, 5, 5
|
|
];
|
|
|
|
var groupBases = [
|
|
0, 0,
|
|
33554432, 43046721, 16777216, 48828125, 60466176, 40353607, 16777216,
|
|
43046721, 10000000, 19487171, 35831808, 62748517, 7529536, 11390625,
|
|
16777216, 24137569, 34012224, 47045881, 64000000, 4084101, 5153632,
|
|
6436343, 7962624, 9765625, 11881376, 14348907, 17210368, 20511149,
|
|
24300000, 28629151, 33554432, 39135393, 45435424, 52521875, 60466176
|
|
];
|
|
|
|
BN.prototype.toString = function toString (base, padding) {
|
|
base = base || 10;
|
|
padding = padding | 0 || 1;
|
|
|
|
var out;
|
|
if (base === 16 || base === 'hex') {
|
|
out = '';
|
|
var off = 0;
|
|
var carry = 0;
|
|
for (var i = 0; i < this.length; i++) {
|
|
var w = this.words[i];
|
|
var word = (((w << off) | carry) & 0xffffff).toString(16);
|
|
carry = (w >>> (24 - off)) & 0xffffff;
|
|
if (carry !== 0 || i !== this.length - 1) {
|
|
out = zeros[6 - word.length] + word + out;
|
|
} else {
|
|
out = word + out;
|
|
}
|
|
off += 2;
|
|
if (off >= 26) {
|
|
off -= 26;
|
|
i--;
|
|
}
|
|
}
|
|
if (carry !== 0) {
|
|
out = carry.toString(16) + out;
|
|
}
|
|
while (out.length % padding !== 0) {
|
|
out = '0' + out;
|
|
}
|
|
if (this.negative !== 0) {
|
|
out = '-' + out;
|
|
}
|
|
return out;
|
|
}
|
|
|
|
if (base === (base | 0) && base >= 2 && base <= 36) {
|
|
// var groupSize = Math.floor(BN.wordSize * Math.LN2 / Math.log(base));
|
|
var groupSize = groupSizes[base];
|
|
// var groupBase = Math.pow(base, groupSize);
|
|
var groupBase = groupBases[base];
|
|
out = '';
|
|
var c = this.clone();
|
|
c.negative = 0;
|
|
while (!c.isZero()) {
|
|
var r = c.modn(groupBase).toString(base);
|
|
c = c.idivn(groupBase);
|
|
|
|
if (!c.isZero()) {
|
|
out = zeros[groupSize - r.length] + r + out;
|
|
} else {
|
|
out = r + out;
|
|
}
|
|
}
|
|
if (this.isZero()) {
|
|
out = '0' + out;
|
|
}
|
|
while (out.length % padding !== 0) {
|
|
out = '0' + out;
|
|
}
|
|
if (this.negative !== 0) {
|
|
out = '-' + out;
|
|
}
|
|
return out;
|
|
}
|
|
|
|
assert(false, 'Base should be between 2 and 36');
|
|
};
|
|
|
|
BN.prototype.toNumber = function toNumber () {
|
|
var ret = this.words[0];
|
|
if (this.length === 2) {
|
|
ret += this.words[1] * 0x4000000;
|
|
} else if (this.length === 3 && this.words[2] === 0x01) {
|
|
// NOTE: at this stage it is known that the top bit is set
|
|
ret += 0x10000000000000 + (this.words[1] * 0x4000000);
|
|
} else if (this.length > 2) {
|
|
assert(false, 'Number can only safely store up to 53 bits');
|
|
}
|
|
return (this.negative !== 0) ? -ret : ret;
|
|
};
|
|
|
|
BN.prototype.toJSON = function toJSON () {
|
|
return this.toString(16);
|
|
};
|
|
|
|
BN.prototype.toBuffer = function toBuffer (endian, length) {
|
|
assert(typeof Buffer !== 'undefined');
|
|
return this.toArrayLike(Buffer, endian, length);
|
|
};
|
|
|
|
BN.prototype.toArray = function toArray (endian, length) {
|
|
return this.toArrayLike(Array, endian, length);
|
|
};
|
|
|
|
BN.prototype.toArrayLike = function toArrayLike (ArrayType, endian, length) {
|
|
var byteLength = this.byteLength();
|
|
var reqLength = length || Math.max(1, byteLength);
|
|
assert(byteLength <= reqLength, 'byte array longer than desired length');
|
|
assert(reqLength > 0, 'Requested array length <= 0');
|
|
|
|
this.strip();
|
|
var littleEndian = endian === 'le';
|
|
var res = new ArrayType(reqLength);
|
|
|
|
var b, i;
|
|
var q = this.clone();
|
|
if (!littleEndian) {
|
|
// Assume big-endian
|
|
for (i = 0; i < reqLength - byteLength; i++) {
|
|
res[i] = 0;
|
|
}
|
|
|
|
for (i = 0; !q.isZero(); i++) {
|
|
b = q.andln(0xff);
|
|
q.iushrn(8);
|
|
|
|
res[reqLength - i - 1] = b;
|
|
}
|
|
} else {
|
|
for (i = 0; !q.isZero(); i++) {
|
|
b = q.andln(0xff);
|
|
q.iushrn(8);
|
|
|
|
res[i] = b;
|
|
}
|
|
|
|
for (; i < reqLength; i++) {
|
|
res[i] = 0;
|
|
}
|
|
}
|
|
|
|
return res;
|
|
};
|
|
|
|
if (Math.clz32) {
|
|
BN.prototype._countBits = function _countBits (w) {
|
|
return 32 - Math.clz32(w);
|
|
};
|
|
} else {
|
|
BN.prototype._countBits = function _countBits (w) {
|
|
var t = w;
|
|
var r = 0;
|
|
if (t >= 0x1000) {
|
|
r += 13;
|
|
t >>>= 13;
|
|
}
|
|
if (t >= 0x40) {
|
|
r += 7;
|
|
t >>>= 7;
|
|
}
|
|
if (t >= 0x8) {
|
|
r += 4;
|
|
t >>>= 4;
|
|
}
|
|
if (t >= 0x02) {
|
|
r += 2;
|
|
t >>>= 2;
|
|
}
|
|
return r + t;
|
|
};
|
|
}
|
|
|
|
BN.prototype._zeroBits = function _zeroBits (w) {
|
|
// Short-cut
|
|
if (w === 0) return 26;
|
|
|
|
var t = w;
|
|
var r = 0;
|
|
if ((t & 0x1fff) === 0) {
|
|
r += 13;
|
|
t >>>= 13;
|
|
}
|
|
if ((t & 0x7f) === 0) {
|
|
r += 7;
|
|
t >>>= 7;
|
|
}
|
|
if ((t & 0xf) === 0) {
|
|
r += 4;
|
|
t >>>= 4;
|
|
}
|
|
if ((t & 0x3) === 0) {
|
|
r += 2;
|
|
t >>>= 2;
|
|
}
|
|
if ((t & 0x1) === 0) {
|
|
r++;
|
|
}
|
|
return r;
|
|
};
|
|
|
|
// Return number of used bits in a BN
|
|
BN.prototype.bitLength = function bitLength () {
|
|
var w = this.words[this.length - 1];
|
|
var hi = this._countBits(w);
|
|
return (this.length - 1) * 26 + hi;
|
|
};
|
|
|
|
function toBitArray (num) {
|
|
var w = new Array(num.bitLength());
|
|
|
|
for (var bit = 0; bit < w.length; bit++) {
|
|
var off = (bit / 26) | 0;
|
|
var wbit = bit % 26;
|
|
|
|
w[bit] = (num.words[off] & (1 << wbit)) >>> wbit;
|
|
}
|
|
|
|
return w;
|
|
}
|
|
|
|
// Number of trailing zero bits
|
|
BN.prototype.zeroBits = function zeroBits () {
|
|
if (this.isZero()) return 0;
|
|
|
|
var r = 0;
|
|
for (var i = 0; i < this.length; i++) {
|
|
var b = this._zeroBits(this.words[i]);
|
|
r += b;
|
|
if (b !== 26) break;
|
|
}
|
|
return r;
|
|
};
|
|
|
|
BN.prototype.byteLength = function byteLength () {
|
|
return Math.ceil(this.bitLength() / 8);
|
|
};
|
|
|
|
BN.prototype.toTwos = function toTwos (width) {
|
|
if (this.negative !== 0) {
|
|
return this.abs().inotn(width).iaddn(1);
|
|
}
|
|
return this.clone();
|
|
};
|
|
|
|
BN.prototype.fromTwos = function fromTwos (width) {
|
|
if (this.testn(width - 1)) {
|
|
return this.notn(width).iaddn(1).ineg();
|
|
}
|
|
return this.clone();
|
|
};
|
|
|
|
BN.prototype.isNeg = function isNeg () {
|
|
return this.negative !== 0;
|
|
};
|
|
|
|
// Return negative clone of `this`
|
|
BN.prototype.neg = function neg () {
|
|
return this.clone().ineg();
|
|
};
|
|
|
|
BN.prototype.ineg = function ineg () {
|
|
if (!this.isZero()) {
|
|
this.negative ^= 1;
|
|
}
|
|
|
|
return this;
|
|
};
|
|
|
|
// Or `num` with `this` in-place
|
|
BN.prototype.iuor = function iuor (num) {
|
|
while (this.length < num.length) {
|
|
this.words[this.length++] = 0;
|
|
}
|
|
|
|
for (var i = 0; i < num.length; i++) {
|
|
this.words[i] = this.words[i] | num.words[i];
|
|
}
|
|
|
|
return this.strip();
|
|
};
|
|
|
|
BN.prototype.ior = function ior (num) {
|
|
assert((this.negative | num.negative) === 0);
|
|
return this.iuor(num);
|
|
};
|
|
|
|
// Or `num` with `this`
|
|
BN.prototype.or = function or (num) {
|
|
if (this.length > num.length) return this.clone().ior(num);
|
|
return num.clone().ior(this);
|
|
};
|
|
|
|
BN.prototype.uor = function uor (num) {
|
|
if (this.length > num.length) return this.clone().iuor(num);
|
|
return num.clone().iuor(this);
|
|
};
|
|
|
|
// And `num` with `this` in-place
|
|
BN.prototype.iuand = function iuand (num) {
|
|
// b = min-length(num, this)
|
|
var b;
|
|
if (this.length > num.length) {
|
|
b = num;
|
|
} else {
|
|
b = this;
|
|
}
|
|
|
|
for (var i = 0; i < b.length; i++) {
|
|
this.words[i] = this.words[i] & num.words[i];
|
|
}
|
|
|
|
this.length = b.length;
|
|
|
|
return this.strip();
|
|
};
|
|
|
|
BN.prototype.iand = function iand (num) {
|
|
assert((this.negative | num.negative) === 0);
|
|
return this.iuand(num);
|
|
};
|
|
|
|
// And `num` with `this`
|
|
BN.prototype.and = function and (num) {
|
|
if (this.length > num.length) return this.clone().iand(num);
|
|
return num.clone().iand(this);
|
|
};
|
|
|
|
BN.prototype.uand = function uand (num) {
|
|
if (this.length > num.length) return this.clone().iuand(num);
|
|
return num.clone().iuand(this);
|
|
};
|
|
|
|
// Xor `num` with `this` in-place
|
|
BN.prototype.iuxor = function iuxor (num) {
|
|
// a.length > b.length
|
|
var a;
|
|
var b;
|
|
if (this.length > num.length) {
|
|
a = this;
|
|
b = num;
|
|
} else {
|
|
a = num;
|
|
b = this;
|
|
}
|
|
|
|
for (var i = 0; i < b.length; i++) {
|
|
this.words[i] = a.words[i] ^ b.words[i];
|
|
}
|
|
|
|
if (this !== a) {
|
|
for (; i < a.length; i++) {
|
|
this.words[i] = a.words[i];
|
|
}
|
|
}
|
|
|
|
this.length = a.length;
|
|
|
|
return this.strip();
|
|
};
|
|
|
|
BN.prototype.ixor = function ixor (num) {
|
|
assert((this.negative | num.negative) === 0);
|
|
return this.iuxor(num);
|
|
};
|
|
|
|
// Xor `num` with `this`
|
|
BN.prototype.xor = function xor (num) {
|
|
if (this.length > num.length) return this.clone().ixor(num);
|
|
return num.clone().ixor(this);
|
|
};
|
|
|
|
BN.prototype.uxor = function uxor (num) {
|
|
if (this.length > num.length) return this.clone().iuxor(num);
|
|
return num.clone().iuxor(this);
|
|
};
|
|
|
|
// Not ``this`` with ``width`` bitwidth
|
|
BN.prototype.inotn = function inotn (width) {
|
|
assert(typeof width === 'number' && width >= 0);
|
|
|
|
var bytesNeeded = Math.ceil(width / 26) | 0;
|
|
var bitsLeft = width % 26;
|
|
|
|
// Extend the buffer with leading zeroes
|
|
this._expand(bytesNeeded);
|
|
|
|
if (bitsLeft > 0) {
|
|
bytesNeeded--;
|
|
}
|
|
|
|
// Handle complete words
|
|
for (var i = 0; i < bytesNeeded; i++) {
|
|
this.words[i] = ~this.words[i] & 0x3ffffff;
|
|
}
|
|
|
|
// Handle the residue
|
|
if (bitsLeft > 0) {
|
|
this.words[i] = ~this.words[i] & (0x3ffffff >> (26 - bitsLeft));
|
|
}
|
|
|
|
// And remove leading zeroes
|
|
return this.strip();
|
|
};
|
|
|
|
BN.prototype.notn = function notn (width) {
|
|
return this.clone().inotn(width);
|
|
};
|
|
|
|
// Set `bit` of `this`
|
|
BN.prototype.setn = function setn (bit, val) {
|
|
assert(typeof bit === 'number' && bit >= 0);
|
|
|
|
var off = (bit / 26) | 0;
|
|
var wbit = bit % 26;
|
|
|
|
this._expand(off + 1);
|
|
|
|
if (val) {
|
|
this.words[off] = this.words[off] | (1 << wbit);
|
|
} else {
|
|
this.words[off] = this.words[off] & ~(1 << wbit);
|
|
}
|
|
|
|
return this.strip();
|
|
};
|
|
|
|
// Add `num` to `this` in-place
|
|
BN.prototype.iadd = function iadd (num) {
|
|
var r;
|
|
|
|
// negative + positive
|
|
if (this.negative !== 0 && num.negative === 0) {
|
|
this.negative = 0;
|
|
r = this.isub(num);
|
|
this.negative ^= 1;
|
|
return this._normSign();
|
|
|
|
// positive + negative
|
|
} else if (this.negative === 0 && num.negative !== 0) {
|
|
num.negative = 0;
|
|
r = this.isub(num);
|
|
num.negative = 1;
|
|
return r._normSign();
|
|
}
|
|
|
|
// a.length > b.length
|
|
var a, b;
|
|
if (this.length > num.length) {
|
|
a = this;
|
|
b = num;
|
|
} else {
|
|
a = num;
|
|
b = this;
|
|
}
|
|
|
|
var carry = 0;
|
|
for (var i = 0; i < b.length; i++) {
|
|
r = (a.words[i] | 0) + (b.words[i] | 0) + carry;
|
|
this.words[i] = r & 0x3ffffff;
|
|
carry = r >>> 26;
|
|
}
|
|
for (; carry !== 0 && i < a.length; i++) {
|
|
r = (a.words[i] | 0) + carry;
|
|
this.words[i] = r & 0x3ffffff;
|
|
carry = r >>> 26;
|
|
}
|
|
|
|
this.length = a.length;
|
|
if (carry !== 0) {
|
|
this.words[this.length] = carry;
|
|
this.length++;
|
|
// Copy the rest of the words
|
|
} else if (a !== this) {
|
|
for (; i < a.length; i++) {
|
|
this.words[i] = a.words[i];
|
|
}
|
|
}
|
|
|
|
return this;
|
|
};
|
|
|
|
// Add `num` to `this`
|
|
BN.prototype.add = function add (num) {
|
|
var res;
|
|
if (num.negative !== 0 && this.negative === 0) {
|
|
num.negative = 0;
|
|
res = this.sub(num);
|
|
num.negative ^= 1;
|
|
return res;
|
|
} else if (num.negative === 0 && this.negative !== 0) {
|
|
this.negative = 0;
|
|
res = num.sub(this);
|
|
this.negative = 1;
|
|
return res;
|
|
}
|
|
|
|
if (this.length > num.length) return this.clone().iadd(num);
|
|
|
|
return num.clone().iadd(this);
|
|
};
|
|
|
|
// Subtract `num` from `this` in-place
|
|
BN.prototype.isub = function isub (num) {
|
|
// this - (-num) = this + num
|
|
if (num.negative !== 0) {
|
|
num.negative = 0;
|
|
var r = this.iadd(num);
|
|
num.negative = 1;
|
|
return r._normSign();
|
|
|
|
// -this - num = -(this + num)
|
|
} else if (this.negative !== 0) {
|
|
this.negative = 0;
|
|
this.iadd(num);
|
|
this.negative = 1;
|
|
return this._normSign();
|
|
}
|
|
|
|
// At this point both numbers are positive
|
|
var cmp = this.cmp(num);
|
|
|
|
// Optimization - zeroify
|
|
if (cmp === 0) {
|
|
this.negative = 0;
|
|
this.length = 1;
|
|
this.words[0] = 0;
|
|
return this;
|
|
}
|
|
|
|
// a > b
|
|
var a, b;
|
|
if (cmp > 0) {
|
|
a = this;
|
|
b = num;
|
|
} else {
|
|
a = num;
|
|
b = this;
|
|
}
|
|
|
|
var carry = 0;
|
|
for (var i = 0; i < b.length; i++) {
|
|
r = (a.words[i] | 0) - (b.words[i] | 0) + carry;
|
|
carry = r >> 26;
|
|
this.words[i] = r & 0x3ffffff;
|
|
}
|
|
for (; carry !== 0 && i < a.length; i++) {
|
|
r = (a.words[i] | 0) + carry;
|
|
carry = r >> 26;
|
|
this.words[i] = r & 0x3ffffff;
|
|
}
|
|
|
|
// Copy rest of the words
|
|
if (carry === 0 && i < a.length && a !== this) {
|
|
for (; i < a.length; i++) {
|
|
this.words[i] = a.words[i];
|
|
}
|
|
}
|
|
|
|
this.length = Math.max(this.length, i);
|
|
|
|
if (a !== this) {
|
|
this.negative = 1;
|
|
}
|
|
|
|
return this.strip();
|
|
};
|
|
|
|
// Subtract `num` from `this`
|
|
BN.prototype.sub = function sub (num) {
|
|
return this.clone().isub(num);
|
|
};
|
|
|
|
function smallMulTo (self, num, out) {
|
|
out.negative = num.negative ^ self.negative;
|
|
var len = (self.length + num.length) | 0;
|
|
out.length = len;
|
|
len = (len - 1) | 0;
|
|
|
|
// Peel one iteration (compiler can't do it, because of code complexity)
|
|
var a = self.words[0] | 0;
|
|
var b = num.words[0] | 0;
|
|
var r = a * b;
|
|
|
|
var lo = r & 0x3ffffff;
|
|
var carry = (r / 0x4000000) | 0;
|
|
out.words[0] = lo;
|
|
|
|
for (var k = 1; k < len; k++) {
|
|
// Sum all words with the same `i + j = k` and accumulate `ncarry`,
|
|
// note that ncarry could be >= 0x3ffffff
|
|
var ncarry = carry >>> 26;
|
|
var rword = carry & 0x3ffffff;
|
|
var maxJ = Math.min(k, num.length - 1);
|
|
for (var j = Math.max(0, k - self.length + 1); j <= maxJ; j++) {
|
|
var i = (k - j) | 0;
|
|
a = self.words[i] | 0;
|
|
b = num.words[j] | 0;
|
|
r = a * b + rword;
|
|
ncarry += (r / 0x4000000) | 0;
|
|
rword = r & 0x3ffffff;
|
|
}
|
|
out.words[k] = rword | 0;
|
|
carry = ncarry | 0;
|
|
}
|
|
if (carry !== 0) {
|
|
out.words[k] = carry | 0;
|
|
} else {
|
|
out.length--;
|
|
}
|
|
|
|
return out.strip();
|
|
}
|
|
|
|
// TODO(indutny): it may be reasonable to omit it for users who don't need
|
|
// to work with 256-bit numbers, otherwise it gives 20% improvement for 256-bit
|
|
// multiplication (like elliptic secp256k1).
|
|
var comb10MulTo = function comb10MulTo (self, num, out) {
|
|
var a = self.words;
|
|
var b = num.words;
|
|
var o = out.words;
|
|
var c = 0;
|
|
var lo;
|
|
var mid;
|
|
var hi;
|
|
var a0 = a[0] | 0;
|
|
var al0 = a0 & 0x1fff;
|
|
var ah0 = a0 >>> 13;
|
|
var a1 = a[1] | 0;
|
|
var al1 = a1 & 0x1fff;
|
|
var ah1 = a1 >>> 13;
|
|
var a2 = a[2] | 0;
|
|
var al2 = a2 & 0x1fff;
|
|
var ah2 = a2 >>> 13;
|
|
var a3 = a[3] | 0;
|
|
var al3 = a3 & 0x1fff;
|
|
var ah3 = a3 >>> 13;
|
|
var a4 = a[4] | 0;
|
|
var al4 = a4 & 0x1fff;
|
|
var ah4 = a4 >>> 13;
|
|
var a5 = a[5] | 0;
|
|
var al5 = a5 & 0x1fff;
|
|
var ah5 = a5 >>> 13;
|
|
var a6 = a[6] | 0;
|
|
var al6 = a6 & 0x1fff;
|
|
var ah6 = a6 >>> 13;
|
|
var a7 = a[7] | 0;
|
|
var al7 = a7 & 0x1fff;
|
|
var ah7 = a7 >>> 13;
|
|
var a8 = a[8] | 0;
|
|
var al8 = a8 & 0x1fff;
|
|
var ah8 = a8 >>> 13;
|
|
var a9 = a[9] | 0;
|
|
var al9 = a9 & 0x1fff;
|
|
var ah9 = a9 >>> 13;
|
|
var b0 = b[0] | 0;
|
|
var bl0 = b0 & 0x1fff;
|
|
var bh0 = b0 >>> 13;
|
|
var b1 = b[1] | 0;
|
|
var bl1 = b1 & 0x1fff;
|
|
var bh1 = b1 >>> 13;
|
|
var b2 = b[2] | 0;
|
|
var bl2 = b2 & 0x1fff;
|
|
var bh2 = b2 >>> 13;
|
|
var b3 = b[3] | 0;
|
|
var bl3 = b3 & 0x1fff;
|
|
var bh3 = b3 >>> 13;
|
|
var b4 = b[4] | 0;
|
|
var bl4 = b4 & 0x1fff;
|
|
var bh4 = b4 >>> 13;
|
|
var b5 = b[5] | 0;
|
|
var bl5 = b5 & 0x1fff;
|
|
var bh5 = b5 >>> 13;
|
|
var b6 = b[6] | 0;
|
|
var bl6 = b6 & 0x1fff;
|
|
var bh6 = b6 >>> 13;
|
|
var b7 = b[7] | 0;
|
|
var bl7 = b7 & 0x1fff;
|
|
var bh7 = b7 >>> 13;
|
|
var b8 = b[8] | 0;
|
|
var bl8 = b8 & 0x1fff;
|
|
var bh8 = b8 >>> 13;
|
|
var b9 = b[9] | 0;
|
|
var bl9 = b9 & 0x1fff;
|
|
var bh9 = b9 >>> 13;
|
|
|
|
out.negative = self.negative ^ num.negative;
|
|
out.length = 19;
|
|
/* k = 0 */
|
|
lo = Math.imul(al0, bl0);
|
|
mid = Math.imul(al0, bh0);
|
|
mid = (mid + Math.imul(ah0, bl0)) | 0;
|
|
hi = Math.imul(ah0, bh0);
|
|
var w0 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
|
|
c = (((hi + (mid >>> 13)) | 0) + (w0 >>> 26)) | 0;
|
|
w0 &= 0x3ffffff;
|
|
/* k = 1 */
|
|
lo = Math.imul(al1, bl0);
|
|
mid = Math.imul(al1, bh0);
|
|
mid = (mid + Math.imul(ah1, bl0)) | 0;
|
|
hi = Math.imul(ah1, bh0);
|
|
lo = (lo + Math.imul(al0, bl1)) | 0;
|
|
mid = (mid + Math.imul(al0, bh1)) | 0;
|
|
mid = (mid + Math.imul(ah0, bl1)) | 0;
|
|
hi = (hi + Math.imul(ah0, bh1)) | 0;
|
|
var w1 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
|
|
c = (((hi + (mid >>> 13)) | 0) + (w1 >>> 26)) | 0;
|
|
w1 &= 0x3ffffff;
|
|
/* k = 2 */
|
|
lo = Math.imul(al2, bl0);
|
|
mid = Math.imul(al2, bh0);
|
|
mid = (mid + Math.imul(ah2, bl0)) | 0;
|
|
hi = Math.imul(ah2, bh0);
|
|
lo = (lo + Math.imul(al1, bl1)) | 0;
|
|
mid = (mid + Math.imul(al1, bh1)) | 0;
|
|
mid = (mid + Math.imul(ah1, bl1)) | 0;
|
|
hi = (hi + Math.imul(ah1, bh1)) | 0;
|
|
lo = (lo + Math.imul(al0, bl2)) | 0;
|
|
mid = (mid + Math.imul(al0, bh2)) | 0;
|
|
mid = (mid + Math.imul(ah0, bl2)) | 0;
|
|
hi = (hi + Math.imul(ah0, bh2)) | 0;
|
|
var w2 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
|
|
c = (((hi + (mid >>> 13)) | 0) + (w2 >>> 26)) | 0;
|
|
w2 &= 0x3ffffff;
|
|
/* k = 3 */
|
|
lo = Math.imul(al3, bl0);
|
|
mid = Math.imul(al3, bh0);
|
|
mid = (mid + Math.imul(ah3, bl0)) | 0;
|
|
hi = Math.imul(ah3, bh0);
|
|
lo = (lo + Math.imul(al2, bl1)) | 0;
|
|
mid = (mid + Math.imul(al2, bh1)) | 0;
|
|
mid = (mid + Math.imul(ah2, bl1)) | 0;
|
|
hi = (hi + Math.imul(ah2, bh1)) | 0;
|
|
lo = (lo + Math.imul(al1, bl2)) | 0;
|
|
mid = (mid + Math.imul(al1, bh2)) | 0;
|
|
mid = (mid + Math.imul(ah1, bl2)) | 0;
|
|
hi = (hi + Math.imul(ah1, bh2)) | 0;
|
|
lo = (lo + Math.imul(al0, bl3)) | 0;
|
|
mid = (mid + Math.imul(al0, bh3)) | 0;
|
|
mid = (mid + Math.imul(ah0, bl3)) | 0;
|
|
hi = (hi + Math.imul(ah0, bh3)) | 0;
|
|
var w3 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
|
|
c = (((hi + (mid >>> 13)) | 0) + (w3 >>> 26)) | 0;
|
|
w3 &= 0x3ffffff;
|
|
/* k = 4 */
|
|
lo = Math.imul(al4, bl0);
|
|
mid = Math.imul(al4, bh0);
|
|
mid = (mid + Math.imul(ah4, bl0)) | 0;
|
|
hi = Math.imul(ah4, bh0);
|
|
lo = (lo + Math.imul(al3, bl1)) | 0;
|
|
mid = (mid + Math.imul(al3, bh1)) | 0;
|
|
mid = (mid + Math.imul(ah3, bl1)) | 0;
|
|
hi = (hi + Math.imul(ah3, bh1)) | 0;
|
|
lo = (lo + Math.imul(al2, bl2)) | 0;
|
|
mid = (mid + Math.imul(al2, bh2)) | 0;
|
|
mid = (mid + Math.imul(ah2, bl2)) | 0;
|
|
hi = (hi + Math.imul(ah2, bh2)) | 0;
|
|
lo = (lo + Math.imul(al1, bl3)) | 0;
|
|
mid = (mid + Math.imul(al1, bh3)) | 0;
|
|
mid = (mid + Math.imul(ah1, bl3)) | 0;
|
|
hi = (hi + Math.imul(ah1, bh3)) | 0;
|
|
lo = (lo + Math.imul(al0, bl4)) | 0;
|
|
mid = (mid + Math.imul(al0, bh4)) | 0;
|
|
mid = (mid + Math.imul(ah0, bl4)) | 0;
|
|
hi = (hi + Math.imul(ah0, bh4)) | 0;
|
|
var w4 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
|
|
c = (((hi + (mid >>> 13)) | 0) + (w4 >>> 26)) | 0;
|
|
w4 &= 0x3ffffff;
|
|
/* k = 5 */
|
|
lo = Math.imul(al5, bl0);
|
|
mid = Math.imul(al5, bh0);
|
|
mid = (mid + Math.imul(ah5, bl0)) | 0;
|
|
hi = Math.imul(ah5, bh0);
|
|
lo = (lo + Math.imul(al4, bl1)) | 0;
|
|
mid = (mid + Math.imul(al4, bh1)) | 0;
|
|
mid = (mid + Math.imul(ah4, bl1)) | 0;
|
|
hi = (hi + Math.imul(ah4, bh1)) | 0;
|
|
lo = (lo + Math.imul(al3, bl2)) | 0;
|
|
mid = (mid + Math.imul(al3, bh2)) | 0;
|
|
mid = (mid + Math.imul(ah3, bl2)) | 0;
|
|
hi = (hi + Math.imul(ah3, bh2)) | 0;
|
|
lo = (lo + Math.imul(al2, bl3)) | 0;
|
|
mid = (mid + Math.imul(al2, bh3)) | 0;
|
|
mid = (mid + Math.imul(ah2, bl3)) | 0;
|
|
hi = (hi + Math.imul(ah2, bh3)) | 0;
|
|
lo = (lo + Math.imul(al1, bl4)) | 0;
|
|
mid = (mid + Math.imul(al1, bh4)) | 0;
|
|
mid = (mid + Math.imul(ah1, bl4)) | 0;
|
|
hi = (hi + Math.imul(ah1, bh4)) | 0;
|
|
lo = (lo + Math.imul(al0, bl5)) | 0;
|
|
mid = (mid + Math.imul(al0, bh5)) | 0;
|
|
mid = (mid + Math.imul(ah0, bl5)) | 0;
|
|
hi = (hi + Math.imul(ah0, bh5)) | 0;
|
|
var w5 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
|
|
c = (((hi + (mid >>> 13)) | 0) + (w5 >>> 26)) | 0;
|
|
w5 &= 0x3ffffff;
|
|
/* k = 6 */
|
|
lo = Math.imul(al6, bl0);
|
|
mid = Math.imul(al6, bh0);
|
|
mid = (mid + Math.imul(ah6, bl0)) | 0;
|
|
hi = Math.imul(ah6, bh0);
|
|
lo = (lo + Math.imul(al5, bl1)) | 0;
|
|
mid = (mid + Math.imul(al5, bh1)) | 0;
|
|
mid = (mid + Math.imul(ah5, bl1)) | 0;
|
|
hi = (hi + Math.imul(ah5, bh1)) | 0;
|
|
lo = (lo + Math.imul(al4, bl2)) | 0;
|
|
mid = (mid + Math.imul(al4, bh2)) | 0;
|
|
mid = (mid + Math.imul(ah4, bl2)) | 0;
|
|
hi = (hi + Math.imul(ah4, bh2)) | 0;
|
|
lo = (lo + Math.imul(al3, bl3)) | 0;
|
|
mid = (mid + Math.imul(al3, bh3)) | 0;
|
|
mid = (mid + Math.imul(ah3, bl3)) | 0;
|
|
hi = (hi + Math.imul(ah3, bh3)) | 0;
|
|
lo = (lo + Math.imul(al2, bl4)) | 0;
|
|
mid = (mid + Math.imul(al2, bh4)) | 0;
|
|
mid = (mid + Math.imul(ah2, bl4)) | 0;
|
|
hi = (hi + Math.imul(ah2, bh4)) | 0;
|
|
lo = (lo + Math.imul(al1, bl5)) | 0;
|
|
mid = (mid + Math.imul(al1, bh5)) | 0;
|
|
mid = (mid + Math.imul(ah1, bl5)) | 0;
|
|
hi = (hi + Math.imul(ah1, bh5)) | 0;
|
|
lo = (lo + Math.imul(al0, bl6)) | 0;
|
|
mid = (mid + Math.imul(al0, bh6)) | 0;
|
|
mid = (mid + Math.imul(ah0, bl6)) | 0;
|
|
hi = (hi + Math.imul(ah0, bh6)) | 0;
|
|
var w6 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
|
|
c = (((hi + (mid >>> 13)) | 0) + (w6 >>> 26)) | 0;
|
|
w6 &= 0x3ffffff;
|
|
/* k = 7 */
|
|
lo = Math.imul(al7, bl0);
|
|
mid = Math.imul(al7, bh0);
|
|
mid = (mid + Math.imul(ah7, bl0)) | 0;
|
|
hi = Math.imul(ah7, bh0);
|
|
lo = (lo + Math.imul(al6, bl1)) | 0;
|
|
mid = (mid + Math.imul(al6, bh1)) | 0;
|
|
mid = (mid + Math.imul(ah6, bl1)) | 0;
|
|
hi = (hi + Math.imul(ah6, bh1)) | 0;
|
|
lo = (lo + Math.imul(al5, bl2)) | 0;
|
|
mid = (mid + Math.imul(al5, bh2)) | 0;
|
|
mid = (mid + Math.imul(ah5, bl2)) | 0;
|
|
hi = (hi + Math.imul(ah5, bh2)) | 0;
|
|
lo = (lo + Math.imul(al4, bl3)) | 0;
|
|
mid = (mid + Math.imul(al4, bh3)) | 0;
|
|
mid = (mid + Math.imul(ah4, bl3)) | 0;
|
|
hi = (hi + Math.imul(ah4, bh3)) | 0;
|
|
lo = (lo + Math.imul(al3, bl4)) | 0;
|
|
mid = (mid + Math.imul(al3, bh4)) | 0;
|
|
mid = (mid + Math.imul(ah3, bl4)) | 0;
|
|
hi = (hi + Math.imul(ah3, bh4)) | 0;
|
|
lo = (lo + Math.imul(al2, bl5)) | 0;
|
|
mid = (mid + Math.imul(al2, bh5)) | 0;
|
|
mid = (mid + Math.imul(ah2, bl5)) | 0;
|
|
hi = (hi + Math.imul(ah2, bh5)) | 0;
|
|
lo = (lo + Math.imul(al1, bl6)) | 0;
|
|
mid = (mid + Math.imul(al1, bh6)) | 0;
|
|
mid = (mid + Math.imul(ah1, bl6)) | 0;
|
|
hi = (hi + Math.imul(ah1, bh6)) | 0;
|
|
lo = (lo + Math.imul(al0, bl7)) | 0;
|
|
mid = (mid + Math.imul(al0, bh7)) | 0;
|
|
mid = (mid + Math.imul(ah0, bl7)) | 0;
|
|
hi = (hi + Math.imul(ah0, bh7)) | 0;
|
|
var w7 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
|
|
c = (((hi + (mid >>> 13)) | 0) + (w7 >>> 26)) | 0;
|
|
w7 &= 0x3ffffff;
|
|
/* k = 8 */
|
|
lo = Math.imul(al8, bl0);
|
|
mid = Math.imul(al8, bh0);
|
|
mid = (mid + Math.imul(ah8, bl0)) | 0;
|
|
hi = Math.imul(ah8, bh0);
|
|
lo = (lo + Math.imul(al7, bl1)) | 0;
|
|
mid = (mid + Math.imul(al7, bh1)) | 0;
|
|
mid = (mid + Math.imul(ah7, bl1)) | 0;
|
|
hi = (hi + Math.imul(ah7, bh1)) | 0;
|
|
lo = (lo + Math.imul(al6, bl2)) | 0;
|
|
mid = (mid + Math.imul(al6, bh2)) | 0;
|
|
mid = (mid + Math.imul(ah6, bl2)) | 0;
|
|
hi = (hi + Math.imul(ah6, bh2)) | 0;
|
|
lo = (lo + Math.imul(al5, bl3)) | 0;
|
|
mid = (mid + Math.imul(al5, bh3)) | 0;
|
|
mid = (mid + Math.imul(ah5, bl3)) | 0;
|
|
hi = (hi + Math.imul(ah5, bh3)) | 0;
|
|
lo = (lo + Math.imul(al4, bl4)) | 0;
|
|
mid = (mid + Math.imul(al4, bh4)) | 0;
|
|
mid = (mid + Math.imul(ah4, bl4)) | 0;
|
|
hi = (hi + Math.imul(ah4, bh4)) | 0;
|
|
lo = (lo + Math.imul(al3, bl5)) | 0;
|
|
mid = (mid + Math.imul(al3, bh5)) | 0;
|
|
mid = (mid + Math.imul(ah3, bl5)) | 0;
|
|
hi = (hi + Math.imul(ah3, bh5)) | 0;
|
|
lo = (lo + Math.imul(al2, bl6)) | 0;
|
|
mid = (mid + Math.imul(al2, bh6)) | 0;
|
|
mid = (mid + Math.imul(ah2, bl6)) | 0;
|
|
hi = (hi + Math.imul(ah2, bh6)) | 0;
|
|
lo = (lo + Math.imul(al1, bl7)) | 0;
|
|
mid = (mid + Math.imul(al1, bh7)) | 0;
|
|
mid = (mid + Math.imul(ah1, bl7)) | 0;
|
|
hi = (hi + Math.imul(ah1, bh7)) | 0;
|
|
lo = (lo + Math.imul(al0, bl8)) | 0;
|
|
mid = (mid + Math.imul(al0, bh8)) | 0;
|
|
mid = (mid + Math.imul(ah0, bl8)) | 0;
|
|
hi = (hi + Math.imul(ah0, bh8)) | 0;
|
|
var w8 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
|
|
c = (((hi + (mid >>> 13)) | 0) + (w8 >>> 26)) | 0;
|
|
w8 &= 0x3ffffff;
|
|
/* k = 9 */
|
|
lo = Math.imul(al9, bl0);
|
|
mid = Math.imul(al9, bh0);
|
|
mid = (mid + Math.imul(ah9, bl0)) | 0;
|
|
hi = Math.imul(ah9, bh0);
|
|
lo = (lo + Math.imul(al8, bl1)) | 0;
|
|
mid = (mid + Math.imul(al8, bh1)) | 0;
|
|
mid = (mid + Math.imul(ah8, bl1)) | 0;
|
|
hi = (hi + Math.imul(ah8, bh1)) | 0;
|
|
lo = (lo + Math.imul(al7, bl2)) | 0;
|
|
mid = (mid + Math.imul(al7, bh2)) | 0;
|
|
mid = (mid + Math.imul(ah7, bl2)) | 0;
|
|
hi = (hi + Math.imul(ah7, bh2)) | 0;
|
|
lo = (lo + Math.imul(al6, bl3)) | 0;
|
|
mid = (mid + Math.imul(al6, bh3)) | 0;
|
|
mid = (mid + Math.imul(ah6, bl3)) | 0;
|
|
hi = (hi + Math.imul(ah6, bh3)) | 0;
|
|
lo = (lo + Math.imul(al5, bl4)) | 0;
|
|
mid = (mid + Math.imul(al5, bh4)) | 0;
|
|
mid = (mid + Math.imul(ah5, bl4)) | 0;
|
|
hi = (hi + Math.imul(ah5, bh4)) | 0;
|
|
lo = (lo + Math.imul(al4, bl5)) | 0;
|
|
mid = (mid + Math.imul(al4, bh5)) | 0;
|
|
mid = (mid + Math.imul(ah4, bl5)) | 0;
|
|
hi = (hi + Math.imul(ah4, bh5)) | 0;
|
|
lo = (lo + Math.imul(al3, bl6)) | 0;
|
|
mid = (mid + Math.imul(al3, bh6)) | 0;
|
|
mid = (mid + Math.imul(ah3, bl6)) | 0;
|
|
hi = (hi + Math.imul(ah3, bh6)) | 0;
|
|
lo = (lo + Math.imul(al2, bl7)) | 0;
|
|
mid = (mid + Math.imul(al2, bh7)) | 0;
|
|
mid = (mid + Math.imul(ah2, bl7)) | 0;
|
|
hi = (hi + Math.imul(ah2, bh7)) | 0;
|
|
lo = (lo + Math.imul(al1, bl8)) | 0;
|
|
mid = (mid + Math.imul(al1, bh8)) | 0;
|
|
mid = (mid + Math.imul(ah1, bl8)) | 0;
|
|
hi = (hi + Math.imul(ah1, bh8)) | 0;
|
|
lo = (lo + Math.imul(al0, bl9)) | 0;
|
|
mid = (mid + Math.imul(al0, bh9)) | 0;
|
|
mid = (mid + Math.imul(ah0, bl9)) | 0;
|
|
hi = (hi + Math.imul(ah0, bh9)) | 0;
|
|
var w9 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
|
|
c = (((hi + (mid >>> 13)) | 0) + (w9 >>> 26)) | 0;
|
|
w9 &= 0x3ffffff;
|
|
/* k = 10 */
|
|
lo = Math.imul(al9, bl1);
|
|
mid = Math.imul(al9, bh1);
|
|
mid = (mid + Math.imul(ah9, bl1)) | 0;
|
|
hi = Math.imul(ah9, bh1);
|
|
lo = (lo + Math.imul(al8, bl2)) | 0;
|
|
mid = (mid + Math.imul(al8, bh2)) | 0;
|
|
mid = (mid + Math.imul(ah8, bl2)) | 0;
|
|
hi = (hi + Math.imul(ah8, bh2)) | 0;
|
|
lo = (lo + Math.imul(al7, bl3)) | 0;
|
|
mid = (mid + Math.imul(al7, bh3)) | 0;
|
|
mid = (mid + Math.imul(ah7, bl3)) | 0;
|
|
hi = (hi + Math.imul(ah7, bh3)) | 0;
|
|
lo = (lo + Math.imul(al6, bl4)) | 0;
|
|
mid = (mid + Math.imul(al6, bh4)) | 0;
|
|
mid = (mid + Math.imul(ah6, bl4)) | 0;
|
|
hi = (hi + Math.imul(ah6, bh4)) | 0;
|
|
lo = (lo + Math.imul(al5, bl5)) | 0;
|
|
mid = (mid + Math.imul(al5, bh5)) | 0;
|
|
mid = (mid + Math.imul(ah5, bl5)) | 0;
|
|
hi = (hi + Math.imul(ah5, bh5)) | 0;
|
|
lo = (lo + Math.imul(al4, bl6)) | 0;
|
|
mid = (mid + Math.imul(al4, bh6)) | 0;
|
|
mid = (mid + Math.imul(ah4, bl6)) | 0;
|
|
hi = (hi + Math.imul(ah4, bh6)) | 0;
|
|
lo = (lo + Math.imul(al3, bl7)) | 0;
|
|
mid = (mid + Math.imul(al3, bh7)) | 0;
|
|
mid = (mid + Math.imul(ah3, bl7)) | 0;
|
|
hi = (hi + Math.imul(ah3, bh7)) | 0;
|
|
lo = (lo + Math.imul(al2, bl8)) | 0;
|
|
mid = (mid + Math.imul(al2, bh8)) | 0;
|
|
mid = (mid + Math.imul(ah2, bl8)) | 0;
|
|
hi = (hi + Math.imul(ah2, bh8)) | 0;
|
|
lo = (lo + Math.imul(al1, bl9)) | 0;
|
|
mid = (mid + Math.imul(al1, bh9)) | 0;
|
|
mid = (mid + Math.imul(ah1, bl9)) | 0;
|
|
hi = (hi + Math.imul(ah1, bh9)) | 0;
|
|
var w10 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
|
|
c = (((hi + (mid >>> 13)) | 0) + (w10 >>> 26)) | 0;
|
|
w10 &= 0x3ffffff;
|
|
/* k = 11 */
|
|
lo = Math.imul(al9, bl2);
|
|
mid = Math.imul(al9, bh2);
|
|
mid = (mid + Math.imul(ah9, bl2)) | 0;
|
|
hi = Math.imul(ah9, bh2);
|
|
lo = (lo + Math.imul(al8, bl3)) | 0;
|
|
mid = (mid + Math.imul(al8, bh3)) | 0;
|
|
mid = (mid + Math.imul(ah8, bl3)) | 0;
|
|
hi = (hi + Math.imul(ah8, bh3)) | 0;
|
|
lo = (lo + Math.imul(al7, bl4)) | 0;
|
|
mid = (mid + Math.imul(al7, bh4)) | 0;
|
|
mid = (mid + Math.imul(ah7, bl4)) | 0;
|
|
hi = (hi + Math.imul(ah7, bh4)) | 0;
|
|
lo = (lo + Math.imul(al6, bl5)) | 0;
|
|
mid = (mid + Math.imul(al6, bh5)) | 0;
|
|
mid = (mid + Math.imul(ah6, bl5)) | 0;
|
|
hi = (hi + Math.imul(ah6, bh5)) | 0;
|
|
lo = (lo + Math.imul(al5, bl6)) | 0;
|
|
mid = (mid + Math.imul(al5, bh6)) | 0;
|
|
mid = (mid + Math.imul(ah5, bl6)) | 0;
|
|
hi = (hi + Math.imul(ah5, bh6)) | 0;
|
|
lo = (lo + Math.imul(al4, bl7)) | 0;
|
|
mid = (mid + Math.imul(al4, bh7)) | 0;
|
|
mid = (mid + Math.imul(ah4, bl7)) | 0;
|
|
hi = (hi + Math.imul(ah4, bh7)) | 0;
|
|
lo = (lo + Math.imul(al3, bl8)) | 0;
|
|
mid = (mid + Math.imul(al3, bh8)) | 0;
|
|
mid = (mid + Math.imul(ah3, bl8)) | 0;
|
|
hi = (hi + Math.imul(ah3, bh8)) | 0;
|
|
lo = (lo + Math.imul(al2, bl9)) | 0;
|
|
mid = (mid + Math.imul(al2, bh9)) | 0;
|
|
mid = (mid + Math.imul(ah2, bl9)) | 0;
|
|
hi = (hi + Math.imul(ah2, bh9)) | 0;
|
|
var w11 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
|
|
c = (((hi + (mid >>> 13)) | 0) + (w11 >>> 26)) | 0;
|
|
w11 &= 0x3ffffff;
|
|
/* k = 12 */
|
|
lo = Math.imul(al9, bl3);
|
|
mid = Math.imul(al9, bh3);
|
|
mid = (mid + Math.imul(ah9, bl3)) | 0;
|
|
hi = Math.imul(ah9, bh3);
|
|
lo = (lo + Math.imul(al8, bl4)) | 0;
|
|
mid = (mid + Math.imul(al8, bh4)) | 0;
|
|
mid = (mid + Math.imul(ah8, bl4)) | 0;
|
|
hi = (hi + Math.imul(ah8, bh4)) | 0;
|
|
lo = (lo + Math.imul(al7, bl5)) | 0;
|
|
mid = (mid + Math.imul(al7, bh5)) | 0;
|
|
mid = (mid + Math.imul(ah7, bl5)) | 0;
|
|
hi = (hi + Math.imul(ah7, bh5)) | 0;
|
|
lo = (lo + Math.imul(al6, bl6)) | 0;
|
|
mid = (mid + Math.imul(al6, bh6)) | 0;
|
|
mid = (mid + Math.imul(ah6, bl6)) | 0;
|
|
hi = (hi + Math.imul(ah6, bh6)) | 0;
|
|
lo = (lo + Math.imul(al5, bl7)) | 0;
|
|
mid = (mid + Math.imul(al5, bh7)) | 0;
|
|
mid = (mid + Math.imul(ah5, bl7)) | 0;
|
|
hi = (hi + Math.imul(ah5, bh7)) | 0;
|
|
lo = (lo + Math.imul(al4, bl8)) | 0;
|
|
mid = (mid + Math.imul(al4, bh8)) | 0;
|
|
mid = (mid + Math.imul(ah4, bl8)) | 0;
|
|
hi = (hi + Math.imul(ah4, bh8)) | 0;
|
|
lo = (lo + Math.imul(al3, bl9)) | 0;
|
|
mid = (mid + Math.imul(al3, bh9)) | 0;
|
|
mid = (mid + Math.imul(ah3, bl9)) | 0;
|
|
hi = (hi + Math.imul(ah3, bh9)) | 0;
|
|
var w12 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
|
|
c = (((hi + (mid >>> 13)) | 0) + (w12 >>> 26)) | 0;
|
|
w12 &= 0x3ffffff;
|
|
/* k = 13 */
|
|
lo = Math.imul(al9, bl4);
|
|
mid = Math.imul(al9, bh4);
|
|
mid = (mid + Math.imul(ah9, bl4)) | 0;
|
|
hi = Math.imul(ah9, bh4);
|
|
lo = (lo + Math.imul(al8, bl5)) | 0;
|
|
mid = (mid + Math.imul(al8, bh5)) | 0;
|
|
mid = (mid + Math.imul(ah8, bl5)) | 0;
|
|
hi = (hi + Math.imul(ah8, bh5)) | 0;
|
|
lo = (lo + Math.imul(al7, bl6)) | 0;
|
|
mid = (mid + Math.imul(al7, bh6)) | 0;
|
|
mid = (mid + Math.imul(ah7, bl6)) | 0;
|
|
hi = (hi + Math.imul(ah7, bh6)) | 0;
|
|
lo = (lo + Math.imul(al6, bl7)) | 0;
|
|
mid = (mid + Math.imul(al6, bh7)) | 0;
|
|
mid = (mid + Math.imul(ah6, bl7)) | 0;
|
|
hi = (hi + Math.imul(ah6, bh7)) | 0;
|
|
lo = (lo + Math.imul(al5, bl8)) | 0;
|
|
mid = (mid + Math.imul(al5, bh8)) | 0;
|
|
mid = (mid + Math.imul(ah5, bl8)) | 0;
|
|
hi = (hi + Math.imul(ah5, bh8)) | 0;
|
|
lo = (lo + Math.imul(al4, bl9)) | 0;
|
|
mid = (mid + Math.imul(al4, bh9)) | 0;
|
|
mid = (mid + Math.imul(ah4, bl9)) | 0;
|
|
hi = (hi + Math.imul(ah4, bh9)) | 0;
|
|
var w13 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
|
|
c = (((hi + (mid >>> 13)) | 0) + (w13 >>> 26)) | 0;
|
|
w13 &= 0x3ffffff;
|
|
/* k = 14 */
|
|
lo = Math.imul(al9, bl5);
|
|
mid = Math.imul(al9, bh5);
|
|
mid = (mid + Math.imul(ah9, bl5)) | 0;
|
|
hi = Math.imul(ah9, bh5);
|
|
lo = (lo + Math.imul(al8, bl6)) | 0;
|
|
mid = (mid + Math.imul(al8, bh6)) | 0;
|
|
mid = (mid + Math.imul(ah8, bl6)) | 0;
|
|
hi = (hi + Math.imul(ah8, bh6)) | 0;
|
|
lo = (lo + Math.imul(al7, bl7)) | 0;
|
|
mid = (mid + Math.imul(al7, bh7)) | 0;
|
|
mid = (mid + Math.imul(ah7, bl7)) | 0;
|
|
hi = (hi + Math.imul(ah7, bh7)) | 0;
|
|
lo = (lo + Math.imul(al6, bl8)) | 0;
|
|
mid = (mid + Math.imul(al6, bh8)) | 0;
|
|
mid = (mid + Math.imul(ah6, bl8)) | 0;
|
|
hi = (hi + Math.imul(ah6, bh8)) | 0;
|
|
lo = (lo + Math.imul(al5, bl9)) | 0;
|
|
mid = (mid + Math.imul(al5, bh9)) | 0;
|
|
mid = (mid + Math.imul(ah5, bl9)) | 0;
|
|
hi = (hi + Math.imul(ah5, bh9)) | 0;
|
|
var w14 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
|
|
c = (((hi + (mid >>> 13)) | 0) + (w14 >>> 26)) | 0;
|
|
w14 &= 0x3ffffff;
|
|
/* k = 15 */
|
|
lo = Math.imul(al9, bl6);
|
|
mid = Math.imul(al9, bh6);
|
|
mid = (mid + Math.imul(ah9, bl6)) | 0;
|
|
hi = Math.imul(ah9, bh6);
|
|
lo = (lo + Math.imul(al8, bl7)) | 0;
|
|
mid = (mid + Math.imul(al8, bh7)) | 0;
|
|
mid = (mid + Math.imul(ah8, bl7)) | 0;
|
|
hi = (hi + Math.imul(ah8, bh7)) | 0;
|
|
lo = (lo + Math.imul(al7, bl8)) | 0;
|
|
mid = (mid + Math.imul(al7, bh8)) | 0;
|
|
mid = (mid + Math.imul(ah7, bl8)) | 0;
|
|
hi = (hi + Math.imul(ah7, bh8)) | 0;
|
|
lo = (lo + Math.imul(al6, bl9)) | 0;
|
|
mid = (mid + Math.imul(al6, bh9)) | 0;
|
|
mid = (mid + Math.imul(ah6, bl9)) | 0;
|
|
hi = (hi + Math.imul(ah6, bh9)) | 0;
|
|
var w15 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
|
|
c = (((hi + (mid >>> 13)) | 0) + (w15 >>> 26)) | 0;
|
|
w15 &= 0x3ffffff;
|
|
/* k = 16 */
|
|
lo = Math.imul(al9, bl7);
|
|
mid = Math.imul(al9, bh7);
|
|
mid = (mid + Math.imul(ah9, bl7)) | 0;
|
|
hi = Math.imul(ah9, bh7);
|
|
lo = (lo + Math.imul(al8, bl8)) | 0;
|
|
mid = (mid + Math.imul(al8, bh8)) | 0;
|
|
mid = (mid + Math.imul(ah8, bl8)) | 0;
|
|
hi = (hi + Math.imul(ah8, bh8)) | 0;
|
|
lo = (lo + Math.imul(al7, bl9)) | 0;
|
|
mid = (mid + Math.imul(al7, bh9)) | 0;
|
|
mid = (mid + Math.imul(ah7, bl9)) | 0;
|
|
hi = (hi + Math.imul(ah7, bh9)) | 0;
|
|
var w16 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
|
|
c = (((hi + (mid >>> 13)) | 0) + (w16 >>> 26)) | 0;
|
|
w16 &= 0x3ffffff;
|
|
/* k = 17 */
|
|
lo = Math.imul(al9, bl8);
|
|
mid = Math.imul(al9, bh8);
|
|
mid = (mid + Math.imul(ah9, bl8)) | 0;
|
|
hi = Math.imul(ah9, bh8);
|
|
lo = (lo + Math.imul(al8, bl9)) | 0;
|
|
mid = (mid + Math.imul(al8, bh9)) | 0;
|
|
mid = (mid + Math.imul(ah8, bl9)) | 0;
|
|
hi = (hi + Math.imul(ah8, bh9)) | 0;
|
|
var w17 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
|
|
c = (((hi + (mid >>> 13)) | 0) + (w17 >>> 26)) | 0;
|
|
w17 &= 0x3ffffff;
|
|
/* k = 18 */
|
|
lo = Math.imul(al9, bl9);
|
|
mid = Math.imul(al9, bh9);
|
|
mid = (mid + Math.imul(ah9, bl9)) | 0;
|
|
hi = Math.imul(ah9, bh9);
|
|
var w18 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
|
|
c = (((hi + (mid >>> 13)) | 0) + (w18 >>> 26)) | 0;
|
|
w18 &= 0x3ffffff;
|
|
o[0] = w0;
|
|
o[1] = w1;
|
|
o[2] = w2;
|
|
o[3] = w3;
|
|
o[4] = w4;
|
|
o[5] = w5;
|
|
o[6] = w6;
|
|
o[7] = w7;
|
|
o[8] = w8;
|
|
o[9] = w9;
|
|
o[10] = w10;
|
|
o[11] = w11;
|
|
o[12] = w12;
|
|
o[13] = w13;
|
|
o[14] = w14;
|
|
o[15] = w15;
|
|
o[16] = w16;
|
|
o[17] = w17;
|
|
o[18] = w18;
|
|
if (c !== 0) {
|
|
o[19] = c;
|
|
out.length++;
|
|
}
|
|
return out;
|
|
};
|
|
|
|
// Polyfill comb
|
|
if (!Math.imul) {
|
|
comb10MulTo = smallMulTo;
|
|
}
|
|
|
|
function bigMulTo (self, num, out) {
|
|
out.negative = num.negative ^ self.negative;
|
|
out.length = self.length + num.length;
|
|
|
|
var carry = 0;
|
|
var hncarry = 0;
|
|
for (var k = 0; k < out.length - 1; k++) {
|
|
// Sum all words with the same `i + j = k` and accumulate `ncarry`,
|
|
// note that ncarry could be >= 0x3ffffff
|
|
var ncarry = hncarry;
|
|
hncarry = 0;
|
|
var rword = carry & 0x3ffffff;
|
|
var maxJ = Math.min(k, num.length - 1);
|
|
for (var j = Math.max(0, k - self.length + 1); j <= maxJ; j++) {
|
|
var i = k - j;
|
|
var a = self.words[i] | 0;
|
|
var b = num.words[j] | 0;
|
|
var r = a * b;
|
|
|
|
var lo = r & 0x3ffffff;
|
|
ncarry = (ncarry + ((r / 0x4000000) | 0)) | 0;
|
|
lo = (lo + rword) | 0;
|
|
rword = lo & 0x3ffffff;
|
|
ncarry = (ncarry + (lo >>> 26)) | 0;
|
|
|
|
hncarry += ncarry >>> 26;
|
|
ncarry &= 0x3ffffff;
|
|
}
|
|
out.words[k] = rword;
|
|
carry = ncarry;
|
|
ncarry = hncarry;
|
|
}
|
|
if (carry !== 0) {
|
|
out.words[k] = carry;
|
|
} else {
|
|
out.length--;
|
|
}
|
|
|
|
return out.strip();
|
|
}
|
|
|
|
function jumboMulTo (self, num, out) {
|
|
var fftm = new FFTM();
|
|
return fftm.mulp(self, num, out);
|
|
}
|
|
|
|
BN.prototype.mulTo = function mulTo (num, out) {
|
|
var res;
|
|
var len = this.length + num.length;
|
|
if (this.length === 10 && num.length === 10) {
|
|
res = comb10MulTo(this, num, out);
|
|
} else if (len < 63) {
|
|
res = smallMulTo(this, num, out);
|
|
} else if (len < 1024) {
|
|
res = bigMulTo(this, num, out);
|
|
} else {
|
|
res = jumboMulTo(this, num, out);
|
|
}
|
|
|
|
return res;
|
|
};
|
|
|
|
// Cooley-Tukey algorithm for FFT
|
|
// slightly revisited to rely on looping instead of recursion
|
|
|
|
function FFTM (x, y) {
|
|
this.x = x;
|
|
this.y = y;
|
|
}
|
|
|
|
FFTM.prototype.makeRBT = function makeRBT (N) {
|
|
var t = new Array(N);
|
|
var l = BN.prototype._countBits(N) - 1;
|
|
for (var i = 0; i < N; i++) {
|
|
t[i] = this.revBin(i, l, N);
|
|
}
|
|
|
|
return t;
|
|
};
|
|
|
|
// Returns binary-reversed representation of `x`
|
|
FFTM.prototype.revBin = function revBin (x, l, N) {
|
|
if (x === 0 || x === N - 1) return x;
|
|
|
|
var rb = 0;
|
|
for (var i = 0; i < l; i++) {
|
|
rb |= (x & 1) << (l - i - 1);
|
|
x >>= 1;
|
|
}
|
|
|
|
return rb;
|
|
};
|
|
|
|
// Performs "tweedling" phase, therefore 'emulating'
|
|
// behaviour of the recursive algorithm
|
|
FFTM.prototype.permute = function permute (rbt, rws, iws, rtws, itws, N) {
|
|
for (var i = 0; i < N; i++) {
|
|
rtws[i] = rws[rbt[i]];
|
|
itws[i] = iws[rbt[i]];
|
|
}
|
|
};
|
|
|
|
FFTM.prototype.transform = function transform (rws, iws, rtws, itws, N, rbt) {
|
|
this.permute(rbt, rws, iws, rtws, itws, N);
|
|
|
|
for (var s = 1; s < N; s <<= 1) {
|
|
var l = s << 1;
|
|
|
|
var rtwdf = Math.cos(2 * Math.PI / l);
|
|
var itwdf = Math.sin(2 * Math.PI / l);
|
|
|
|
for (var p = 0; p < N; p += l) {
|
|
var rtwdf_ = rtwdf;
|
|
var itwdf_ = itwdf;
|
|
|
|
for (var j = 0; j < s; j++) {
|
|
var re = rtws[p + j];
|
|
var ie = itws[p + j];
|
|
|
|
var ro = rtws[p + j + s];
|
|
var io = itws[p + j + s];
|
|
|
|
var rx = rtwdf_ * ro - itwdf_ * io;
|
|
|
|
io = rtwdf_ * io + itwdf_ * ro;
|
|
ro = rx;
|
|
|
|
rtws[p + j] = re + ro;
|
|
itws[p + j] = ie + io;
|
|
|
|
rtws[p + j + s] = re - ro;
|
|
itws[p + j + s] = ie - io;
|
|
|
|
/* jshint maxdepth : false */
|
|
if (j !== l) {
|
|
rx = rtwdf * rtwdf_ - itwdf * itwdf_;
|
|
|
|
itwdf_ = rtwdf * itwdf_ + itwdf * rtwdf_;
|
|
rtwdf_ = rx;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
FFTM.prototype.guessLen13b = function guessLen13b (n, m) {
|
|
var N = Math.max(m, n) | 1;
|
|
var odd = N & 1;
|
|
var i = 0;
|
|
for (N = N / 2 | 0; N; N = N >>> 1) {
|
|
i++;
|
|
}
|
|
|
|
return 1 << i + 1 + odd;
|
|
};
|
|
|
|
FFTM.prototype.conjugate = function conjugate (rws, iws, N) {
|
|
if (N <= 1) return;
|
|
|
|
for (var i = 0; i < N / 2; i++) {
|
|
var t = rws[i];
|
|
|
|
rws[i] = rws[N - i - 1];
|
|
rws[N - i - 1] = t;
|
|
|
|
t = iws[i];
|
|
|
|
iws[i] = -iws[N - i - 1];
|
|
iws[N - i - 1] = -t;
|
|
}
|
|
};
|
|
|
|
FFTM.prototype.normalize13b = function normalize13b (ws, N) {
|
|
var carry = 0;
|
|
for (var i = 0; i < N / 2; i++) {
|
|
var w = Math.round(ws[2 * i + 1] / N) * 0x2000 +
|
|
Math.round(ws[2 * i] / N) +
|
|
carry;
|
|
|
|
ws[i] = w & 0x3ffffff;
|
|
|
|
if (w < 0x4000000) {
|
|
carry = 0;
|
|
} else {
|
|
carry = w / 0x4000000 | 0;
|
|
}
|
|
}
|
|
|
|
return ws;
|
|
};
|
|
|
|
FFTM.prototype.convert13b = function convert13b (ws, len, rws, N) {
|
|
var carry = 0;
|
|
for (var i = 0; i < len; i++) {
|
|
carry = carry + (ws[i] | 0);
|
|
|
|
rws[2 * i] = carry & 0x1fff; carry = carry >>> 13;
|
|
rws[2 * i + 1] = carry & 0x1fff; carry = carry >>> 13;
|
|
}
|
|
|
|
// Pad with zeroes
|
|
for (i = 2 * len; i < N; ++i) {
|
|
rws[i] = 0;
|
|
}
|
|
|
|
assert(carry === 0);
|
|
assert((carry & ~0x1fff) === 0);
|
|
};
|
|
|
|
FFTM.prototype.stub = function stub (N) {
|
|
var ph = new Array(N);
|
|
for (var i = 0; i < N; i++) {
|
|
ph[i] = 0;
|
|
}
|
|
|
|
return ph;
|
|
};
|
|
|
|
FFTM.prototype.mulp = function mulp (x, y, out) {
|
|
var N = 2 * this.guessLen13b(x.length, y.length);
|
|
|
|
var rbt = this.makeRBT(N);
|
|
|
|
var _ = this.stub(N);
|
|
|
|
var rws = new Array(N);
|
|
var rwst = new Array(N);
|
|
var iwst = new Array(N);
|
|
|
|
var nrws = new Array(N);
|
|
var nrwst = new Array(N);
|
|
var niwst = new Array(N);
|
|
|
|
var rmws = out.words;
|
|
rmws.length = N;
|
|
|
|
this.convert13b(x.words, x.length, rws, N);
|
|
this.convert13b(y.words, y.length, nrws, N);
|
|
|
|
this.transform(rws, _, rwst, iwst, N, rbt);
|
|
this.transform(nrws, _, nrwst, niwst, N, rbt);
|
|
|
|
for (var i = 0; i < N; i++) {
|
|
var rx = rwst[i] * nrwst[i] - iwst[i] * niwst[i];
|
|
iwst[i] = rwst[i] * niwst[i] + iwst[i] * nrwst[i];
|
|
rwst[i] = rx;
|
|
}
|
|
|
|
this.conjugate(rwst, iwst, N);
|
|
this.transform(rwst, iwst, rmws, _, N, rbt);
|
|
this.conjugate(rmws, _, N);
|
|
this.normalize13b(rmws, N);
|
|
|
|
out.negative = x.negative ^ y.negative;
|
|
out.length = x.length + y.length;
|
|
return out.strip();
|
|
};
|
|
|
|
// Multiply `this` by `num`
|
|
BN.prototype.mul = function mul (num) {
|
|
var out = new BN(null);
|
|
out.words = new Array(this.length + num.length);
|
|
return this.mulTo(num, out);
|
|
};
|
|
|
|
// Multiply employing FFT
|
|
BN.prototype.mulf = function mulf (num) {
|
|
var out = new BN(null);
|
|
out.words = new Array(this.length + num.length);
|
|
return jumboMulTo(this, num, out);
|
|
};
|
|
|
|
// In-place Multiplication
|
|
BN.prototype.imul = function imul (num) {
|
|
return this.clone().mulTo(num, this);
|
|
};
|
|
|
|
BN.prototype.imuln = function imuln (num) {
|
|
assert(typeof num === 'number');
|
|
assert(num < 0x4000000);
|
|
|
|
// Carry
|
|
var carry = 0;
|
|
for (var i = 0; i < this.length; i++) {
|
|
var w = (this.words[i] | 0) * num;
|
|
var lo = (w & 0x3ffffff) + (carry & 0x3ffffff);
|
|
carry >>= 26;
|
|
carry += (w / 0x4000000) | 0;
|
|
// NOTE: lo is 27bit maximum
|
|
carry += lo >>> 26;
|
|
this.words[i] = lo & 0x3ffffff;
|
|
}
|
|
|
|
if (carry !== 0) {
|
|
this.words[i] = carry;
|
|
this.length++;
|
|
}
|
|
|
|
return this;
|
|
};
|
|
|
|
BN.prototype.muln = function muln (num) {
|
|
return this.clone().imuln(num);
|
|
};
|
|
|
|
// `this` * `this`
|
|
BN.prototype.sqr = function sqr () {
|
|
return this.mul(this);
|
|
};
|
|
|
|
// `this` * `this` in-place
|
|
BN.prototype.isqr = function isqr () {
|
|
return this.imul(this.clone());
|
|
};
|
|
|
|
// Math.pow(`this`, `num`)
|
|
BN.prototype.pow = function pow (num) {
|
|
var w = toBitArray(num);
|
|
if (w.length === 0) return new BN(1);
|
|
|
|
// Skip leading zeroes
|
|
var res = this;
|
|
for (var i = 0; i < w.length; i++, res = res.sqr()) {
|
|
if (w[i] !== 0) break;
|
|
}
|
|
|
|
if (++i < w.length) {
|
|
for (var q = res.sqr(); i < w.length; i++, q = q.sqr()) {
|
|
if (w[i] === 0) continue;
|
|
|
|
res = res.mul(q);
|
|
}
|
|
}
|
|
|
|
return res;
|
|
};
|
|
|
|
// Shift-left in-place
|
|
BN.prototype.iushln = function iushln (bits) {
|
|
assert(typeof bits === 'number' && bits >= 0);
|
|
var r = bits % 26;
|
|
var s = (bits - r) / 26;
|
|
var carryMask = (0x3ffffff >>> (26 - r)) << (26 - r);
|
|
var i;
|
|
|
|
if (r !== 0) {
|
|
var carry = 0;
|
|
|
|
for (i = 0; i < this.length; i++) {
|
|
var newCarry = this.words[i] & carryMask;
|
|
var c = ((this.words[i] | 0) - newCarry) << r;
|
|
this.words[i] = c | carry;
|
|
carry = newCarry >>> (26 - r);
|
|
}
|
|
|
|
if (carry) {
|
|
this.words[i] = carry;
|
|
this.length++;
|
|
}
|
|
}
|
|
|
|
if (s !== 0) {
|
|
for (i = this.length - 1; i >= 0; i--) {
|
|
this.words[i + s] = this.words[i];
|
|
}
|
|
|
|
for (i = 0; i < s; i++) {
|
|
this.words[i] = 0;
|
|
}
|
|
|
|
this.length += s;
|
|
}
|
|
|
|
return this.strip();
|
|
};
|
|
|
|
BN.prototype.ishln = function ishln (bits) {
|
|
// TODO(indutny): implement me
|
|
assert(this.negative === 0);
|
|
return this.iushln(bits);
|
|
};
|
|
|
|
// Shift-right in-place
|
|
// NOTE: `hint` is a lowest bit before trailing zeroes
|
|
// NOTE: if `extended` is present - it will be filled with destroyed bits
|
|
BN.prototype.iushrn = function iushrn (bits, hint, extended) {
|
|
assert(typeof bits === 'number' && bits >= 0);
|
|
var h;
|
|
if (hint) {
|
|
h = (hint - (hint % 26)) / 26;
|
|
} else {
|
|
h = 0;
|
|
}
|
|
|
|
var r = bits % 26;
|
|
var s = Math.min((bits - r) / 26, this.length);
|
|
var mask = 0x3ffffff ^ ((0x3ffffff >>> r) << r);
|
|
var maskedWords = extended;
|
|
|
|
h -= s;
|
|
h = Math.max(0, h);
|
|
|
|
// Extended mode, copy masked part
|
|
if (maskedWords) {
|
|
for (var i = 0; i < s; i++) {
|
|
maskedWords.words[i] = this.words[i];
|
|
}
|
|
maskedWords.length = s;
|
|
}
|
|
|
|
if (s === 0) {
|
|
// No-op, we should not move anything at all
|
|
} else if (this.length > s) {
|
|
this.length -= s;
|
|
for (i = 0; i < this.length; i++) {
|
|
this.words[i] = this.words[i + s];
|
|
}
|
|
} else {
|
|
this.words[0] = 0;
|
|
this.length = 1;
|
|
}
|
|
|
|
var carry = 0;
|
|
for (i = this.length - 1; i >= 0 && (carry !== 0 || i >= h); i--) {
|
|
var word = this.words[i] | 0;
|
|
this.words[i] = (carry << (26 - r)) | (word >>> r);
|
|
carry = word & mask;
|
|
}
|
|
|
|
// Push carried bits as a mask
|
|
if (maskedWords && carry !== 0) {
|
|
maskedWords.words[maskedWords.length++] = carry;
|
|
}
|
|
|
|
if (this.length === 0) {
|
|
this.words[0] = 0;
|
|
this.length = 1;
|
|
}
|
|
|
|
return this.strip();
|
|
};
|
|
|
|
BN.prototype.ishrn = function ishrn (bits, hint, extended) {
|
|
// TODO(indutny): implement me
|
|
assert(this.negative === 0);
|
|
return this.iushrn(bits, hint, extended);
|
|
};
|
|
|
|
// Shift-left
|
|
BN.prototype.shln = function shln (bits) {
|
|
return this.clone().ishln(bits);
|
|
};
|
|
|
|
BN.prototype.ushln = function ushln (bits) {
|
|
return this.clone().iushln(bits);
|
|
};
|
|
|
|
// Shift-right
|
|
BN.prototype.shrn = function shrn (bits) {
|
|
return this.clone().ishrn(bits);
|
|
};
|
|
|
|
BN.prototype.ushrn = function ushrn (bits) {
|
|
return this.clone().iushrn(bits);
|
|
};
|
|
|
|
// Test if n bit is set
|
|
BN.prototype.testn = function testn (bit) {
|
|
assert(typeof bit === 'number' && bit >= 0);
|
|
var r = bit % 26;
|
|
var s = (bit - r) / 26;
|
|
var q = 1 << r;
|
|
|
|
// Fast case: bit is much higher than all existing words
|
|
if (this.length <= s) return false;
|
|
|
|
// Check bit and return
|
|
var w = this.words[s];
|
|
|
|
return !!(w & q);
|
|
};
|
|
|
|
// Return only lowers bits of number (in-place)
|
|
BN.prototype.imaskn = function imaskn (bits) {
|
|
assert(typeof bits === 'number' && bits >= 0);
|
|
var r = bits % 26;
|
|
var s = (bits - r) / 26;
|
|
|
|
assert(this.negative === 0, 'imaskn works only with positive numbers');
|
|
|
|
if (this.length <= s) {
|
|
return this;
|
|
}
|
|
|
|
if (r !== 0) {
|
|
s++;
|
|
}
|
|
this.length = Math.min(s, this.length);
|
|
|
|
if (r !== 0) {
|
|
var mask = 0x3ffffff ^ ((0x3ffffff >>> r) << r);
|
|
this.words[this.length - 1] &= mask;
|
|
}
|
|
|
|
return this.strip();
|
|
};
|
|
|
|
// Return only lowers bits of number
|
|
BN.prototype.maskn = function maskn (bits) {
|
|
return this.clone().imaskn(bits);
|
|
};
|
|
|
|
// Add plain number `num` to `this`
|
|
BN.prototype.iaddn = function iaddn (num) {
|
|
assert(typeof num === 'number');
|
|
assert(num < 0x4000000);
|
|
if (num < 0) return this.isubn(-num);
|
|
|
|
// Possible sign change
|
|
if (this.negative !== 0) {
|
|
if (this.length === 1 && (this.words[0] | 0) < num) {
|
|
this.words[0] = num - (this.words[0] | 0);
|
|
this.negative = 0;
|
|
return this;
|
|
}
|
|
|
|
this.negative = 0;
|
|
this.isubn(num);
|
|
this.negative = 1;
|
|
return this;
|
|
}
|
|
|
|
// Add without checks
|
|
return this._iaddn(num);
|
|
};
|
|
|
|
BN.prototype._iaddn = function _iaddn (num) {
|
|
this.words[0] += num;
|
|
|
|
// Carry
|
|
for (var i = 0; i < this.length && this.words[i] >= 0x4000000; i++) {
|
|
this.words[i] -= 0x4000000;
|
|
if (i === this.length - 1) {
|
|
this.words[i + 1] = 1;
|
|
} else {
|
|
this.words[i + 1]++;
|
|
}
|
|
}
|
|
this.length = Math.max(this.length, i + 1);
|
|
|
|
return this;
|
|
};
|
|
|
|
// Subtract plain number `num` from `this`
|
|
BN.prototype.isubn = function isubn (num) {
|
|
assert(typeof num === 'number');
|
|
assert(num < 0x4000000);
|
|
if (num < 0) return this.iaddn(-num);
|
|
|
|
if (this.negative !== 0) {
|
|
this.negative = 0;
|
|
this.iaddn(num);
|
|
this.negative = 1;
|
|
return this;
|
|
}
|
|
|
|
this.words[0] -= num;
|
|
|
|
if (this.length === 1 && this.words[0] < 0) {
|
|
this.words[0] = -this.words[0];
|
|
this.negative = 1;
|
|
} else {
|
|
// Carry
|
|
for (var i = 0; i < this.length && this.words[i] < 0; i++) {
|
|
this.words[i] += 0x4000000;
|
|
this.words[i + 1] -= 1;
|
|
}
|
|
}
|
|
|
|
return this.strip();
|
|
};
|
|
|
|
BN.prototype.addn = function addn (num) {
|
|
return this.clone().iaddn(num);
|
|
};
|
|
|
|
BN.prototype.subn = function subn (num) {
|
|
return this.clone().isubn(num);
|
|
};
|
|
|
|
BN.prototype.iabs = function iabs () {
|
|
this.negative = 0;
|
|
|
|
return this;
|
|
};
|
|
|
|
BN.prototype.abs = function abs () {
|
|
return this.clone().iabs();
|
|
};
|
|
|
|
BN.prototype._ishlnsubmul = function _ishlnsubmul (num, mul, shift) {
|
|
var len = num.length + shift;
|
|
var i;
|
|
|
|
this._expand(len);
|
|
|
|
var w;
|
|
var carry = 0;
|
|
for (i = 0; i < num.length; i++) {
|
|
w = (this.words[i + shift] | 0) + carry;
|
|
var right = (num.words[i] | 0) * mul;
|
|
w -= right & 0x3ffffff;
|
|
carry = (w >> 26) - ((right / 0x4000000) | 0);
|
|
this.words[i + shift] = w & 0x3ffffff;
|
|
}
|
|
for (; i < this.length - shift; i++) {
|
|
w = (this.words[i + shift] | 0) + carry;
|
|
carry = w >> 26;
|
|
this.words[i + shift] = w & 0x3ffffff;
|
|
}
|
|
|
|
if (carry === 0) return this.strip();
|
|
|
|
// Subtraction overflow
|
|
assert(carry === -1);
|
|
carry = 0;
|
|
for (i = 0; i < this.length; i++) {
|
|
w = -(this.words[i] | 0) + carry;
|
|
carry = w >> 26;
|
|
this.words[i] = w & 0x3ffffff;
|
|
}
|
|
this.negative = 1;
|
|
|
|
return this.strip();
|
|
};
|
|
|
|
BN.prototype._wordDiv = function _wordDiv (num, mode) {
|
|
var shift = this.length - num.length;
|
|
|
|
var a = this.clone();
|
|
var b = num;
|
|
|
|
// Normalize
|
|
var bhi = b.words[b.length - 1] | 0;
|
|
var bhiBits = this._countBits(bhi);
|
|
shift = 26 - bhiBits;
|
|
if (shift !== 0) {
|
|
b = b.ushln(shift);
|
|
a.iushln(shift);
|
|
bhi = b.words[b.length - 1] | 0;
|
|
}
|
|
|
|
// Initialize quotient
|
|
var m = a.length - b.length;
|
|
var q;
|
|
|
|
if (mode !== 'mod') {
|
|
q = new BN(null);
|
|
q.length = m + 1;
|
|
q.words = new Array(q.length);
|
|
for (var i = 0; i < q.length; i++) {
|
|
q.words[i] = 0;
|
|
}
|
|
}
|
|
|
|
var diff = a.clone()._ishlnsubmul(b, 1, m);
|
|
if (diff.negative === 0) {
|
|
a = diff;
|
|
if (q) {
|
|
q.words[m] = 1;
|
|
}
|
|
}
|
|
|
|
for (var j = m - 1; j >= 0; j--) {
|
|
var qj = (a.words[b.length + j] | 0) * 0x4000000 +
|
|
(a.words[b.length + j - 1] | 0);
|
|
|
|
// NOTE: (qj / bhi) is (0x3ffffff * 0x4000000 + 0x3ffffff) / 0x2000000 max
|
|
// (0x7ffffff)
|
|
qj = Math.min((qj / bhi) | 0, 0x3ffffff);
|
|
|
|
a._ishlnsubmul(b, qj, j);
|
|
while (a.negative !== 0) {
|
|
qj--;
|
|
a.negative = 0;
|
|
a._ishlnsubmul(b, 1, j);
|
|
if (!a.isZero()) {
|
|
a.negative ^= 1;
|
|
}
|
|
}
|
|
if (q) {
|
|
q.words[j] = qj;
|
|
}
|
|
}
|
|
if (q) {
|
|
q.strip();
|
|
}
|
|
a.strip();
|
|
|
|
// Denormalize
|
|
if (mode !== 'div' && shift !== 0) {
|
|
a.iushrn(shift);
|
|
}
|
|
|
|
return {
|
|
div: q || null,
|
|
mod: a
|
|
};
|
|
};
|
|
|
|
// NOTE: 1) `mode` can be set to `mod` to request mod only,
|
|
// to `div` to request div only, or be absent to
|
|
// request both div & mod
|
|
// 2) `positive` is true if unsigned mod is requested
|
|
BN.prototype.divmod = function divmod (num, mode, positive) {
|
|
assert(!num.isZero());
|
|
|
|
if (this.isZero()) {
|
|
return {
|
|
div: new BN(0),
|
|
mod: new BN(0)
|
|
};
|
|
}
|
|
|
|
var div, mod, res;
|
|
if (this.negative !== 0 && num.negative === 0) {
|
|
res = this.neg().divmod(num, mode);
|
|
|
|
if (mode !== 'mod') {
|
|
div = res.div.neg();
|
|
}
|
|
|
|
if (mode !== 'div') {
|
|
mod = res.mod.neg();
|
|
if (positive && mod.negative !== 0) {
|
|
mod.iadd(num);
|
|
}
|
|
}
|
|
|
|
return {
|
|
div: div,
|
|
mod: mod
|
|
};
|
|
}
|
|
|
|
if (this.negative === 0 && num.negative !== 0) {
|
|
res = this.divmod(num.neg(), mode);
|
|
|
|
if (mode !== 'mod') {
|
|
div = res.div.neg();
|
|
}
|
|
|
|
return {
|
|
div: div,
|
|
mod: res.mod
|
|
};
|
|
}
|
|
|
|
if ((this.negative & num.negative) !== 0) {
|
|
res = this.neg().divmod(num.neg(), mode);
|
|
|
|
if (mode !== 'div') {
|
|
mod = res.mod.neg();
|
|
if (positive && mod.negative !== 0) {
|
|
mod.isub(num);
|
|
}
|
|
}
|
|
|
|
return {
|
|
div: res.div,
|
|
mod: mod
|
|
};
|
|
}
|
|
|
|
// Both numbers are positive at this point
|
|
|
|
// Strip both numbers to approximate shift value
|
|
if (num.length > this.length || this.cmp(num) < 0) {
|
|
return {
|
|
div: new BN(0),
|
|
mod: this
|
|
};
|
|
}
|
|
|
|
// Very short reduction
|
|
if (num.length === 1) {
|
|
if (mode === 'div') {
|
|
return {
|
|
div: this.divn(num.words[0]),
|
|
mod: null
|
|
};
|
|
}
|
|
|
|
if (mode === 'mod') {
|
|
return {
|
|
div: null,
|
|
mod: new BN(this.modn(num.words[0]))
|
|
};
|
|
}
|
|
|
|
return {
|
|
div: this.divn(num.words[0]),
|
|
mod: new BN(this.modn(num.words[0]))
|
|
};
|
|
}
|
|
|
|
return this._wordDiv(num, mode);
|
|
};
|
|
|
|
// Find `this` / `num`
|
|
BN.prototype.div = function div (num) {
|
|
return this.divmod(num, 'div', false).div;
|
|
};
|
|
|
|
// Find `this` % `num`
|
|
BN.prototype.mod = function mod (num) {
|
|
return this.divmod(num, 'mod', false).mod;
|
|
};
|
|
|
|
BN.prototype.umod = function umod (num) {
|
|
return this.divmod(num, 'mod', true).mod;
|
|
};
|
|
|
|
// Find Round(`this` / `num`)
|
|
BN.prototype.divRound = function divRound (num) {
|
|
var dm = this.divmod(num);
|
|
|
|
// Fast case - exact division
|
|
if (dm.mod.isZero()) return dm.div;
|
|
|
|
var mod = dm.div.negative !== 0 ? dm.mod.isub(num) : dm.mod;
|
|
|
|
var half = num.ushrn(1);
|
|
var r2 = num.andln(1);
|
|
var cmp = mod.cmp(half);
|
|
|
|
// Round down
|
|
if (cmp < 0 || r2 === 1 && cmp === 0) return dm.div;
|
|
|
|
// Round up
|
|
return dm.div.negative !== 0 ? dm.div.isubn(1) : dm.div.iaddn(1);
|
|
};
|
|
|
|
BN.prototype.modn = function modn (num) {
|
|
assert(num <= 0x3ffffff);
|
|
var p = (1 << 26) % num;
|
|
|
|
var acc = 0;
|
|
for (var i = this.length - 1; i >= 0; i--) {
|
|
acc = (p * acc + (this.words[i] | 0)) % num;
|
|
}
|
|
|
|
return acc;
|
|
};
|
|
|
|
// In-place division by number
|
|
BN.prototype.idivn = function idivn (num) {
|
|
assert(num <= 0x3ffffff);
|
|
|
|
var carry = 0;
|
|
for (var i = this.length - 1; i >= 0; i--) {
|
|
var w = (this.words[i] | 0) + carry * 0x4000000;
|
|
this.words[i] = (w / num) | 0;
|
|
carry = w % num;
|
|
}
|
|
|
|
return this.strip();
|
|
};
|
|
|
|
BN.prototype.divn = function divn (num) {
|
|
return this.clone().idivn(num);
|
|
};
|
|
|
|
BN.prototype.egcd = function egcd (p) {
|
|
assert(p.negative === 0);
|
|
assert(!p.isZero());
|
|
|
|
var x = this;
|
|
var y = p.clone();
|
|
|
|
if (x.negative !== 0) {
|
|
x = x.umod(p);
|
|
} else {
|
|
x = x.clone();
|
|
}
|
|
|
|
// A * x + B * y = x
|
|
var A = new BN(1);
|
|
var B = new BN(0);
|
|
|
|
// C * x + D * y = y
|
|
var C = new BN(0);
|
|
var D = new BN(1);
|
|
|
|
var g = 0;
|
|
|
|
while (x.isEven() && y.isEven()) {
|
|
x.iushrn(1);
|
|
y.iushrn(1);
|
|
++g;
|
|
}
|
|
|
|
var yp = y.clone();
|
|
var xp = x.clone();
|
|
|
|
while (!x.isZero()) {
|
|
for (var i = 0, im = 1; (x.words[0] & im) === 0 && i < 26; ++i, im <<= 1);
|
|
if (i > 0) {
|
|
x.iushrn(i);
|
|
while (i-- > 0) {
|
|
if (A.isOdd() || B.isOdd()) {
|
|
A.iadd(yp);
|
|
B.isub(xp);
|
|
}
|
|
|
|
A.iushrn(1);
|
|
B.iushrn(1);
|
|
}
|
|
}
|
|
|
|
for (var j = 0, jm = 1; (y.words[0] & jm) === 0 && j < 26; ++j, jm <<= 1);
|
|
if (j > 0) {
|
|
y.iushrn(j);
|
|
while (j-- > 0) {
|
|
if (C.isOdd() || D.isOdd()) {
|
|
C.iadd(yp);
|
|
D.isub(xp);
|
|
}
|
|
|
|
C.iushrn(1);
|
|
D.iushrn(1);
|
|
}
|
|
}
|
|
|
|
if (x.cmp(y) >= 0) {
|
|
x.isub(y);
|
|
A.isub(C);
|
|
B.isub(D);
|
|
} else {
|
|
y.isub(x);
|
|
C.isub(A);
|
|
D.isub(B);
|
|
}
|
|
}
|
|
|
|
return {
|
|
a: C,
|
|
b: D,
|
|
gcd: y.iushln(g)
|
|
};
|
|
};
|
|
|
|
// This is reduced incarnation of the binary EEA
|
|
// above, designated to invert members of the
|
|
// _prime_ fields F(p) at a maximal speed
|
|
BN.prototype._invmp = function _invmp (p) {
|
|
assert(p.negative === 0);
|
|
assert(!p.isZero());
|
|
|
|
var a = this;
|
|
var b = p.clone();
|
|
|
|
if (a.negative !== 0) {
|
|
a = a.umod(p);
|
|
} else {
|
|
a = a.clone();
|
|
}
|
|
|
|
var x1 = new BN(1);
|
|
var x2 = new BN(0);
|
|
|
|
var delta = b.clone();
|
|
|
|
while (a.cmpn(1) > 0 && b.cmpn(1) > 0) {
|
|
for (var i = 0, im = 1; (a.words[0] & im) === 0 && i < 26; ++i, im <<= 1);
|
|
if (i > 0) {
|
|
a.iushrn(i);
|
|
while (i-- > 0) {
|
|
if (x1.isOdd()) {
|
|
x1.iadd(delta);
|
|
}
|
|
|
|
x1.iushrn(1);
|
|
}
|
|
}
|
|
|
|
for (var j = 0, jm = 1; (b.words[0] & jm) === 0 && j < 26; ++j, jm <<= 1);
|
|
if (j > 0) {
|
|
b.iushrn(j);
|
|
while (j-- > 0) {
|
|
if (x2.isOdd()) {
|
|
x2.iadd(delta);
|
|
}
|
|
|
|
x2.iushrn(1);
|
|
}
|
|
}
|
|
|
|
if (a.cmp(b) >= 0) {
|
|
a.isub(b);
|
|
x1.isub(x2);
|
|
} else {
|
|
b.isub(a);
|
|
x2.isub(x1);
|
|
}
|
|
}
|
|
|
|
var res;
|
|
if (a.cmpn(1) === 0) {
|
|
res = x1;
|
|
} else {
|
|
res = x2;
|
|
}
|
|
|
|
if (res.cmpn(0) < 0) {
|
|
res.iadd(p);
|
|
}
|
|
|
|
return res;
|
|
};
|
|
|
|
BN.prototype.gcd = function gcd (num) {
|
|
if (this.isZero()) return num.abs();
|
|
if (num.isZero()) return this.abs();
|
|
|
|
var a = this.clone();
|
|
var b = num.clone();
|
|
a.negative = 0;
|
|
b.negative = 0;
|
|
|
|
// Remove common factor of two
|
|
for (var shift = 0; a.isEven() && b.isEven(); shift++) {
|
|
a.iushrn(1);
|
|
b.iushrn(1);
|
|
}
|
|
|
|
do {
|
|
while (a.isEven()) {
|
|
a.iushrn(1);
|
|
}
|
|
while (b.isEven()) {
|
|
b.iushrn(1);
|
|
}
|
|
|
|
var r = a.cmp(b);
|
|
if (r < 0) {
|
|
// Swap `a` and `b` to make `a` always bigger than `b`
|
|
var t = a;
|
|
a = b;
|
|
b = t;
|
|
} else if (r === 0 || b.cmpn(1) === 0) {
|
|
break;
|
|
}
|
|
|
|
a.isub(b);
|
|
} while (true);
|
|
|
|
return b.iushln(shift);
|
|
};
|
|
|
|
// Invert number in the field F(num)
|
|
BN.prototype.invm = function invm (num) {
|
|
return this.egcd(num).a.umod(num);
|
|
};
|
|
|
|
BN.prototype.isEven = function isEven () {
|
|
return (this.words[0] & 1) === 0;
|
|
};
|
|
|
|
BN.prototype.isOdd = function isOdd () {
|
|
return (this.words[0] & 1) === 1;
|
|
};
|
|
|
|
// And first word and num
|
|
BN.prototype.andln = function andln (num) {
|
|
return this.words[0] & num;
|
|
};
|
|
|
|
// Increment at the bit position in-line
|
|
BN.prototype.bincn = function bincn (bit) {
|
|
assert(typeof bit === 'number');
|
|
var r = bit % 26;
|
|
var s = (bit - r) / 26;
|
|
var q = 1 << r;
|
|
|
|
// Fast case: bit is much higher than all existing words
|
|
if (this.length <= s) {
|
|
this._expand(s + 1);
|
|
this.words[s] |= q;
|
|
return this;
|
|
}
|
|
|
|
// Add bit and propagate, if needed
|
|
var carry = q;
|
|
for (var i = s; carry !== 0 && i < this.length; i++) {
|
|
var w = this.words[i] | 0;
|
|
w += carry;
|
|
carry = w >>> 26;
|
|
w &= 0x3ffffff;
|
|
this.words[i] = w;
|
|
}
|
|
if (carry !== 0) {
|
|
this.words[i] = carry;
|
|
this.length++;
|
|
}
|
|
return this;
|
|
};
|
|
|
|
BN.prototype.isZero = function isZero () {
|
|
return this.length === 1 && this.words[0] === 0;
|
|
};
|
|
|
|
BN.prototype.cmpn = function cmpn (num) {
|
|
var negative = num < 0;
|
|
|
|
if (this.negative !== 0 && !negative) return -1;
|
|
if (this.negative === 0 && negative) return 1;
|
|
|
|
this.strip();
|
|
|
|
var res;
|
|
if (this.length > 1) {
|
|
res = 1;
|
|
} else {
|
|
if (negative) {
|
|
num = -num;
|
|
}
|
|
|
|
assert(num <= 0x3ffffff, 'Number is too big');
|
|
|
|
var w = this.words[0] | 0;
|
|
res = w === num ? 0 : w < num ? -1 : 1;
|
|
}
|
|
if (this.negative !== 0) return -res | 0;
|
|
return res;
|
|
};
|
|
|
|
// Compare two numbers and return:
|
|
// 1 - if `this` > `num`
|
|
// 0 - if `this` == `num`
|
|
// -1 - if `this` < `num`
|
|
BN.prototype.cmp = function cmp (num) {
|
|
if (this.negative !== 0 && num.negative === 0) return -1;
|
|
if (this.negative === 0 && num.negative !== 0) return 1;
|
|
|
|
var res = this.ucmp(num);
|
|
if (this.negative !== 0) return -res | 0;
|
|
return res;
|
|
};
|
|
|
|
// Unsigned comparison
|
|
BN.prototype.ucmp = function ucmp (num) {
|
|
// At this point both numbers have the same sign
|
|
if (this.length > num.length) return 1;
|
|
if (this.length < num.length) return -1;
|
|
|
|
var res = 0;
|
|
for (var i = this.length - 1; i >= 0; i--) {
|
|
var a = this.words[i] | 0;
|
|
var b = num.words[i] | 0;
|
|
|
|
if (a === b) continue;
|
|
if (a < b) {
|
|
res = -1;
|
|
} else if (a > b) {
|
|
res = 1;
|
|
}
|
|
break;
|
|
}
|
|
return res;
|
|
};
|
|
|
|
BN.prototype.gtn = function gtn (num) {
|
|
return this.cmpn(num) === 1;
|
|
};
|
|
|
|
BN.prototype.gt = function gt (num) {
|
|
return this.cmp(num) === 1;
|
|
};
|
|
|
|
BN.prototype.gten = function gten (num) {
|
|
return this.cmpn(num) >= 0;
|
|
};
|
|
|
|
BN.prototype.gte = function gte (num) {
|
|
return this.cmp(num) >= 0;
|
|
};
|
|
|
|
BN.prototype.ltn = function ltn (num) {
|
|
return this.cmpn(num) === -1;
|
|
};
|
|
|
|
BN.prototype.lt = function lt (num) {
|
|
return this.cmp(num) === -1;
|
|
};
|
|
|
|
BN.prototype.lten = function lten (num) {
|
|
return this.cmpn(num) <= 0;
|
|
};
|
|
|
|
BN.prototype.lte = function lte (num) {
|
|
return this.cmp(num) <= 0;
|
|
};
|
|
|
|
BN.prototype.eqn = function eqn (num) {
|
|
return this.cmpn(num) === 0;
|
|
};
|
|
|
|
BN.prototype.eq = function eq (num) {
|
|
return this.cmp(num) === 0;
|
|
};
|
|
|
|
//
|
|
// A reduce context, could be using montgomery or something better, depending
|
|
// on the `m` itself.
|
|
//
|
|
BN.red = function red (num) {
|
|
return new Red(num);
|
|
};
|
|
|
|
BN.prototype.toRed = function toRed (ctx) {
|
|
assert(!this.red, 'Already a number in reduction context');
|
|
assert(this.negative === 0, 'red works only with positives');
|
|
return ctx.convertTo(this)._forceRed(ctx);
|
|
};
|
|
|
|
BN.prototype.fromRed = function fromRed () {
|
|
assert(this.red, 'fromRed works only with numbers in reduction context');
|
|
return this.red.convertFrom(this);
|
|
};
|
|
|
|
BN.prototype._forceRed = function _forceRed (ctx) {
|
|
this.red = ctx;
|
|
return this;
|
|
};
|
|
|
|
BN.prototype.forceRed = function forceRed (ctx) {
|
|
assert(!this.red, 'Already a number in reduction context');
|
|
return this._forceRed(ctx);
|
|
};
|
|
|
|
BN.prototype.redAdd = function redAdd (num) {
|
|
assert(this.red, 'redAdd works only with red numbers');
|
|
return this.red.add(this, num);
|
|
};
|
|
|
|
BN.prototype.redIAdd = function redIAdd (num) {
|
|
assert(this.red, 'redIAdd works only with red numbers');
|
|
return this.red.iadd(this, num);
|
|
};
|
|
|
|
BN.prototype.redSub = function redSub (num) {
|
|
assert(this.red, 'redSub works only with red numbers');
|
|
return this.red.sub(this, num);
|
|
};
|
|
|
|
BN.prototype.redISub = function redISub (num) {
|
|
assert(this.red, 'redISub works only with red numbers');
|
|
return this.red.isub(this, num);
|
|
};
|
|
|
|
BN.prototype.redShl = function redShl (num) {
|
|
assert(this.red, 'redShl works only with red numbers');
|
|
return this.red.shl(this, num);
|
|
};
|
|
|
|
BN.prototype.redMul = function redMul (num) {
|
|
assert(this.red, 'redMul works only with red numbers');
|
|
this.red._verify2(this, num);
|
|
return this.red.mul(this, num);
|
|
};
|
|
|
|
BN.prototype.redIMul = function redIMul (num) {
|
|
assert(this.red, 'redMul works only with red numbers');
|
|
this.red._verify2(this, num);
|
|
return this.red.imul(this, num);
|
|
};
|
|
|
|
BN.prototype.redSqr = function redSqr () {
|
|
assert(this.red, 'redSqr works only with red numbers');
|
|
this.red._verify1(this);
|
|
return this.red.sqr(this);
|
|
};
|
|
|
|
BN.prototype.redISqr = function redISqr () {
|
|
assert(this.red, 'redISqr works only with red numbers');
|
|
this.red._verify1(this);
|
|
return this.red.isqr(this);
|
|
};
|
|
|
|
// Square root over p
|
|
BN.prototype.redSqrt = function redSqrt () {
|
|
assert(this.red, 'redSqrt works only with red numbers');
|
|
this.red._verify1(this);
|
|
return this.red.sqrt(this);
|
|
};
|
|
|
|
BN.prototype.redInvm = function redInvm () {
|
|
assert(this.red, 'redInvm works only with red numbers');
|
|
this.red._verify1(this);
|
|
return this.red.invm(this);
|
|
};
|
|
|
|
// Return negative clone of `this` % `red modulo`
|
|
BN.prototype.redNeg = function redNeg () {
|
|
assert(this.red, 'redNeg works only with red numbers');
|
|
this.red._verify1(this);
|
|
return this.red.neg(this);
|
|
};
|
|
|
|
BN.prototype.redPow = function redPow (num) {
|
|
assert(this.red && !num.red, 'redPow(normalNum)');
|
|
this.red._verify1(this);
|
|
return this.red.pow(this, num);
|
|
};
|
|
|
|
// Prime numbers with efficient reduction
|
|
var primes = {
|
|
k256: null,
|
|
p224: null,
|
|
p192: null,
|
|
p25519: null
|
|
};
|
|
|
|
// Pseudo-Mersenne prime
|
|
function MPrime (name, p) {
|
|
// P = 2 ^ N - K
|
|
this.name = name;
|
|
this.p = new BN(p, 16);
|
|
this.n = this.p.bitLength();
|
|
this.k = new BN(1).iushln(this.n).isub(this.p);
|
|
|
|
this.tmp = this._tmp();
|
|
}
|
|
|
|
MPrime.prototype._tmp = function _tmp () {
|
|
var tmp = new BN(null);
|
|
tmp.words = new Array(Math.ceil(this.n / 13));
|
|
return tmp;
|
|
};
|
|
|
|
MPrime.prototype.ireduce = function ireduce (num) {
|
|
// Assumes that `num` is less than `P^2`
|
|
// num = HI * (2 ^ N - K) + HI * K + LO = HI * K + LO (mod P)
|
|
var r = num;
|
|
var rlen;
|
|
|
|
do {
|
|
this.split(r, this.tmp);
|
|
r = this.imulK(r);
|
|
r = r.iadd(this.tmp);
|
|
rlen = r.bitLength();
|
|
} while (rlen > this.n);
|
|
|
|
var cmp = rlen < this.n ? -1 : r.ucmp(this.p);
|
|
if (cmp === 0) {
|
|
r.words[0] = 0;
|
|
r.length = 1;
|
|
} else if (cmp > 0) {
|
|
r.isub(this.p);
|
|
} else {
|
|
r.strip();
|
|
}
|
|
|
|
return r;
|
|
};
|
|
|
|
MPrime.prototype.split = function split (input, out) {
|
|
input.iushrn(this.n, 0, out);
|
|
};
|
|
|
|
MPrime.prototype.imulK = function imulK (num) {
|
|
return num.imul(this.k);
|
|
};
|
|
|
|
function K256 () {
|
|
MPrime.call(
|
|
this,
|
|
'k256',
|
|
'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f');
|
|
}
|
|
inherits(K256, MPrime);
|
|
|
|
K256.prototype.split = function split (input, output) {
|
|
// 256 = 9 * 26 + 22
|
|
var mask = 0x3fffff;
|
|
|
|
var outLen = Math.min(input.length, 9);
|
|
for (var i = 0; i < outLen; i++) {
|
|
output.words[i] = input.words[i];
|
|
}
|
|
output.length = outLen;
|
|
|
|
if (input.length <= 9) {
|
|
input.words[0] = 0;
|
|
input.length = 1;
|
|
return;
|
|
}
|
|
|
|
// Shift by 9 limbs
|
|
var prev = input.words[9];
|
|
output.words[output.length++] = prev & mask;
|
|
|
|
for (i = 10; i < input.length; i++) {
|
|
var next = input.words[i] | 0;
|
|
input.words[i - 10] = ((next & mask) << 4) | (prev >>> 22);
|
|
prev = next;
|
|
}
|
|
prev >>>= 22;
|
|
input.words[i - 10] = prev;
|
|
if (prev === 0 && input.length > 10) {
|
|
input.length -= 10;
|
|
} else {
|
|
input.length -= 9;
|
|
}
|
|
};
|
|
|
|
K256.prototype.imulK = function imulK (num) {
|
|
// K = 0x1000003d1 = [ 0x40, 0x3d1 ]
|
|
num.words[num.length] = 0;
|
|
num.words[num.length + 1] = 0;
|
|
num.length += 2;
|
|
|
|
// bounded at: 0x40 * 0x3ffffff + 0x3d0 = 0x100000390
|
|
var lo = 0;
|
|
for (var i = 0; i < num.length; i++) {
|
|
var w = num.words[i] | 0;
|
|
lo += w * 0x3d1;
|
|
num.words[i] = lo & 0x3ffffff;
|
|
lo = w * 0x40 + ((lo / 0x4000000) | 0);
|
|
}
|
|
|
|
// Fast length reduction
|
|
if (num.words[num.length - 1] === 0) {
|
|
num.length--;
|
|
if (num.words[num.length - 1] === 0) {
|
|
num.length--;
|
|
}
|
|
}
|
|
return num;
|
|
};
|
|
|
|
function P224 () {
|
|
MPrime.call(
|
|
this,
|
|
'p224',
|
|
'ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001');
|
|
}
|
|
inherits(P224, MPrime);
|
|
|
|
function P192 () {
|
|
MPrime.call(
|
|
this,
|
|
'p192',
|
|
'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff');
|
|
}
|
|
inherits(P192, MPrime);
|
|
|
|
function P25519 () {
|
|
// 2 ^ 255 - 19
|
|
MPrime.call(
|
|
this,
|
|
'25519',
|
|
'7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed');
|
|
}
|
|
inherits(P25519, MPrime);
|
|
|
|
P25519.prototype.imulK = function imulK (num) {
|
|
// K = 0x13
|
|
var carry = 0;
|
|
for (var i = 0; i < num.length; i++) {
|
|
var hi = (num.words[i] | 0) * 0x13 + carry;
|
|
var lo = hi & 0x3ffffff;
|
|
hi >>>= 26;
|
|
|
|
num.words[i] = lo;
|
|
carry = hi;
|
|
}
|
|
if (carry !== 0) {
|
|
num.words[num.length++] = carry;
|
|
}
|
|
return num;
|
|
};
|
|
|
|
// Exported mostly for testing purposes, use plain name instead
|
|
BN._prime = function prime (name) {
|
|
// Cached version of prime
|
|
if (primes[name]) return primes[name];
|
|
|
|
var prime;
|
|
if (name === 'k256') {
|
|
prime = new K256();
|
|
} else if (name === 'p224') {
|
|
prime = new P224();
|
|
} else if (name === 'p192') {
|
|
prime = new P192();
|
|
} else if (name === 'p25519') {
|
|
prime = new P25519();
|
|
} else {
|
|
throw new Error('Unknown prime ' + name);
|
|
}
|
|
primes[name] = prime;
|
|
|
|
return prime;
|
|
};
|
|
|
|
//
|
|
// Base reduction engine
|
|
//
|
|
function Red (m) {
|
|
if (typeof m === 'string') {
|
|
var prime = BN._prime(m);
|
|
this.m = prime.p;
|
|
this.prime = prime;
|
|
} else {
|
|
assert(m.gtn(1), 'modulus must be greater than 1');
|
|
this.m = m;
|
|
this.prime = null;
|
|
}
|
|
}
|
|
|
|
Red.prototype._verify1 = function _verify1 (a) {
|
|
assert(a.negative === 0, 'red works only with positives');
|
|
assert(a.red, 'red works only with red numbers');
|
|
};
|
|
|
|
Red.prototype._verify2 = function _verify2 (a, b) {
|
|
assert((a.negative | b.negative) === 0, 'red works only with positives');
|
|
assert(a.red && a.red === b.red,
|
|
'red works only with red numbers');
|
|
};
|
|
|
|
Red.prototype.imod = function imod (a) {
|
|
if (this.prime) return this.prime.ireduce(a)._forceRed(this);
|
|
return a.umod(this.m)._forceRed(this);
|
|
};
|
|
|
|
Red.prototype.neg = function neg (a) {
|
|
if (a.isZero()) {
|
|
return a.clone();
|
|
}
|
|
|
|
return this.m.sub(a)._forceRed(this);
|
|
};
|
|
|
|
Red.prototype.add = function add (a, b) {
|
|
this._verify2(a, b);
|
|
|
|
var res = a.add(b);
|
|
if (res.cmp(this.m) >= 0) {
|
|
res.isub(this.m);
|
|
}
|
|
return res._forceRed(this);
|
|
};
|
|
|
|
Red.prototype.iadd = function iadd (a, b) {
|
|
this._verify2(a, b);
|
|
|
|
var res = a.iadd(b);
|
|
if (res.cmp(this.m) >= 0) {
|
|
res.isub(this.m);
|
|
}
|
|
return res;
|
|
};
|
|
|
|
Red.prototype.sub = function sub (a, b) {
|
|
this._verify2(a, b);
|
|
|
|
var res = a.sub(b);
|
|
if (res.cmpn(0) < 0) {
|
|
res.iadd(this.m);
|
|
}
|
|
return res._forceRed(this);
|
|
};
|
|
|
|
Red.prototype.isub = function isub (a, b) {
|
|
this._verify2(a, b);
|
|
|
|
var res = a.isub(b);
|
|
if (res.cmpn(0) < 0) {
|
|
res.iadd(this.m);
|
|
}
|
|
return res;
|
|
};
|
|
|
|
Red.prototype.shl = function shl (a, num) {
|
|
this._verify1(a);
|
|
return this.imod(a.ushln(num));
|
|
};
|
|
|
|
Red.prototype.imul = function imul (a, b) {
|
|
this._verify2(a, b);
|
|
return this.imod(a.imul(b));
|
|
};
|
|
|
|
Red.prototype.mul = function mul (a, b) {
|
|
this._verify2(a, b);
|
|
return this.imod(a.mul(b));
|
|
};
|
|
|
|
Red.prototype.isqr = function isqr (a) {
|
|
return this.imul(a, a.clone());
|
|
};
|
|
|
|
Red.prototype.sqr = function sqr (a) {
|
|
return this.mul(a, a);
|
|
};
|
|
|
|
Red.prototype.sqrt = function sqrt (a) {
|
|
if (a.isZero()) return a.clone();
|
|
|
|
var mod3 = this.m.andln(3);
|
|
assert(mod3 % 2 === 1);
|
|
|
|
// Fast case
|
|
if (mod3 === 3) {
|
|
var pow = this.m.add(new BN(1)).iushrn(2);
|
|
return this.pow(a, pow);
|
|
}
|
|
|
|
// Tonelli-Shanks algorithm (Totally unoptimized and slow)
|
|
//
|
|
// Find Q and S, that Q * 2 ^ S = (P - 1)
|
|
var q = this.m.subn(1);
|
|
var s = 0;
|
|
while (!q.isZero() && q.andln(1) === 0) {
|
|
s++;
|
|
q.iushrn(1);
|
|
}
|
|
assert(!q.isZero());
|
|
|
|
var one = new BN(1).toRed(this);
|
|
var nOne = one.redNeg();
|
|
|
|
// Find quadratic non-residue
|
|
// NOTE: Max is such because of generalized Riemann hypothesis.
|
|
var lpow = this.m.subn(1).iushrn(1);
|
|
var z = this.m.bitLength();
|
|
z = new BN(2 * z * z).toRed(this);
|
|
|
|
while (this.pow(z, lpow).cmp(nOne) !== 0) {
|
|
z.redIAdd(nOne);
|
|
}
|
|
|
|
var c = this.pow(z, q);
|
|
var r = this.pow(a, q.addn(1).iushrn(1));
|
|
var t = this.pow(a, q);
|
|
var m = s;
|
|
while (t.cmp(one) !== 0) {
|
|
var tmp = t;
|
|
for (var i = 0; tmp.cmp(one) !== 0; i++) {
|
|
tmp = tmp.redSqr();
|
|
}
|
|
assert(i < m);
|
|
var b = this.pow(c, new BN(1).iushln(m - i - 1));
|
|
|
|
r = r.redMul(b);
|
|
c = b.redSqr();
|
|
t = t.redMul(c);
|
|
m = i;
|
|
}
|
|
|
|
return r;
|
|
};
|
|
|
|
Red.prototype.invm = function invm (a) {
|
|
var inv = a._invmp(this.m);
|
|
if (inv.negative !== 0) {
|
|
inv.negative = 0;
|
|
return this.imod(inv).redNeg();
|
|
} else {
|
|
return this.imod(inv);
|
|
}
|
|
};
|
|
|
|
Red.prototype.pow = function pow (a, num) {
|
|
if (num.isZero()) return new BN(1).toRed(this);
|
|
if (num.cmpn(1) === 0) return a.clone();
|
|
|
|
var windowSize = 4;
|
|
var wnd = new Array(1 << windowSize);
|
|
wnd[0] = new BN(1).toRed(this);
|
|
wnd[1] = a;
|
|
for (var i = 2; i < wnd.length; i++) {
|
|
wnd[i] = this.mul(wnd[i - 1], a);
|
|
}
|
|
|
|
var res = wnd[0];
|
|
var current = 0;
|
|
var currentLen = 0;
|
|
var start = num.bitLength() % 26;
|
|
if (start === 0) {
|
|
start = 26;
|
|
}
|
|
|
|
for (i = num.length - 1; i >= 0; i--) {
|
|
var word = num.words[i];
|
|
for (var j = start - 1; j >= 0; j--) {
|
|
var bit = (word >> j) & 1;
|
|
if (res !== wnd[0]) {
|
|
res = this.sqr(res);
|
|
}
|
|
|
|
if (bit === 0 && current === 0) {
|
|
currentLen = 0;
|
|
continue;
|
|
}
|
|
|
|
current <<= 1;
|
|
current |= bit;
|
|
currentLen++;
|
|
if (currentLen !== windowSize && (i !== 0 || j !== 0)) continue;
|
|
|
|
res = this.mul(res, wnd[current]);
|
|
currentLen = 0;
|
|
current = 0;
|
|
}
|
|
start = 26;
|
|
}
|
|
|
|
return res;
|
|
};
|
|
|
|
Red.prototype.convertTo = function convertTo (num) {
|
|
var r = num.umod(this.m);
|
|
|
|
return r === num ? r.clone() : r;
|
|
};
|
|
|
|
Red.prototype.convertFrom = function convertFrom (num) {
|
|
var res = num.clone();
|
|
res.red = null;
|
|
return res;
|
|
};
|
|
|
|
//
|
|
// Montgomery method engine
|
|
//
|
|
|
|
BN.mont = function mont (num) {
|
|
return new Mont(num);
|
|
};
|
|
|
|
function Mont (m) {
|
|
Red.call(this, m);
|
|
|
|
this.shift = this.m.bitLength();
|
|
if (this.shift % 26 !== 0) {
|
|
this.shift += 26 - (this.shift % 26);
|
|
}
|
|
|
|
this.r = new BN(1).iushln(this.shift);
|
|
this.r2 = this.imod(this.r.sqr());
|
|
this.rinv = this.r._invmp(this.m);
|
|
|
|
this.minv = this.rinv.mul(this.r).isubn(1).div(this.m);
|
|
this.minv = this.minv.umod(this.r);
|
|
this.minv = this.r.sub(this.minv);
|
|
}
|
|
inherits(Mont, Red);
|
|
|
|
Mont.prototype.convertTo = function convertTo (num) {
|
|
return this.imod(num.ushln(this.shift));
|
|
};
|
|
|
|
Mont.prototype.convertFrom = function convertFrom (num) {
|
|
var r = this.imod(num.mul(this.rinv));
|
|
r.red = null;
|
|
return r;
|
|
};
|
|
|
|
Mont.prototype.imul = function imul (a, b) {
|
|
if (a.isZero() || b.isZero()) {
|
|
a.words[0] = 0;
|
|
a.length = 1;
|
|
return a;
|
|
}
|
|
|
|
var t = a.imul(b);
|
|
var c = t.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m);
|
|
var u = t.isub(c).iushrn(this.shift);
|
|
var res = u;
|
|
|
|
if (u.cmp(this.m) >= 0) {
|
|
res = u.isub(this.m);
|
|
} else if (u.cmpn(0) < 0) {
|
|
res = u.iadd(this.m);
|
|
}
|
|
|
|
return res._forceRed(this);
|
|
};
|
|
|
|
Mont.prototype.mul = function mul (a, b) {
|
|
if (a.isZero() || b.isZero()) return new BN(0)._forceRed(this);
|
|
|
|
var t = a.mul(b);
|
|
var c = t.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m);
|
|
var u = t.isub(c).iushrn(this.shift);
|
|
var res = u;
|
|
if (u.cmp(this.m) >= 0) {
|
|
res = u.isub(this.m);
|
|
} else if (u.cmpn(0) < 0) {
|
|
res = u.iadd(this.m);
|
|
}
|
|
|
|
return res._forceRed(this);
|
|
};
|
|
|
|
Mont.prototype.invm = function invm (a) {
|
|
// (AR)^-1 * R^2 = (A^-1 * R^-1) * R^2 = A^-1 * R
|
|
var res = this.imod(a._invmp(this.m).mul(this.r2));
|
|
return res._forceRed(this);
|
|
};
|
|
})(typeof module === 'undefined' || module, this);
|
|
|
|
},{"buffer":5}],5:[function(require,module,exports){
|
|
|
|
},{}],6:[function(require,module,exports){
|
|
(function (process,global){
|
|
/**
|
|
* [js-sha3]{@link https://github.com/emn178/js-sha3}
|
|
*
|
|
* @version 0.5.7
|
|
* @author Chen, Yi-Cyuan [emn178@gmail.com]
|
|
* @copyright Chen, Yi-Cyuan 2015-2016
|
|
* @license MIT
|
|
*/
|
|
/*jslint bitwise: true */
|
|
(function () {
|
|
'use strict';
|
|
|
|
var root = typeof window === 'object' ? window : {};
|
|
var NODE_JS = !root.JS_SHA3_NO_NODE_JS && typeof process === 'object' && process.versions && process.versions.node;
|
|
if (NODE_JS) {
|
|
root = global;
|
|
}
|
|
var COMMON_JS = !root.JS_SHA3_NO_COMMON_JS && typeof module === 'object' && module.exports;
|
|
var HEX_CHARS = '0123456789abcdef'.split('');
|
|
var SHAKE_PADDING = [31, 7936, 2031616, 520093696];
|
|
var KECCAK_PADDING = [1, 256, 65536, 16777216];
|
|
var PADDING = [6, 1536, 393216, 100663296];
|
|
var SHIFT = [0, 8, 16, 24];
|
|
var RC = [1, 0, 32898, 0, 32906, 2147483648, 2147516416, 2147483648, 32907, 0, 2147483649,
|
|
0, 2147516545, 2147483648, 32777, 2147483648, 138, 0, 136, 0, 2147516425, 0,
|
|
2147483658, 0, 2147516555, 0, 139, 2147483648, 32905, 2147483648, 32771,
|
|
2147483648, 32770, 2147483648, 128, 2147483648, 32778, 0, 2147483658, 2147483648,
|
|
2147516545, 2147483648, 32896, 2147483648, 2147483649, 0, 2147516424, 2147483648];
|
|
var BITS = [224, 256, 384, 512];
|
|
var SHAKE_BITS = [128, 256];
|
|
var OUTPUT_TYPES = ['hex', 'buffer', 'arrayBuffer', 'array'];
|
|
|
|
var createOutputMethod = function (bits, padding, outputType) {
|
|
return function (message) {
|
|
return new Keccak(bits, padding, bits).update(message)[outputType]();
|
|
};
|
|
};
|
|
|
|
var createShakeOutputMethod = function (bits, padding, outputType) {
|
|
return function (message, outputBits) {
|
|
return new Keccak(bits, padding, outputBits).update(message)[outputType]();
|
|
};
|
|
};
|
|
|
|
var createMethod = function (bits, padding) {
|
|
var method = createOutputMethod(bits, padding, 'hex');
|
|
method.create = function () {
|
|
return new Keccak(bits, padding, bits);
|
|
};
|
|
method.update = function (message) {
|
|
return method.create().update(message);
|
|
};
|
|
for (var i = 0; i < OUTPUT_TYPES.length; ++i) {
|
|
var type = OUTPUT_TYPES[i];
|
|
method[type] = createOutputMethod(bits, padding, type);
|
|
}
|
|
return method;
|
|
};
|
|
|
|
var createShakeMethod = function (bits, padding) {
|
|
var method = createShakeOutputMethod(bits, padding, 'hex');
|
|
method.create = function (outputBits) {
|
|
return new Keccak(bits, padding, outputBits);
|
|
};
|
|
method.update = function (message, outputBits) {
|
|
return method.create(outputBits).update(message);
|
|
};
|
|
for (var i = 0; i < OUTPUT_TYPES.length; ++i) {
|
|
var type = OUTPUT_TYPES[i];
|
|
method[type] = createShakeOutputMethod(bits, padding, type);
|
|
}
|
|
return method;
|
|
};
|
|
|
|
var algorithms = [
|
|
{name: 'keccak', padding: KECCAK_PADDING, bits: BITS, createMethod: createMethod},
|
|
{name: 'sha3', padding: PADDING, bits: BITS, createMethod: createMethod},
|
|
{name: 'shake', padding: SHAKE_PADDING, bits: SHAKE_BITS, createMethod: createShakeMethod}
|
|
];
|
|
|
|
var methods = {}, methodNames = [];
|
|
|
|
for (var i = 0; i < algorithms.length; ++i) {
|
|
var algorithm = algorithms[i];
|
|
var bits = algorithm.bits;
|
|
for (var j = 0; j < bits.length; ++j) {
|
|
var methodName = algorithm.name +'_' + bits[j];
|
|
methodNames.push(methodName);
|
|
methods[methodName] = algorithm.createMethod(bits[j], algorithm.padding);
|
|
}
|
|
}
|
|
|
|
function Keccak(bits, padding, outputBits) {
|
|
this.blocks = [];
|
|
this.s = [];
|
|
this.padding = padding;
|
|
this.outputBits = outputBits;
|
|
this.reset = true;
|
|
this.block = 0;
|
|
this.start = 0;
|
|
this.blockCount = (1600 - (bits << 1)) >> 5;
|
|
this.byteCount = this.blockCount << 2;
|
|
this.outputBlocks = outputBits >> 5;
|
|
this.extraBytes = (outputBits & 31) >> 3;
|
|
|
|
for (var i = 0; i < 50; ++i) {
|
|
this.s[i] = 0;
|
|
}
|
|
}
|
|
|
|
Keccak.prototype.update = function (message) {
|
|
var notString = typeof message !== 'string';
|
|
if (notString && message.constructor === ArrayBuffer) {
|
|
message = new Uint8Array(message);
|
|
}
|
|
var length = message.length, blocks = this.blocks, byteCount = this.byteCount,
|
|
blockCount = this.blockCount, index = 0, s = this.s, i, code;
|
|
|
|
while (index < length) {
|
|
if (this.reset) {
|
|
this.reset = false;
|
|
blocks[0] = this.block;
|
|
for (i = 1; i < blockCount + 1; ++i) {
|
|
blocks[i] = 0;
|
|
}
|
|
}
|
|
if (notString) {
|
|
for (i = this.start; index < length && i < byteCount; ++index) {
|
|
blocks[i >> 2] |= message[index] << SHIFT[i++ & 3];
|
|
}
|
|
} else {
|
|
for (i = this.start; index < length && i < byteCount; ++index) {
|
|
code = message.charCodeAt(index);
|
|
if (code < 0x80) {
|
|
blocks[i >> 2] |= code << SHIFT[i++ & 3];
|
|
} else if (code < 0x800) {
|
|
blocks[i >> 2] |= (0xc0 | (code >> 6)) << SHIFT[i++ & 3];
|
|
blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];
|
|
} else if (code < 0xd800 || code >= 0xe000) {
|
|
blocks[i >> 2] |= (0xe0 | (code >> 12)) << SHIFT[i++ & 3];
|
|
blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3];
|
|
blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];
|
|
} else {
|
|
code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff));
|
|
blocks[i >> 2] |= (0xf0 | (code >> 18)) << SHIFT[i++ & 3];
|
|
blocks[i >> 2] |= (0x80 | ((code >> 12) & 0x3f)) << SHIFT[i++ & 3];
|
|
blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3];
|
|
blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];
|
|
}
|
|
}
|
|
}
|
|
this.lastByteIndex = i;
|
|
if (i >= byteCount) {
|
|
this.start = i - byteCount;
|
|
this.block = blocks[blockCount];
|
|
for (i = 0; i < blockCount; ++i) {
|
|
s[i] ^= blocks[i];
|
|
}
|
|
f(s);
|
|
this.reset = true;
|
|
} else {
|
|
this.start = i;
|
|
}
|
|
}
|
|
return this;
|
|
};
|
|
|
|
Keccak.prototype.finalize = function () {
|
|
var blocks = this.blocks, i = this.lastByteIndex, blockCount = this.blockCount, s = this.s;
|
|
blocks[i >> 2] |= this.padding[i & 3];
|
|
if (this.lastByteIndex === this.byteCount) {
|
|
blocks[0] = blocks[blockCount];
|
|
for (i = 1; i < blockCount + 1; ++i) {
|
|
blocks[i] = 0;
|
|
}
|
|
}
|
|
blocks[blockCount - 1] |= 0x80000000;
|
|
for (i = 0; i < blockCount; ++i) {
|
|
s[i] ^= blocks[i];
|
|
}
|
|
f(s);
|
|
};
|
|
|
|
Keccak.prototype.toString = Keccak.prototype.hex = function () {
|
|
this.finalize();
|
|
|
|
var blockCount = this.blockCount, s = this.s, outputBlocks = this.outputBlocks,
|
|
extraBytes = this.extraBytes, i = 0, j = 0;
|
|
var hex = '', block;
|
|
while (j < outputBlocks) {
|
|
for (i = 0; i < blockCount && j < outputBlocks; ++i, ++j) {
|
|
block = s[i];
|
|
hex += HEX_CHARS[(block >> 4) & 0x0F] + HEX_CHARS[block & 0x0F] +
|
|
HEX_CHARS[(block >> 12) & 0x0F] + HEX_CHARS[(block >> 8) & 0x0F] +
|
|
HEX_CHARS[(block >> 20) & 0x0F] + HEX_CHARS[(block >> 16) & 0x0F] +
|
|
HEX_CHARS[(block >> 28) & 0x0F] + HEX_CHARS[(block >> 24) & 0x0F];
|
|
}
|
|
if (j % blockCount === 0) {
|
|
f(s);
|
|
i = 0;
|
|
}
|
|
}
|
|
if (extraBytes) {
|
|
block = s[i];
|
|
if (extraBytes > 0) {
|
|
hex += HEX_CHARS[(block >> 4) & 0x0F] + HEX_CHARS[block & 0x0F];
|
|
}
|
|
if (extraBytes > 1) {
|
|
hex += HEX_CHARS[(block >> 12) & 0x0F] + HEX_CHARS[(block >> 8) & 0x0F];
|
|
}
|
|
if (extraBytes > 2) {
|
|
hex += HEX_CHARS[(block >> 20) & 0x0F] + HEX_CHARS[(block >> 16) & 0x0F];
|
|
}
|
|
}
|
|
return hex;
|
|
};
|
|
|
|
Keccak.prototype.arrayBuffer = function () {
|
|
this.finalize();
|
|
|
|
var blockCount = this.blockCount, s = this.s, outputBlocks = this.outputBlocks,
|
|
extraBytes = this.extraBytes, i = 0, j = 0;
|
|
var bytes = this.outputBits >> 3;
|
|
var buffer;
|
|
if (extraBytes) {
|
|
buffer = new ArrayBuffer((outputBlocks + 1) << 2);
|
|
} else {
|
|
buffer = new ArrayBuffer(bytes);
|
|
}
|
|
var array = new Uint32Array(buffer);
|
|
while (j < outputBlocks) {
|
|
for (i = 0; i < blockCount && j < outputBlocks; ++i, ++j) {
|
|
array[j] = s[i];
|
|
}
|
|
if (j % blockCount === 0) {
|
|
f(s);
|
|
}
|
|
}
|
|
if (extraBytes) {
|
|
array[i] = s[i];
|
|
buffer = buffer.slice(0, bytes);
|
|
}
|
|
return buffer;
|
|
};
|
|
|
|
Keccak.prototype.buffer = Keccak.prototype.arrayBuffer;
|
|
|
|
Keccak.prototype.digest = Keccak.prototype.array = function () {
|
|
this.finalize();
|
|
|
|
var blockCount = this.blockCount, s = this.s, outputBlocks = this.outputBlocks,
|
|
extraBytes = this.extraBytes, i = 0, j = 0;
|
|
var array = [], offset, block;
|
|
while (j < outputBlocks) {
|
|
for (i = 0; i < blockCount && j < outputBlocks; ++i, ++j) {
|
|
offset = j << 2;
|
|
block = s[i];
|
|
array[offset] = block & 0xFF;
|
|
array[offset + 1] = (block >> 8) & 0xFF;
|
|
array[offset + 2] = (block >> 16) & 0xFF;
|
|
array[offset + 3] = (block >> 24) & 0xFF;
|
|
}
|
|
if (j % blockCount === 0) {
|
|
f(s);
|
|
}
|
|
}
|
|
if (extraBytes) {
|
|
offset = j << 2;
|
|
block = s[i];
|
|
if (extraBytes > 0) {
|
|
array[offset] = block & 0xFF;
|
|
}
|
|
if (extraBytes > 1) {
|
|
array[offset + 1] = (block >> 8) & 0xFF;
|
|
}
|
|
if (extraBytes > 2) {
|
|
array[offset + 2] = (block >> 16) & 0xFF;
|
|
}
|
|
}
|
|
return array;
|
|
};
|
|
|
|
var f = function (s) {
|
|
var h, l, n, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9,
|
|
b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16, b17,
|
|
b18, b19, b20, b21, b22, b23, b24, b25, b26, b27, b28, b29, b30, b31, b32, b33,
|
|
b34, b35, b36, b37, b38, b39, b40, b41, b42, b43, b44, b45, b46, b47, b48, b49;
|
|
for (n = 0; n < 48; n += 2) {
|
|
c0 = s[0] ^ s[10] ^ s[20] ^ s[30] ^ s[40];
|
|
c1 = s[1] ^ s[11] ^ s[21] ^ s[31] ^ s[41];
|
|
c2 = s[2] ^ s[12] ^ s[22] ^ s[32] ^ s[42];
|
|
c3 = s[3] ^ s[13] ^ s[23] ^ s[33] ^ s[43];
|
|
c4 = s[4] ^ s[14] ^ s[24] ^ s[34] ^ s[44];
|
|
c5 = s[5] ^ s[15] ^ s[25] ^ s[35] ^ s[45];
|
|
c6 = s[6] ^ s[16] ^ s[26] ^ s[36] ^ s[46];
|
|
c7 = s[7] ^ s[17] ^ s[27] ^ s[37] ^ s[47];
|
|
c8 = s[8] ^ s[18] ^ s[28] ^ s[38] ^ s[48];
|
|
c9 = s[9] ^ s[19] ^ s[29] ^ s[39] ^ s[49];
|
|
|
|
h = c8 ^ ((c2 << 1) | (c3 >>> 31));
|
|
l = c9 ^ ((c3 << 1) | (c2 >>> 31));
|
|
s[0] ^= h;
|
|
s[1] ^= l;
|
|
s[10] ^= h;
|
|
s[11] ^= l;
|
|
s[20] ^= h;
|
|
s[21] ^= l;
|
|
s[30] ^= h;
|
|
s[31] ^= l;
|
|
s[40] ^= h;
|
|
s[41] ^= l;
|
|
h = c0 ^ ((c4 << 1) | (c5 >>> 31));
|
|
l = c1 ^ ((c5 << 1) | (c4 >>> 31));
|
|
s[2] ^= h;
|
|
s[3] ^= l;
|
|
s[12] ^= h;
|
|
s[13] ^= l;
|
|
s[22] ^= h;
|
|
s[23] ^= l;
|
|
s[32] ^= h;
|
|
s[33] ^= l;
|
|
s[42] ^= h;
|
|
s[43] ^= l;
|
|
h = c2 ^ ((c6 << 1) | (c7 >>> 31));
|
|
l = c3 ^ ((c7 << 1) | (c6 >>> 31));
|
|
s[4] ^= h;
|
|
s[5] ^= l;
|
|
s[14] ^= h;
|
|
s[15] ^= l;
|
|
s[24] ^= h;
|
|
s[25] ^= l;
|
|
s[34] ^= h;
|
|
s[35] ^= l;
|
|
s[44] ^= h;
|
|
s[45] ^= l;
|
|
h = c4 ^ ((c8 << 1) | (c9 >>> 31));
|
|
l = c5 ^ ((c9 << 1) | (c8 >>> 31));
|
|
s[6] ^= h;
|
|
s[7] ^= l;
|
|
s[16] ^= h;
|
|
s[17] ^= l;
|
|
s[26] ^= h;
|
|
s[27] ^= l;
|
|
s[36] ^= h;
|
|
s[37] ^= l;
|
|
s[46] ^= h;
|
|
s[47] ^= l;
|
|
h = c6 ^ ((c0 << 1) | (c1 >>> 31));
|
|
l = c7 ^ ((c1 << 1) | (c0 >>> 31));
|
|
s[8] ^= h;
|
|
s[9] ^= l;
|
|
s[18] ^= h;
|
|
s[19] ^= l;
|
|
s[28] ^= h;
|
|
s[29] ^= l;
|
|
s[38] ^= h;
|
|
s[39] ^= l;
|
|
s[48] ^= h;
|
|
s[49] ^= l;
|
|
|
|
b0 = s[0];
|
|
b1 = s[1];
|
|
b32 = (s[11] << 4) | (s[10] >>> 28);
|
|
b33 = (s[10] << 4) | (s[11] >>> 28);
|
|
b14 = (s[20] << 3) | (s[21] >>> 29);
|
|
b15 = (s[21] << 3) | (s[20] >>> 29);
|
|
b46 = (s[31] << 9) | (s[30] >>> 23);
|
|
b47 = (s[30] << 9) | (s[31] >>> 23);
|
|
b28 = (s[40] << 18) | (s[41] >>> 14);
|
|
b29 = (s[41] << 18) | (s[40] >>> 14);
|
|
b20 = (s[2] << 1) | (s[3] >>> 31);
|
|
b21 = (s[3] << 1) | (s[2] >>> 31);
|
|
b2 = (s[13] << 12) | (s[12] >>> 20);
|
|
b3 = (s[12] << 12) | (s[13] >>> 20);
|
|
b34 = (s[22] << 10) | (s[23] >>> 22);
|
|
b35 = (s[23] << 10) | (s[22] >>> 22);
|
|
b16 = (s[33] << 13) | (s[32] >>> 19);
|
|
b17 = (s[32] << 13) | (s[33] >>> 19);
|
|
b48 = (s[42] << 2) | (s[43] >>> 30);
|
|
b49 = (s[43] << 2) | (s[42] >>> 30);
|
|
b40 = (s[5] << 30) | (s[4] >>> 2);
|
|
b41 = (s[4] << 30) | (s[5] >>> 2);
|
|
b22 = (s[14] << 6) | (s[15] >>> 26);
|
|
b23 = (s[15] << 6) | (s[14] >>> 26);
|
|
b4 = (s[25] << 11) | (s[24] >>> 21);
|
|
b5 = (s[24] << 11) | (s[25] >>> 21);
|
|
b36 = (s[34] << 15) | (s[35] >>> 17);
|
|
b37 = (s[35] << 15) | (s[34] >>> 17);
|
|
b18 = (s[45] << 29) | (s[44] >>> 3);
|
|
b19 = (s[44] << 29) | (s[45] >>> 3);
|
|
b10 = (s[6] << 28) | (s[7] >>> 4);
|
|
b11 = (s[7] << 28) | (s[6] >>> 4);
|
|
b42 = (s[17] << 23) | (s[16] >>> 9);
|
|
b43 = (s[16] << 23) | (s[17] >>> 9);
|
|
b24 = (s[26] << 25) | (s[27] >>> 7);
|
|
b25 = (s[27] << 25) | (s[26] >>> 7);
|
|
b6 = (s[36] << 21) | (s[37] >>> 11);
|
|
b7 = (s[37] << 21) | (s[36] >>> 11);
|
|
b38 = (s[47] << 24) | (s[46] >>> 8);
|
|
b39 = (s[46] << 24) | (s[47] >>> 8);
|
|
b30 = (s[8] << 27) | (s[9] >>> 5);
|
|
b31 = (s[9] << 27) | (s[8] >>> 5);
|
|
b12 = (s[18] << 20) | (s[19] >>> 12);
|
|
b13 = (s[19] << 20) | (s[18] >>> 12);
|
|
b44 = (s[29] << 7) | (s[28] >>> 25);
|
|
b45 = (s[28] << 7) | (s[29] >>> 25);
|
|
b26 = (s[38] << 8) | (s[39] >>> 24);
|
|
b27 = (s[39] << 8) | (s[38] >>> 24);
|
|
b8 = (s[48] << 14) | (s[49] >>> 18);
|
|
b9 = (s[49] << 14) | (s[48] >>> 18);
|
|
|
|
s[0] = b0 ^ (~b2 & b4);
|
|
s[1] = b1 ^ (~b3 & b5);
|
|
s[10] = b10 ^ (~b12 & b14);
|
|
s[11] = b11 ^ (~b13 & b15);
|
|
s[20] = b20 ^ (~b22 & b24);
|
|
s[21] = b21 ^ (~b23 & b25);
|
|
s[30] = b30 ^ (~b32 & b34);
|
|
s[31] = b31 ^ (~b33 & b35);
|
|
s[40] = b40 ^ (~b42 & b44);
|
|
s[41] = b41 ^ (~b43 & b45);
|
|
s[2] = b2 ^ (~b4 & b6);
|
|
s[3] = b3 ^ (~b5 & b7);
|
|
s[12] = b12 ^ (~b14 & b16);
|
|
s[13] = b13 ^ (~b15 & b17);
|
|
s[22] = b22 ^ (~b24 & b26);
|
|
s[23] = b23 ^ (~b25 & b27);
|
|
s[32] = b32 ^ (~b34 & b36);
|
|
s[33] = b33 ^ (~b35 & b37);
|
|
s[42] = b42 ^ (~b44 & b46);
|
|
s[43] = b43 ^ (~b45 & b47);
|
|
s[4] = b4 ^ (~b6 & b8);
|
|
s[5] = b5 ^ (~b7 & b9);
|
|
s[14] = b14 ^ (~b16 & b18);
|
|
s[15] = b15 ^ (~b17 & b19);
|
|
s[24] = b24 ^ (~b26 & b28);
|
|
s[25] = b25 ^ (~b27 & b29);
|
|
s[34] = b34 ^ (~b36 & b38);
|
|
s[35] = b35 ^ (~b37 & b39);
|
|
s[44] = b44 ^ (~b46 & b48);
|
|
s[45] = b45 ^ (~b47 & b49);
|
|
s[6] = b6 ^ (~b8 & b0);
|
|
s[7] = b7 ^ (~b9 & b1);
|
|
s[16] = b16 ^ (~b18 & b10);
|
|
s[17] = b17 ^ (~b19 & b11);
|
|
s[26] = b26 ^ (~b28 & b20);
|
|
s[27] = b27 ^ (~b29 & b21);
|
|
s[36] = b36 ^ (~b38 & b30);
|
|
s[37] = b37 ^ (~b39 & b31);
|
|
s[46] = b46 ^ (~b48 & b40);
|
|
s[47] = b47 ^ (~b49 & b41);
|
|
s[8] = b8 ^ (~b0 & b2);
|
|
s[9] = b9 ^ (~b1 & b3);
|
|
s[18] = b18 ^ (~b10 & b12);
|
|
s[19] = b19 ^ (~b11 & b13);
|
|
s[28] = b28 ^ (~b20 & b22);
|
|
s[29] = b29 ^ (~b21 & b23);
|
|
s[38] = b38 ^ (~b30 & b32);
|
|
s[39] = b39 ^ (~b31 & b33);
|
|
s[48] = b48 ^ (~b40 & b42);
|
|
s[49] = b49 ^ (~b41 & b43);
|
|
|
|
s[0] ^= RC[n];
|
|
s[1] ^= RC[n + 1];
|
|
}
|
|
};
|
|
|
|
if (COMMON_JS) {
|
|
module.exports = methods;
|
|
} else {
|
|
for (var i = 0; i < methodNames.length; ++i) {
|
|
root[methodNames[i]] = methods[methodNames[i]];
|
|
}
|
|
}
|
|
})();
|
|
|
|
}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
|
},{"_process":7}],7:[function(require,module,exports){
|
|
// shim for using process in browser
|
|
var process = module.exports = {};
|
|
|
|
// cached from whatever global is present so that test runners that stub it
|
|
// don't break things. But we need to wrap it in a try catch in case it is
|
|
// wrapped in strict mode code which doesn't define any globals. It's inside a
|
|
// function because try/catches deoptimize in certain engines.
|
|
|
|
var cachedSetTimeout;
|
|
var cachedClearTimeout;
|
|
|
|
function defaultSetTimout() {
|
|
throw new Error('setTimeout has not been defined');
|
|
}
|
|
function defaultClearTimeout () {
|
|
throw new Error('clearTimeout has not been defined');
|
|
}
|
|
(function () {
|
|
try {
|
|
if (typeof setTimeout === 'function') {
|
|
cachedSetTimeout = setTimeout;
|
|
} else {
|
|
cachedSetTimeout = defaultSetTimout;
|
|
}
|
|
} catch (e) {
|
|
cachedSetTimeout = defaultSetTimout;
|
|
}
|
|
try {
|
|
if (typeof clearTimeout === 'function') {
|
|
cachedClearTimeout = clearTimeout;
|
|
} else {
|
|
cachedClearTimeout = defaultClearTimeout;
|
|
}
|
|
} catch (e) {
|
|
cachedClearTimeout = defaultClearTimeout;
|
|
}
|
|
} ())
|
|
function runTimeout(fun) {
|
|
if (cachedSetTimeout === setTimeout) {
|
|
//normal enviroments in sane situations
|
|
return setTimeout(fun, 0);
|
|
}
|
|
// if setTimeout wasn't available but was latter defined
|
|
if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
|
|
cachedSetTimeout = setTimeout;
|
|
return setTimeout(fun, 0);
|
|
}
|
|
try {
|
|
// when when somebody has screwed with setTimeout but no I.E. maddness
|
|
return cachedSetTimeout(fun, 0);
|
|
} catch(e){
|
|
try {
|
|
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
|
|
return cachedSetTimeout.call(null, fun, 0);
|
|
} catch(e){
|
|
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
|
|
return cachedSetTimeout.call(this, fun, 0);
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
function runClearTimeout(marker) {
|
|
if (cachedClearTimeout === clearTimeout) {
|
|
//normal enviroments in sane situations
|
|
return clearTimeout(marker);
|
|
}
|
|
// if clearTimeout wasn't available but was latter defined
|
|
if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
|
|
cachedClearTimeout = clearTimeout;
|
|
return clearTimeout(marker);
|
|
}
|
|
try {
|
|
// when when somebody has screwed with setTimeout but no I.E. maddness
|
|
return cachedClearTimeout(marker);
|
|
} catch (e){
|
|
try {
|
|
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
|
|
return cachedClearTimeout.call(null, marker);
|
|
} catch (e){
|
|
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
|
|
// Some versions of I.E. have different rules for clearTimeout vs setTimeout
|
|
return cachedClearTimeout.call(this, marker);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
}
|
|
var queue = [];
|
|
var draining = false;
|
|
var currentQueue;
|
|
var queueIndex = -1;
|
|
|
|
function cleanUpNextTick() {
|
|
if (!draining || !currentQueue) {
|
|
return;
|
|
}
|
|
draining = false;
|
|
if (currentQueue.length) {
|
|
queue = currentQueue.concat(queue);
|
|
} else {
|
|
queueIndex = -1;
|
|
}
|
|
if (queue.length) {
|
|
drainQueue();
|
|
}
|
|
}
|
|
|
|
function drainQueue() {
|
|
if (draining) {
|
|
return;
|
|
}
|
|
var timeout = runTimeout(cleanUpNextTick);
|
|
draining = true;
|
|
|
|
var len = queue.length;
|
|
while(len) {
|
|
currentQueue = queue;
|
|
queue = [];
|
|
while (++queueIndex < len) {
|
|
if (currentQueue) {
|
|
currentQueue[queueIndex].run();
|
|
}
|
|
}
|
|
queueIndex = -1;
|
|
len = queue.length;
|
|
}
|
|
currentQueue = null;
|
|
draining = false;
|
|
runClearTimeout(timeout);
|
|
}
|
|
|
|
process.nextTick = function (fun) {
|
|
var args = new Array(arguments.length - 1);
|
|
if (arguments.length > 1) {
|
|
for (var i = 1; i < arguments.length; i++) {
|
|
args[i - 1] = arguments[i];
|
|
}
|
|
}
|
|
queue.push(new Item(fun, args));
|
|
if (queue.length === 1 && !draining) {
|
|
runTimeout(drainQueue);
|
|
}
|
|
};
|
|
|
|
// v8 likes predictible objects
|
|
function Item(fun, array) {
|
|
this.fun = fun;
|
|
this.array = array;
|
|
}
|
|
Item.prototype.run = function () {
|
|
this.fun.apply(null, this.array);
|
|
};
|
|
process.title = 'browser';
|
|
process.browser = true;
|
|
process.env = {};
|
|
process.argv = [];
|
|
process.version = ''; // empty string to avoid regexp issues
|
|
process.versions = {};
|
|
|
|
function noop() {}
|
|
|
|
process.on = noop;
|
|
process.addListener = noop;
|
|
process.once = noop;
|
|
process.off = noop;
|
|
process.removeListener = noop;
|
|
process.removeAllListeners = noop;
|
|
process.emit = noop;
|
|
process.prependListener = noop;
|
|
process.prependOnceListener = noop;
|
|
|
|
process.listeners = function (name) { return [] }
|
|
|
|
process.binding = function (name) {
|
|
throw new Error('process.binding is not supported');
|
|
};
|
|
|
|
process.cwd = function () { return '/' };
|
|
process.chdir = function (dir) {
|
|
throw new Error('process.chdir is not supported');
|
|
};
|
|
process.umask = function() { return 0; };
|
|
|
|
},{}],8:[function(require,module,exports){
|
|
'use strict';
|
|
|
|
// See: https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI
|
|
|
|
var utils = (function() {
|
|
var convert = require('../utils/convert.js');
|
|
var utf8 = require('../utils/utf8.js');
|
|
|
|
return {
|
|
defineProperty: require('../utils/properties.js').defineProperty,
|
|
|
|
arrayify: convert.arrayify,
|
|
padZeros: convert.padZeros,
|
|
|
|
bigNumberify: require('../utils/bignumber.js').bigNumberify,
|
|
|
|
getAddress: require('../utils/address').getAddress,
|
|
|
|
concat: convert.concat,
|
|
|
|
toUtf8Bytes: utf8.toUtf8Bytes,
|
|
toUtf8String: utf8.toUtf8String,
|
|
|
|
hexlify: convert.hexlify,
|
|
};
|
|
})();
|
|
|
|
var errors = require('./errors');
|
|
|
|
var paramTypeBytes = new RegExp(/^bytes([0-9]*)$/);
|
|
var paramTypeNumber = new RegExp(/^(u?int)([0-9]*)$/);
|
|
var paramTypeArray = new RegExp(/^(.*)\[([0-9]*)\]$/);
|
|
|
|
var defaultCoerceFunc = function(type, value) {
|
|
var match = type.match(paramTypeNumber)
|
|
if (match && parseInt(match[2]) <= 48) { return value.toNumber(); }
|
|
return value;
|
|
}
|
|
|
|
|
|
///////////////////////////////////
|
|
// Parsing for Solidity Signatures
|
|
|
|
var regexParen = new RegExp("^([^)(]*)\\((.*)\\)([^)(]*)$");
|
|
var regexIdentifier = new RegExp("^[A-Za-z_][A-Za-z0-9_]*$");
|
|
|
|
var close = { "(": ")", "[": "]" };
|
|
|
|
function verifyType(type) {
|
|
|
|
// These need to be transformed to their full description
|
|
if (type.match(/^uint($|[^1-9])/)) {
|
|
type = 'uint256' + type.substring(4);
|
|
} else if (type.match(/^int($|[^1-9])/)) {
|
|
type = 'int256' + type.substring(3);
|
|
}
|
|
|
|
return type;
|
|
}
|
|
|
|
function parseParam(param, allowIndexed) {
|
|
function throwError(i) {
|
|
throw new Error('unexpected character "' + param[i] + '" at position ' + i + ' in "' + param + '"');
|
|
}
|
|
|
|
var parent = { type: '', name: '', state: { allowType: true } };
|
|
var node = parent;
|
|
|
|
for (var i = 0; i < param.length; i++) {
|
|
var c = param[i];
|
|
switch (c) {
|
|
case '(':
|
|
if (!node.state.allowParams) { throwError(i); }
|
|
delete node.state.allowType;
|
|
node.type = verifyType(node.type);
|
|
node.components = [ { type: '', name: '', parent: node, state: { allowType: true } } ];
|
|
node = node.components[0];
|
|
break;
|
|
|
|
case ')':
|
|
delete node.state;
|
|
node.type = verifyType(node.type);
|
|
|
|
var child = node;
|
|
node = node.parent;
|
|
if (!node) { throwError(i); }
|
|
delete child.parent;
|
|
delete node.state.allowParams;
|
|
node.state.allowName = true;
|
|
node.state.allowArray = true;
|
|
break;
|
|
|
|
case ',':
|
|
delete node.state;
|
|
node.type = verifyType(node.type);
|
|
|
|
var sibling = { type: '', name: '', parent: node.parent, state: { allowType: true } };
|
|
node.parent.components.push(sibling);
|
|
delete node.parent;
|
|
node = sibling;
|
|
break;
|
|
|
|
// Hit a space...
|
|
case ' ':
|
|
|
|
// If reading type, the type is done and may read a param or name
|
|
if (node.state.allowType) {
|
|
if (node.type !== '') {
|
|
node.type = verifyType(node.type);
|
|
delete node.state.allowType;
|
|
node.state.allowName = true;
|
|
node.state.allowParams = true;
|
|
}
|
|
}
|
|
|
|
// If reading name, the name is done
|
|
if (node.state.allowName) {
|
|
if (node.name !== '') {
|
|
if (allowIndexed && node.name === 'indexed') {
|
|
node.indexed = true;
|
|
node.name = '';
|
|
} else {
|
|
delete node.state.allowName;
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case '[':
|
|
if (!node.state.allowArray) { throwError(i); }
|
|
|
|
//if (!node.array) { node.array = ''; }
|
|
//node.array += c;
|
|
node.type += c;
|
|
|
|
delete node.state.allowArray;
|
|
delete node.state.allowName;
|
|
node.state.readArray = true;
|
|
break;
|
|
|
|
case ']':
|
|
if (!node.state.readArray) { throwError(i); }
|
|
|
|
//node.array += c;
|
|
node.type += c;
|
|
|
|
delete node.state.readArray;
|
|
node.state.allowArray = true;
|
|
node.state.allowName = true;
|
|
break;
|
|
|
|
default:
|
|
if (node.state.allowType) {
|
|
node.type += c;
|
|
node.state.allowParams = true;
|
|
node.state.allowArray = true;
|
|
} else if (node.state.allowName) {
|
|
node.name += c;
|
|
delete node.state.allowArray;
|
|
} else if (node.state.readArray) {
|
|
//node.array += c;
|
|
node.type += c;
|
|
} else {
|
|
throwError(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (node.parent) { throw new Error("unexpected eof"); }
|
|
|
|
delete parent.state;
|
|
parent.type = verifyType(parent.type);
|
|
|
|
//verifyType(parent);
|
|
|
|
return parent;
|
|
}
|
|
|
|
function parseSignatureEvent(fragment) {
|
|
|
|
var abi = {
|
|
anonymous: false,
|
|
inputs: [],
|
|
type: 'event'
|
|
}
|
|
|
|
var match = fragment.match(regexParen);
|
|
if (!match) { throw new Error('invalid event: ' + fragment); }
|
|
|
|
abi.name = match[1].trim();
|
|
|
|
splitNesting(match[2]).forEach(function(param) {
|
|
param = parseParam(param, true);
|
|
param.indexed = !!param.indexed;
|
|
abi.inputs.push(param);
|
|
});
|
|
|
|
match[3].split(' ').forEach(function(modifier) {
|
|
switch(modifier) {
|
|
case 'anonymous':
|
|
abi.anonymous = true;
|
|
break;
|
|
case '':
|
|
break;
|
|
default:
|
|
console.log('unknown modifier: ' + mdifier);
|
|
}
|
|
});
|
|
|
|
if (abi.name && !abi.name.match(regexIdentifier)) {
|
|
throw new Error('invalid identifier: "' + result.name + '"');
|
|
}
|
|
|
|
return abi;
|
|
}
|
|
|
|
function parseSignatureFunction(fragment) {
|
|
var abi = {
|
|
constant: false,
|
|
inputs: [],
|
|
outputs: [],
|
|
payable: false,
|
|
type: 'function'
|
|
};
|
|
|
|
var comps = fragment.split(' returns ');
|
|
var left = comps[0].match(regexParen);
|
|
if (!left) { throw new Error('invalid signature'); }
|
|
|
|
abi.name = left[1].trim();
|
|
if (!abi.name.match(regexIdentifier)) {
|
|
throw new Error('invalid identifier: "' + left[1] + '"');
|
|
}
|
|
|
|
splitNesting(left[2]).forEach(function(param) {
|
|
abi.inputs.push(parseParam(param));
|
|
});
|
|
|
|
left[3].split(' ').forEach(function(modifier) {
|
|
switch (modifier) {
|
|
case 'constant':
|
|
abi.constant = true;
|
|
break;
|
|
case 'payable':
|
|
abi.payable = true;
|
|
break;
|
|
case 'pure':
|
|
abi.constant = true;
|
|
abi.stateMutability = 'pure';
|
|
break;
|
|
case 'view':
|
|
abi.constant = true;
|
|
abi.stateMutability = 'view';
|
|
break;
|
|
case '':
|
|
break;
|
|
default:
|
|
console.log('unknown modifier: ' + modifier);
|
|
}
|
|
});
|
|
|
|
// We have outputs
|
|
if (comps.length > 1) {
|
|
var right = comps[1].match(regexParen);
|
|
if (right[1].trim() != '' || right[3].trim() != '') {
|
|
throw new Error('unexpected tokens');
|
|
}
|
|
|
|
splitNesting(right[2]).forEach(function(param) {
|
|
abi.outputs.push(parseParam(param));
|
|
});
|
|
}
|
|
|
|
return abi;
|
|
}
|
|
|
|
|
|
function parseSignature(fragment) {
|
|
if(typeof(fragment) === 'string') {
|
|
// Make sure the "returns" is surrounded by a space and all whitespace is exactly one space
|
|
fragment = fragment.replace(/\(/g, ' (').replace(/\)/g, ') ').replace(/\s+/g, ' ');
|
|
fragment = fragment.trim();
|
|
|
|
if (fragment.substring(0, 6) === 'event ') {
|
|
return parseSignatureEvent(fragment.substring(6).trim());
|
|
|
|
} else {
|
|
if (fragment.substring(0, 9) === 'function ') {
|
|
fragment = fragment.substring(9);
|
|
}
|
|
return parseSignatureFunction(fragment.trim());
|
|
}
|
|
}
|
|
|
|
throw new Error('unknown fragment');
|
|
}
|
|
|
|
|
|
///////////////////////////////////
|
|
// Coders
|
|
|
|
var coderNull = function(coerceFunc) {
|
|
return {
|
|
name: 'null',
|
|
type: '',
|
|
encode: function(value) {
|
|
return utils.arrayify([]);
|
|
},
|
|
decode: function(data, offset) {
|
|
if (offset > data.length) { throw new Error('invalid null'); }
|
|
return {
|
|
consumed: 0,
|
|
value: coerceFunc('null', undefined)
|
|
}
|
|
},
|
|
dynamic: false
|
|
};
|
|
}
|
|
|
|
var coderNumber = function(coerceFunc, size, signed, localName) {
|
|
var name = ((signed ? 'int': 'uint') + (size * 8));
|
|
return {
|
|
localName: localName,
|
|
name: name,
|
|
type: name,
|
|
encode: function(value) {
|
|
try {
|
|
value = utils.bigNumberify(value)
|
|
} catch (error) {
|
|
errors.throwError('invalid number value', errors.INVALID_ARGUMENT, {
|
|
arg: localName,
|
|
type: typeof(value),
|
|
value: value
|
|
});
|
|
}
|
|
value = value.toTwos(size * 8).maskn(size * 8);
|
|
//value = value.toTwos(size * 8).maskn(size * 8);
|
|
if (signed) {
|
|
value = value.fromTwos(size * 8).toTwos(256);
|
|
}
|
|
return utils.padZeros(utils.arrayify(value), 32);
|
|
},
|
|
decode: function(data, offset) {
|
|
if (data.length < offset + 32) {
|
|
errors.throwError('insufficient data for ' + name + ' type', errors.INVALID_ARGUMENT, {
|
|
arg: localName,
|
|
coderType: name,
|
|
value: utils.hexlify(data.slice(offset, offset + 32))
|
|
});
|
|
}
|
|
var junkLength = 32 - size;
|
|
var value = utils.bigNumberify(data.slice(offset + junkLength, offset + 32));
|
|
if (signed) {
|
|
value = value.fromTwos(size * 8);
|
|
} else {
|
|
value = value.maskn(size * 8);
|
|
}
|
|
|
|
//if (size <= 6) { value = value.toNumber(); }
|
|
|
|
return {
|
|
consumed: 32,
|
|
value: coerceFunc(name, value),
|
|
}
|
|
}
|
|
};
|
|
}
|
|
var uint256Coder = coderNumber(function(type, value) { return value; }, 32, false);
|
|
|
|
var coderBoolean = function(coerceFunc, localName) {
|
|
return {
|
|
localName: localName,
|
|
name: 'bool',
|
|
type: 'bool',
|
|
encode: function(value) {
|
|
return uint256Coder.encode(!!value ? 1: 0);
|
|
},
|
|
decode: function(data, offset) {
|
|
try {
|
|
var result = uint256Coder.decode(data, offset);
|
|
} catch (error) {
|
|
if (error.reason === 'insufficient data for uint256 type') {
|
|
errors.throwError('insufficient data for boolean type', errors.INVALID_ARGUMENT, {
|
|
arg: localName,
|
|
coderType: 'boolean',
|
|
value: error.value
|
|
});
|
|
}
|
|
throw error;
|
|
}
|
|
return {
|
|
consumed: result.consumed,
|
|
value: coerceFunc('boolean', !result.value.isZero())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
var coderFixedBytes = function(coerceFunc, length, localName) {
|
|
var name = ('bytes' + length);
|
|
return {
|
|
localName: localName,
|
|
name: name,
|
|
type: name,
|
|
encode: function(value) {
|
|
try {
|
|
value = utils.arrayify(value);
|
|
} catch (error) {
|
|
errors.throwError('invalid ' + name + ' value', errors.INVALID_ARGUMENT, {
|
|
arg: localName,
|
|
type: typeof(value),
|
|
value: error.value
|
|
});
|
|
}
|
|
if (length === 32) { return value; }
|
|
|
|
var result = new Uint8Array(32);
|
|
result.set(value);
|
|
return result;
|
|
},
|
|
decode: function(data, offset) {
|
|
if (data.length < offset + 32) {
|
|
errors.throwError('insufficient data for ' + name + ' type', errors.INVALID_ARGUMENT, {
|
|
arg: localName,
|
|
coderType: name,
|
|
value: utils.hexlify(data.slice(offset, offset + 32))
|
|
});
|
|
}
|
|
|
|
return {
|
|
consumed: 32,
|
|
value: coerceFunc(name, utils.hexlify(data.slice(offset, offset + length)))
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
var coderAddress = function(coerceFunc, localName) {
|
|
return {
|
|
localName: localName,
|
|
name: 'address',
|
|
type: 'address',
|
|
encode: function(value) {
|
|
try {
|
|
value = utils.arrayify(utils.getAddress(value));
|
|
} catch (error) {
|
|
errors.throwError('invalid address', errors.INVALID_ARGUMENT, {
|
|
arg: localName,
|
|
type: typeof(value),
|
|
value: value
|
|
});
|
|
}
|
|
var result = new Uint8Array(32);
|
|
result.set(value, 12);
|
|
return result;
|
|
},
|
|
decode: function(data, offset) {
|
|
if (data.length < offset + 32) {
|
|
errors.throwError('insufficuent data for address type', errors.INVALID_ARGUMENT, {
|
|
arg: localName,
|
|
coderType: 'address',
|
|
value: utils.hexlify(data.slice(offset, offset + 32))
|
|
});
|
|
}
|
|
return {
|
|
consumed: 32,
|
|
value: coerceFunc('address', utils.getAddress(utils.hexlify(data.slice(offset + 12, offset + 32))))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function _encodeDynamicBytes(value) {
|
|
var dataLength = parseInt(32 * Math.ceil(value.length / 32));
|
|
var padding = new Uint8Array(dataLength - value.length);
|
|
|
|
return utils.concat([
|
|
uint256Coder.encode(value.length),
|
|
value,
|
|
padding
|
|
]);
|
|
}
|
|
|
|
function _decodeDynamicBytes(data, offset, localName) {
|
|
if (data.length < offset + 32) {
|
|
errors.throwError('insufficient data for dynamicBytes length', errors.INVALID_ARGUMENT, {
|
|
arg: localName,
|
|
coderType: 'dynamicBytes',
|
|
value: utils.hexlify(data.slice(offset, offset + 32))
|
|
});
|
|
}
|
|
|
|
var length = uint256Coder.decode(data, offset).value;
|
|
try {
|
|
length = length.toNumber();
|
|
} catch (error) {
|
|
errors.throwError('dynamic bytes count too large', errors.INVALID_ARGUMENT, {
|
|
arg: localName,
|
|
coderType: 'dynamicBytes',
|
|
value: length.toString()
|
|
});
|
|
}
|
|
|
|
if (data.length < offset + 32 + length) {
|
|
errors.throwError('insufficient data for dynamicBytes type', errors.INVALID_ARGUMENT, {
|
|
arg: localName,
|
|
coderType: 'dynamicBytes',
|
|
value: utils.hexlify(data.slice(offset, offset + 32 + length))
|
|
});
|
|
}
|
|
|
|
return {
|
|
consumed: parseInt(32 + 32 * Math.ceil(length / 32)),
|
|
value: data.slice(offset + 32, offset + 32 + length),
|
|
}
|
|
}
|
|
|
|
var coderDynamicBytes = function(coerceFunc, localName) {
|
|
return {
|
|
localName: localName,
|
|
name: 'bytes',
|
|
type: 'bytes',
|
|
encode: function(value) {
|
|
try {
|
|
value = utils.arrayify(value);
|
|
} catch (error) {
|
|
errors.throwError('invalid bytes value', errors.INVALID_ARGUMENT, {
|
|
arg: localName,
|
|
type: typeof(value),
|
|
value: error.value
|
|
});
|
|
}
|
|
return _encodeDynamicBytes(value);
|
|
},
|
|
decode: function(data, offset) {
|
|
var result = _decodeDynamicBytes(data, offset, localName);
|
|
result.value = coerceFunc('bytes', utils.hexlify(result.value));
|
|
return result;
|
|
},
|
|
dynamic: true
|
|
};
|
|
}
|
|
|
|
var coderString = function(coerceFunc, localName) {
|
|
return {
|
|
localName: localName,
|
|
name: 'string',
|
|
type: 'string',
|
|
encode: function(value) {
|
|
if (typeof(value) !== 'string') {
|
|
errors.throwError('invalid string value', errors.INVALID_ARGUMENT, {
|
|
arg: localName,
|
|
type: typeof(value),
|
|
value: value
|
|
});
|
|
}
|
|
return _encodeDynamicBytes(utils.toUtf8Bytes(value));
|
|
},
|
|
decode: function(data, offset) {
|
|
var result = _decodeDynamicBytes(data, offset, localName);
|
|
result.value = coerceFunc('string', utils.toUtf8String(result.value));
|
|
return result;
|
|
},
|
|
dynamic: true
|
|
};
|
|
}
|
|
|
|
function alignSize(size) {
|
|
return parseInt(32 * Math.ceil(size / 32));
|
|
}
|
|
|
|
function pack(coders, values) {
|
|
|
|
if (Array.isArray(values)) {
|
|
// do nothing
|
|
|
|
} else if (values && typeof(values) === 'object') {
|
|
var arrayValues = [];
|
|
coders.forEach(function(coder) {
|
|
arrayValues.push(values[coder.localName]);
|
|
});
|
|
values = arrayValues;
|
|
|
|
} else {
|
|
errors.throwError('invalid tuple value', errors.INVALID_ARGUMENT, {
|
|
coderType: 'tuple',
|
|
type: typeof(values),
|
|
value: values
|
|
});
|
|
}
|
|
|
|
if (coders.length !== values.length) {
|
|
errors.throwError('types/value length mismatch', errors.INVALID_ARGUMENT, {
|
|
coderType: 'tuple',
|
|
value: values
|
|
});
|
|
}
|
|
|
|
var parts = [];
|
|
|
|
coders.forEach(function(coder, index) {
|
|
parts.push({ dynamic: coder.dynamic, value: coder.encode(values[index]) });
|
|
});
|
|
|
|
var staticSize = 0, dynamicSize = 0;
|
|
parts.forEach(function(part, index) {
|
|
if (part.dynamic) {
|
|
staticSize += 32;
|
|
dynamicSize += alignSize(part.value.length);
|
|
} else {
|
|
staticSize += alignSize(part.value.length);
|
|
}
|
|
});
|
|
|
|
var offset = 0, dynamicOffset = staticSize;
|
|
var data = new Uint8Array(staticSize + dynamicSize);
|
|
|
|
parts.forEach(function(part, index) {
|
|
if (part.dynamic) {
|
|
//uint256Coder.encode(dynamicOffset).copy(data, offset);
|
|
data.set(uint256Coder.encode(dynamicOffset), offset);
|
|
offset += 32;
|
|
|
|
//part.value.copy(data, dynamicOffset); @TODO
|
|
data.set(part.value, dynamicOffset);
|
|
dynamicOffset += alignSize(part.value.length);
|
|
} else {
|
|
//part.value.copy(data, offset); @TODO
|
|
data.set(part.value, offset);
|
|
offset += alignSize(part.value.length);
|
|
}
|
|
});
|
|
|
|
return data;
|
|
}
|
|
|
|
function unpack(coders, data, offset) {
|
|
var baseOffset = offset;
|
|
var consumed = 0;
|
|
var value = [];
|
|
coders.forEach(function(coder) {
|
|
if (coder.dynamic) {
|
|
var dynamicOffset = uint256Coder.decode(data, offset);
|
|
var result = coder.decode(data, baseOffset + dynamicOffset.value.toNumber());
|
|
// The dynamic part is leap-frogged somewhere else; doesn't count towards size
|
|
result.consumed = dynamicOffset.consumed;
|
|
} else {
|
|
var result = coder.decode(data, offset);
|
|
}
|
|
|
|
if (result.value != undefined) {
|
|
value.push(result.value);
|
|
}
|
|
|
|
offset += result.consumed;
|
|
consumed += result.consumed;
|
|
});
|
|
|
|
coders.forEach(function(coder, index) {
|
|
var name = coder.localName;
|
|
if (!name) { return; }
|
|
|
|
if (typeof(name) === 'object') { name = name.name; }
|
|
if (!name) { return; }
|
|
|
|
if (name === 'length') { name = '_length'; }
|
|
|
|
if (value[name] != null) { return; }
|
|
|
|
value[name] = value[index];
|
|
});
|
|
|
|
return {
|
|
value: value,
|
|
consumed: consumed
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
function coderArray(coerceFunc, coder, length, localName) {
|
|
var type = (coder.type + '[' + (length >= 0 ? length: '') + ']');
|
|
|
|
return {
|
|
coder: coder,
|
|
localName: localName,
|
|
length: length,
|
|
name: 'array',
|
|
type: type,
|
|
encode: function(value) {
|
|
if (!Array.isArray(value)) {
|
|
errors.throwError('expected array value', errors.INVALID_ARGUMENT, {
|
|
arg: localName,
|
|
coderType: 'array',
|
|
type: typeof(value),
|
|
value: value
|
|
});
|
|
}
|
|
|
|
var count = length;
|
|
|
|
var result = new Uint8Array(0);
|
|
if (count === -1) {
|
|
count = value.length;
|
|
result = uint256Coder.encode(count);
|
|
}
|
|
|
|
if (count !== value.length) {
|
|
error.throwError('array value length mismatch', errors.INVALID_ARGUMENT, {
|
|
arg: localName,
|
|
coderType: 'array',
|
|
count: value.length,
|
|
expectedCount: count,
|
|
value: value
|
|
});
|
|
}
|
|
|
|
var coders = [];
|
|
value.forEach(function(value) { coders.push(coder); });
|
|
|
|
return utils.concat([result, pack(coders, value)]);
|
|
},
|
|
decode: function(data, offset) {
|
|
// @TODO:
|
|
//if (data.length < offset + length * 32) { throw new Error('invalid array'); }
|
|
|
|
var consumed = 0;
|
|
|
|
var count = length;
|
|
|
|
if (count === -1) {
|
|
try {
|
|
var decodedLength = uint256Coder.decode(data, offset);
|
|
} catch (error) {
|
|
errors.throwError('insufficient data for dynamic array length', errors.INVALID_ARGUMENT, {
|
|
arg: localName,
|
|
coderType: 'array',
|
|
value: error.value
|
|
});
|
|
}
|
|
try {
|
|
count = decodedLength.value.toNumber();
|
|
} catch (error) {
|
|
errors.throwError('array count too large', errors.INVALID_ARGUMENT, {
|
|
arg: localName,
|
|
coderType: 'array',
|
|
value: decodedLength.value.toString()
|
|
});
|
|
}
|
|
consumed += decodedLength.consumed;
|
|
offset += decodedLength.consumed;
|
|
}
|
|
|
|
var coders = [];
|
|
for (var i = 0; i < count; i++) { coders.push(coder); }
|
|
|
|
var result = unpack(coders, data, offset);
|
|
result.consumed += consumed;
|
|
result.value = coerceFunc(type, result.value);
|
|
return result;
|
|
},
|
|
dynamic: (length === -1 || coder.dynamic)
|
|
}
|
|
}
|
|
|
|
|
|
function coderTuple(coerceFunc, coders, localName) {
|
|
|
|
var dynamic = false;
|
|
var types = [];
|
|
coders.forEach(function(coder) {
|
|
if (coder.dynamic) { dynamic = true; }
|
|
types.push(coder.type);
|
|
});
|
|
|
|
var type = ('tuple(' + types.join(',') + ')');
|
|
|
|
return {
|
|
coders: coders,
|
|
localName: localName,
|
|
name: 'tuple',
|
|
type: type,
|
|
encode: function(value) {
|
|
return pack(coders, value);
|
|
},
|
|
decode: function(data, offset) {
|
|
var result = unpack(coders, data, offset);
|
|
result.value = coerceFunc(type, result.value);
|
|
return result;
|
|
},
|
|
dynamic: dynamic
|
|
};
|
|
}
|
|
/*
|
|
function getTypes(coders) {
|
|
var type = coderTuple(coders).type;
|
|
return type.substring(6, type.length - 1);
|
|
}
|
|
*/
|
|
function splitNesting(value) {
|
|
var result = [];
|
|
var accum = '';
|
|
var depth = 0;
|
|
for (var offset = 0; offset < value.length; offset++) {
|
|
var c = value[offset];
|
|
if (c === ',' && depth === 0) {
|
|
result.push(accum);
|
|
accum = '';
|
|
} else {
|
|
accum += c;
|
|
if (c === '(') {
|
|
depth++;
|
|
} else if (c === ')') {
|
|
depth--;
|
|
if (depth === -1) {
|
|
throw new Error('unbalanced parenthsis');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
result.push(accum);
|
|
|
|
return result;
|
|
}
|
|
|
|
var paramTypeSimple = {
|
|
address: coderAddress,
|
|
bool: coderBoolean,
|
|
string: coderString,
|
|
bytes: coderDynamicBytes,
|
|
};
|
|
|
|
function getTupleParamCoder(coerceFunc, components, localName) {
|
|
if (!components) { components = []; }
|
|
var coders = [];
|
|
components.forEach(function(component) {
|
|
coders.push(getParamCoder(coerceFunc, component));
|
|
});
|
|
|
|
return coderTuple(coerceFunc, coders, localName);
|
|
}
|
|
|
|
function getParamCoder(coerceFunc, param) {
|
|
var coder = paramTypeSimple[param.type];
|
|
if (coder) { return coder(coerceFunc, param.name); }
|
|
|
|
var match = param.type.match(paramTypeNumber);
|
|
if (match) {
|
|
var size = parseInt(match[2] || 256);
|
|
if (size === 0 || size > 256 || (size % 8) !== 0) {
|
|
errors.throwError('invalid ' + match[1] + ' bit length', errors.INVALID_ARGUMENT, {
|
|
arg: 'param',
|
|
value: param
|
|
});
|
|
}
|
|
return coderNumber(coerceFunc, size / 8, (match[1] === 'int'), param.name);
|
|
}
|
|
|
|
var match = param.type.match(paramTypeBytes);
|
|
if (match) {
|
|
var size = parseInt(match[1]);
|
|
if (size === 0 || size > 32) {
|
|
errors.throwError('invalid bytes length', errors.INVALID_ARGUMENT, {
|
|
arg: 'param',
|
|
value: param
|
|
});
|
|
}
|
|
return coderFixedBytes(coerceFunc, size, param.name);
|
|
}
|
|
|
|
var match = param.type.match(paramTypeArray);
|
|
if (match) {
|
|
var size = parseInt(match[2] || -1);
|
|
param.type = match[1];
|
|
return coderArray(coerceFunc, getParamCoder(coerceFunc, param), size, param.name);
|
|
}
|
|
|
|
if (param.type.substring(0, 5) === 'tuple') {
|
|
return getTupleParamCoder(coerceFunc, param.components, param.name);
|
|
}
|
|
|
|
if (type === '') {
|
|
return coderNull(coerceFunc);
|
|
}
|
|
|
|
errors.throwError('invalid type', errors.INVALID_ARGUMENT, {
|
|
arg: 'type',
|
|
value: type
|
|
});
|
|
}
|
|
|
|
function Coder(coerceFunc) {
|
|
if (!(this instanceof Coder)) { throw new Error('missing new'); }
|
|
if (!coerceFunc) { coerceFunc = defaultCoerceFunc; }
|
|
utils.defineProperty(this, 'coerceFunc', coerceFunc);
|
|
}
|
|
|
|
// Legacy name support
|
|
// @TODO: In the next major version, remove names from decode/encode and don't do this
|
|
function populateNames(type, name) {
|
|
if (!name) { return; }
|
|
|
|
if (type.type.substring(0, 5) === 'tuple' && typeof(name) !== 'string') {
|
|
if (type.components.length != name.names.length) {
|
|
errors.throwError('names/types length mismatch', errors.INVALID_ARGUMENT, {
|
|
count: { names: name.names.length, types: type.components.length },
|
|
value: { names: name.names, types: type.components }
|
|
});
|
|
}
|
|
|
|
name.names.forEach(function(name, index) {
|
|
populateNames(type.components[index], name);
|
|
});
|
|
|
|
name = (name.name || '');
|
|
}
|
|
|
|
if (!type.name && typeof(name) === 'string') {
|
|
type.name = name;
|
|
}
|
|
}
|
|
|
|
utils.defineProperty(Coder.prototype, 'encode', function(names, types, values) {
|
|
|
|
// Names is optional, so shift over all the parameters if not provided
|
|
if (arguments.length < 3) {
|
|
values = types;
|
|
types = names;
|
|
names = [];
|
|
}
|
|
|
|
if (types.length !== values.length) {
|
|
errors.throwError('types/values length mismatch', errors.INVALID_ARGUMENT, {
|
|
count: { types: types.length, values: values.length },
|
|
value: { types: types, values: values }
|
|
});
|
|
}
|
|
|
|
var coders = [];
|
|
types.forEach(function(type, index) {
|
|
// Convert types to type objects
|
|
// - "uint foo" => { type: "uint", name: "foo" }
|
|
// - "tuple(uint, uint)" => { type: "tuple", components: [ { type: "uint" }, { type: "uint" }, ] }
|
|
if (typeof(type) === 'string') {
|
|
type = parseParam(type);
|
|
}
|
|
|
|
// Legacy support for passing in names (this is going away in the next major version)
|
|
populateNames(type, names[index]);
|
|
|
|
coders.push(getParamCoder(this.coerceFunc, type));
|
|
}, this);
|
|
|
|
return utils.hexlify(coderTuple(this.coerceFunc, coders).encode(values));
|
|
});
|
|
|
|
utils.defineProperty(Coder.prototype, 'decode', function(names, types, data) {
|
|
|
|
// Names is optional, so shift over all the parameters if not provided
|
|
if (arguments.length < 3) {
|
|
data = types;
|
|
types = names;
|
|
names = [];
|
|
}
|
|
|
|
data = utils.arrayify(data);
|
|
|
|
var coders = [];
|
|
types.forEach(function(type, index) {
|
|
|
|
// See encode for details
|
|
if (typeof(type) === 'string') {
|
|
type = parseParam(type);
|
|
}
|
|
|
|
// Legacy; going away in the next major version
|
|
populateNames(type, names[index]);
|
|
|
|
coders.push(getParamCoder(this.coerceFunc, type));
|
|
}, this);
|
|
|
|
return coderTuple(this.coerceFunc, coders).decode(data, 0).value;
|
|
|
|
});
|
|
|
|
utils.defineProperty(Coder, 'defaultCoder', new Coder());
|
|
|
|
utils.defineProperty(Coder, 'parseSignature', parseSignature);
|
|
|
|
|
|
module.exports = Coder
|
|
|
|
},{"../utils/address":9,"../utils/bignumber.js":10,"../utils/convert.js":11,"../utils/properties.js":14,"../utils/utf8.js":16,"./errors":12}],9:[function(require,module,exports){
|
|
|
|
var BN = require('bn.js');
|
|
|
|
var convert = require('./convert');
|
|
var throwError = require('./throw-error');
|
|
var keccak256 = require('./keccak256');
|
|
|
|
function getChecksumAddress(address) {
|
|
if (typeof(address) !== 'string' || !address.match(/^0x[0-9A-Fa-f]{40}$/)) {
|
|
throwError('invalid address', {input: address});
|
|
}
|
|
|
|
address = address.toLowerCase();
|
|
|
|
var hashed = address.substring(2).split('');
|
|
for (var i = 0; i < hashed.length; i++) {
|
|
hashed[i] = hashed[i].charCodeAt(0);
|
|
}
|
|
hashed = convert.arrayify(keccak256(hashed));
|
|
|
|
address = address.substring(2).split('');
|
|
for (var i = 0; i < 40; i += 2) {
|
|
if ((hashed[i >> 1] >> 4) >= 8) {
|
|
address[i] = address[i].toUpperCase();
|
|
}
|
|
if ((hashed[i >> 1] & 0x0f) >= 8) {
|
|
address[i + 1] = address[i + 1].toUpperCase();
|
|
}
|
|
}
|
|
|
|
return '0x' + address.join('');
|
|
}
|
|
|
|
// Shims for environments that are missing some required constants and functions
|
|
var MAX_SAFE_INTEGER = 0x1fffffffffffff;
|
|
|
|
function log10(x) {
|
|
if (Math.log10) { return Math.log10(x); }
|
|
return Math.log(x) / Math.LN10;
|
|
}
|
|
|
|
|
|
// See: https://en.wikipedia.org/wiki/International_Bank_Account_Number
|
|
var ibanChecksum = (function() {
|
|
|
|
// Create lookup table
|
|
var ibanLookup = {};
|
|
for (var i = 0; i < 10; i++) { ibanLookup[String(i)] = String(i); }
|
|
for (var i = 0; i < 26; i++) { ibanLookup[String.fromCharCode(65 + i)] = String(10 + i); }
|
|
|
|
// How many decimal digits can we process? (for 64-bit float, this is 15)
|
|
var safeDigits = Math.floor(log10(MAX_SAFE_INTEGER));
|
|
|
|
return function(address) {
|
|
address = address.toUpperCase();
|
|
address = address.substring(4) + address.substring(0, 2) + '00';
|
|
|
|
var expanded = address.split('');
|
|
for (var i = 0; i < expanded.length; i++) {
|
|
expanded[i] = ibanLookup[expanded[i]];
|
|
}
|
|
expanded = expanded.join('');
|
|
|
|
// Javascript can handle integers safely up to 15 (decimal) digits
|
|
while (expanded.length >= safeDigits){
|
|
var block = expanded.substring(0, safeDigits);
|
|
expanded = parseInt(block, 10) % 97 + expanded.substring(block.length);
|
|
}
|
|
|
|
var checksum = String(98 - (parseInt(expanded, 10) % 97));
|
|
while (checksum.length < 2) { checksum = '0' + checksum; }
|
|
|
|
return checksum;
|
|
};
|
|
})();
|
|
|
|
function getAddress(address, icapFormat) {
|
|
var result = null;
|
|
|
|
if (typeof(address) !== 'string') {
|
|
throwError('invalid address', {input: address});
|
|
}
|
|
|
|
if (address.match(/^(0x)?[0-9a-fA-F]{40}$/)) {
|
|
|
|
// Missing the 0x prefix
|
|
if (address.substring(0, 2) !== '0x') { address = '0x' + address; }
|
|
|
|
result = getChecksumAddress(address);
|
|
|
|
// It is a checksummed address with a bad checksum
|
|
if (address.match(/([A-F].*[a-f])|([a-f].*[A-F])/) && result !== address) {
|
|
throwError('invalid address checksum', { input: address, expected: result });
|
|
}
|
|
|
|
// Maybe ICAP? (we only support direct mode)
|
|
} else if (address.match(/^XE[0-9]{2}[0-9A-Za-z]{30,31}$/)) {
|
|
|
|
// It is an ICAP address with a bad checksum
|
|
if (address.substring(2, 4) !== ibanChecksum(address)) {
|
|
throwError('invalid address icap checksum', { input: address });
|
|
}
|
|
|
|
result = (new BN(address.substring(4), 36)).toString(16);
|
|
while (result.length < 40) { result = '0' + result; }
|
|
result = getChecksumAddress('0x' + result);
|
|
|
|
} else {
|
|
throwError('invalid address', { input: address });
|
|
}
|
|
|
|
if (icapFormat) {
|
|
var base36 = (new BN(result.substring(2), 16)).toString(36).toUpperCase();
|
|
while (base36.length < 30) { base36 = '0' + base36; }
|
|
return 'XE' + ibanChecksum('XE00' + base36) + base36;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
module.exports = {
|
|
getAddress: getAddress,
|
|
}
|
|
|
|
},{"./convert":11,"./keccak256":13,"./throw-error":15,"bn.js":4}],10:[function(require,module,exports){
|
|
/**
|
|
* BigNumber
|
|
*
|
|
* A wrapper around the BN.js object. In the future we can swap out
|
|
* the underlying BN.js library for something smaller.
|
|
*/
|
|
|
|
var BN = require('bn.js');
|
|
|
|
var defineProperty = require('./properties').defineProperty;
|
|
var convert = require('./convert');
|
|
var throwError = require('./throw-error');
|
|
|
|
function BigNumber(value) {
|
|
if (!(this instanceof BigNumber)) { throw new Error('missing new'); }
|
|
|
|
if (convert.isHexString(value)) {
|
|
if (value == '0x') { value = '0x0'; }
|
|
value = new BN(value.substring(2), 16);
|
|
} else if (typeof(value) === 'string' && value[0] === '-' && convert.isHexString(value.substring(1))) {
|
|
value = (new BN(value.substring(3), 16)).mul(BigNumber.constantNegativeOne._bn);
|
|
|
|
} else if (typeof(value) === 'string' && value.match(/^-?[0-9]*$/)) {
|
|
if (value == '') { value = '0'; }
|
|
value = new BN(value);
|
|
|
|
} else if (typeof(value) === 'number' && parseInt(value) == value) {
|
|
value = new BN(value);
|
|
|
|
} else if (BN.isBN(value)) {
|
|
//value = value
|
|
|
|
} else if (isBigNumber(value)) {
|
|
value = value._bn;
|
|
|
|
} else if (convert.isArrayish(value)) {
|
|
value = new BN(convert.hexlify(value).substring(2), 16);
|
|
|
|
} else {
|
|
throwError('invalid BigNumber value', { input: value });
|
|
}
|
|
|
|
defineProperty(this, '_bn', value);
|
|
}
|
|
|
|
defineProperty(BigNumber, 'constantNegativeOne', bigNumberify(-1));
|
|
defineProperty(BigNumber, 'constantZero', bigNumberify(0));
|
|
defineProperty(BigNumber, 'constantOne', bigNumberify(1));
|
|
defineProperty(BigNumber, 'constantTwo', bigNumberify(2));
|
|
defineProperty(BigNumber, 'constantWeiPerEther', bigNumberify(new BN('1000000000000000000')));
|
|
|
|
|
|
defineProperty(BigNumber.prototype, 'fromTwos', function(value) {
|
|
return new BigNumber(this._bn.fromTwos(value));
|
|
});
|
|
|
|
defineProperty(BigNumber.prototype, 'toTwos', function(value) {
|
|
return new BigNumber(this._bn.toTwos(value));
|
|
});
|
|
|
|
|
|
defineProperty(BigNumber.prototype, 'add', function(other) {
|
|
return new BigNumber(this._bn.add(bigNumberify(other)._bn));
|
|
});
|
|
|
|
defineProperty(BigNumber.prototype, 'sub', function(other) {
|
|
return new BigNumber(this._bn.sub(bigNumberify(other)._bn));
|
|
});
|
|
|
|
|
|
defineProperty(BigNumber.prototype, 'div', function(other) {
|
|
return new BigNumber(this._bn.div(bigNumberify(other)._bn));
|
|
});
|
|
|
|
defineProperty(BigNumber.prototype, 'mul', function(other) {
|
|
return new BigNumber(this._bn.mul(bigNumberify(other)._bn));
|
|
});
|
|
|
|
defineProperty(BigNumber.prototype, 'mod', function(other) {
|
|
return new BigNumber(this._bn.mod(bigNumberify(other)._bn));
|
|
});
|
|
|
|
defineProperty(BigNumber.prototype, 'pow', function(other) {
|
|
return new BigNumber(this._bn.pow(bigNumberify(other)._bn));
|
|
});
|
|
|
|
|
|
defineProperty(BigNumber.prototype, 'maskn', function(value) {
|
|
return new BigNumber(this._bn.maskn(value));
|
|
});
|
|
|
|
|
|
|
|
defineProperty(BigNumber.prototype, 'eq', function(other) {
|
|
return this._bn.eq(bigNumberify(other)._bn);
|
|
});
|
|
|
|
defineProperty(BigNumber.prototype, 'lt', function(other) {
|
|
return this._bn.lt(bigNumberify(other)._bn);
|
|
});
|
|
|
|
defineProperty(BigNumber.prototype, 'lte', function(other) {
|
|
return this._bn.lte(bigNumberify(other)._bn);
|
|
});
|
|
|
|
defineProperty(BigNumber.prototype, 'gt', function(other) {
|
|
return this._bn.gt(bigNumberify(other)._bn);
|
|
});
|
|
|
|
defineProperty(BigNumber.prototype, 'gte', function(other) {
|
|
return this._bn.gte(bigNumberify(other)._bn);
|
|
});
|
|
|
|
|
|
defineProperty(BigNumber.prototype, 'isZero', function() {
|
|
return this._bn.isZero();
|
|
});
|
|
|
|
|
|
defineProperty(BigNumber.prototype, 'toNumber', function(base) {
|
|
return this._bn.toNumber();
|
|
});
|
|
|
|
defineProperty(BigNumber.prototype, 'toString', function() {
|
|
//return this._bn.toString(base || 10);
|
|
return this._bn.toString(10);
|
|
});
|
|
|
|
defineProperty(BigNumber.prototype, 'toHexString', function() {
|
|
var hex = this._bn.toString(16);
|
|
if (hex.length % 2) { hex = '0' + hex; }
|
|
return '0x' + hex;
|
|
});
|
|
|
|
|
|
function isBigNumber(value) {
|
|
return (value._bn && value._bn.mod);
|
|
}
|
|
|
|
function bigNumberify(value) {
|
|
if (isBigNumber(value)) { return value; }
|
|
return new BigNumber(value);
|
|
}
|
|
|
|
module.exports = {
|
|
isBigNumber: isBigNumber,
|
|
bigNumberify: bigNumberify,
|
|
BigNumber: BigNumber
|
|
};
|
|
|
|
},{"./convert":11,"./properties":14,"./throw-error":15,"bn.js":4}],11:[function(require,module,exports){
|
|
/**
|
|
* Conversion Utilities
|
|
*
|
|
*/
|
|
|
|
var defineProperty = require('./properties.js').defineProperty;
|
|
|
|
var errors = require('./errors');
|
|
|
|
function addSlice(array) {
|
|
if (array.slice) { return array; }
|
|
|
|
array.slice = function() {
|
|
var args = Array.prototype.slice.call(arguments);
|
|
return new Uint8Array(Array.prototype.slice.apply(array, args));
|
|
}
|
|
|
|
return array;
|
|
}
|
|
|
|
function isArrayish(value) {
|
|
if (!value || parseInt(value.length) != value.length || typeof(value) === 'string') {
|
|
return false;
|
|
}
|
|
|
|
for (var i = 0; i < value.length; i++) {
|
|
var v = value[i];
|
|
if (v < 0 || v >= 256 || parseInt(v) != v) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
function arrayify(value) {
|
|
if (value == null) {
|
|
errors.throwError('cannot convert null value to array', errors.INVALID_ARGUMENT, { arg: 'value', value: value });
|
|
}
|
|
|
|
if (value && value.toHexString) {
|
|
value = value.toHexString();
|
|
}
|
|
|
|
if (isHexString(value)) {
|
|
value = value.substring(2);
|
|
if (value.length % 2) { value = '0' + value; }
|
|
|
|
var result = [];
|
|
for (var i = 0; i < value.length; i += 2) {
|
|
result.push(parseInt(value.substr(i, 2), 16));
|
|
}
|
|
|
|
return addSlice(new Uint8Array(result));
|
|
|
|
} else if (typeof(value) === 'string') {
|
|
if (value.match(/^[0-9a-fA-F]*$/)) {
|
|
errors.throwError('hex string must have 0x prefix', errors.INVALID_ARGUMENT, { arg: 'value', value: value });
|
|
}
|
|
errors.throwError('invalid hexidecimal string', errors.INVALID_ARGUMENT, { arg: 'value', value: value });
|
|
}
|
|
|
|
if (isArrayish(value)) {
|
|
return addSlice(new Uint8Array(value));
|
|
}
|
|
|
|
errors.throwError('invalid arrayify value', { arg: 'value', value: value, type: typeof(value) });
|
|
}
|
|
|
|
function concat(objects) {
|
|
var arrays = [];
|
|
var length = 0;
|
|
for (var i = 0; i < objects.length; i++) {
|
|
var object = arrayify(objects[i])
|
|
arrays.push(object);
|
|
length += object.length;
|
|
}
|
|
|
|
var result = new Uint8Array(length);
|
|
var offset = 0;
|
|
for (var i = 0; i < arrays.length; i++) {
|
|
result.set(arrays[i], offset);
|
|
offset += arrays[i].length;
|
|
}
|
|
|
|
return addSlice(result);
|
|
}
|
|
function stripZeros(value) {
|
|
value = arrayify(value);
|
|
|
|
if (value.length === 0) { return value; }
|
|
|
|
// Find the first non-zero entry
|
|
var start = 0;
|
|
while (value[start] === 0) { start++ }
|
|
|
|
// If we started with zeros, strip them
|
|
if (start) {
|
|
value = value.slice(start);
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
function padZeros(value, length) {
|
|
value = arrayify(value);
|
|
|
|
if (length < value.length) { throw new Error('cannot pad'); }
|
|
|
|
var result = new Uint8Array(length);
|
|
result.set(value, length - value.length);
|
|
return addSlice(result);
|
|
}
|
|
|
|
|
|
function isHexString(value, length) {
|
|
if (typeof(value) !== 'string' || !value.match(/^0x[0-9A-Fa-f]*$/)) {
|
|
return false
|
|
}
|
|
if (length && value.length !== 2 + 2 * length) { return false; }
|
|
return true;
|
|
}
|
|
|
|
var HexCharacters = '0123456789abcdef';
|
|
|
|
function hexlify(value) {
|
|
|
|
if (value && value.toHexString) {
|
|
return value.toHexString();
|
|
}
|
|
|
|
if (typeof(value) === 'number') {
|
|
if (value < 0) {
|
|
errors.throwError('cannot hexlify negative value', errors.INVALID_ARG, { arg: 'value', value: value });
|
|
}
|
|
|
|
var hex = '';
|
|
while (value) {
|
|
hex = HexCharacters[value & 0x0f] + hex;
|
|
value = parseInt(value / 16);
|
|
}
|
|
|
|
if (hex.length) {
|
|
if (hex.length % 2) { hex = '0' + hex; }
|
|
return '0x' + hex;
|
|
}
|
|
|
|
return '0x00';
|
|
}
|
|
|
|
if (isHexString(value)) {
|
|
if (value.length % 2) {
|
|
value = '0x0' + value.substring(2);
|
|
}
|
|
return value;
|
|
}
|
|
|
|
if (isArrayish(value)) {
|
|
var result = [];
|
|
for (var i = 0; i < value.length; i++) {
|
|
var v = value[i];
|
|
result.push(HexCharacters[(v & 0xf0) >> 4] + HexCharacters[v & 0x0f]);
|
|
}
|
|
return '0x' + result.join('');
|
|
}
|
|
|
|
errors.throwError('invalid hexlify value', { arg: 'value', value: value });
|
|
}
|
|
|
|
function hexStripZeros(value) {
|
|
while (value.length > 3 && value.substring(0, 3) === '0x0') {
|
|
value = '0x' + value.substring(3);
|
|
}
|
|
return value;
|
|
}
|
|
|
|
function hexZeroPad(value, length) {
|
|
while (value.length < 2 * length + 2) {
|
|
value = '0x0' + value.substring(2);
|
|
}
|
|
return value;
|
|
}
|
|
|
|
/* @TODO: Add something like this to make slicing code easier to understand
|
|
function hexSlice(hex, start, end) {
|
|
hex = hexlify(hex);
|
|
return '0x' + hex.substring(2 + start * 2, 2 + end * 2);
|
|
}
|
|
*/
|
|
|
|
function splitSignature(signature) {
|
|
signature = arrayify(signature);
|
|
if (signature.length !== 65) {
|
|
throw new Error('invalid signature');
|
|
}
|
|
|
|
var v = signature[64];
|
|
if (v !== 27 && v !== 28) {
|
|
v = 27 + (v % 2);
|
|
}
|
|
|
|
return {
|
|
r: hexlify(signature.slice(0, 32)),
|
|
s: hexlify(signature.slice(32, 64)),
|
|
v: v
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
arrayify: arrayify,
|
|
isArrayish: isArrayish,
|
|
|
|
concat: concat,
|
|
|
|
padZeros: padZeros,
|
|
stripZeros: stripZeros,
|
|
|
|
splitSignature: splitSignature,
|
|
|
|
hexlify: hexlify,
|
|
isHexString: isHexString,
|
|
hexStripZeros: hexStripZeros,
|
|
hexZeroPad: hexZeroPad,
|
|
};
|
|
|
|
},{"./errors":12,"./properties.js":14}],12:[function(require,module,exports){
|
|
'use strict';
|
|
|
|
var defineProperty = require('./properties').defineProperty;
|
|
|
|
var codes = { };
|
|
|
|
[
|
|
// Unknown Error
|
|
'UNKNOWN_ERROR',
|
|
|
|
// Not implemented
|
|
'NOT_IMPLEMENTED',
|
|
|
|
// Missing new operator to an object
|
|
// - name: The name of the class
|
|
'MISSING_NEW',
|
|
|
|
|
|
// Call exception
|
|
'CALL_EXCEPTION',
|
|
|
|
|
|
// Response from a server was invalid
|
|
// - response: The body of the response
|
|
//'BAD_RESPONSE',
|
|
|
|
|
|
// Invalid argument (e.g. type) to a function:
|
|
// - arg: The argument name that was invalid
|
|
// - value: The value of the argument
|
|
// - type: The type of the argument
|
|
// - expected: What was expected
|
|
'INVALID_ARGUMENT',
|
|
|
|
// Missing argument to a function:
|
|
// - arg: The argument name that is required
|
|
// - count: The number of arguments received
|
|
// - expectedCount: The number of arguments expected
|
|
'MISSING_ARGUMENT',
|
|
|
|
// Too many arguments
|
|
// - count: The number of arguments received
|
|
// - expectedCount: The number of arguments expected
|
|
'UNEXPECTED_ARGUMENT',
|
|
|
|
|
|
// Unsupported operation
|
|
// - operation
|
|
'UNSUPPORTED_OPERATION',
|
|
|
|
|
|
].forEach(function(code) {
|
|
defineProperty(codes, code, code);
|
|
});
|
|
|
|
|
|
defineProperty(codes, 'throwError', function(message, code, params) {
|
|
if (!code) { code = codes.UNKNOWN_ERROR; }
|
|
if (!params) { params = {}; }
|
|
|
|
var messageDetails = [];
|
|
Object.keys(params).forEach(function(key) {
|
|
try {
|
|
messageDetails.push(key + '=' + JSON.stringify(params[key]));
|
|
} catch (error) {
|
|
messageDetails.push(key + '=' + JSON.stringify(params[key].toString()));
|
|
}
|
|
});
|
|
var reason = message;
|
|
if (messageDetails.length) {
|
|
message += ' (' + messageDetails.join(', ') + ')';
|
|
}
|
|
|
|
var error = new Error(message);
|
|
error.reason = reason;
|
|
error.code = code
|
|
|
|
Object.keys(params).forEach(function(key) {
|
|
error[key] = params[key];
|
|
});
|
|
|
|
throw error;
|
|
});
|
|
|
|
defineProperty(codes, 'checkNew', function(self, kind) {
|
|
if (!(self instanceof kind)) {
|
|
codes.throwError('missing new', codes.MISSING_NEW, { name: kind.name });
|
|
}
|
|
});
|
|
|
|
module.exports = codes;
|
|
|
|
},{"./properties":14}],13:[function(require,module,exports){
|
|
'use strict';
|
|
|
|
var sha3 = require('js-sha3');
|
|
|
|
var convert = require('./convert.js');
|
|
|
|
function keccak256(data) {
|
|
data = convert.arrayify(data);
|
|
return '0x' + sha3.keccak_256(data);
|
|
}
|
|
|
|
module.exports = keccak256;
|
|
|
|
},{"./convert.js":11,"js-sha3":6}],14:[function(require,module,exports){
|
|
'use strict';
|
|
|
|
function defineProperty(object, name, value) {
|
|
Object.defineProperty(object, name, {
|
|
enumerable: true,
|
|
value: value,
|
|
writable: false,
|
|
});
|
|
}
|
|
|
|
function defineFrozen(object, name, value) {
|
|
var frozen = JSON.stringify(value);
|
|
Object.defineProperty(object, name, {
|
|
enumerable: true,
|
|
get: function() { return JSON.parse(frozen); }
|
|
});
|
|
}
|
|
|
|
module.exports = {
|
|
defineFrozen: defineFrozen,
|
|
defineProperty: defineProperty,
|
|
};
|
|
|
|
},{}],15:[function(require,module,exports){
|
|
'use strict';
|
|
|
|
function throwError(message, params) {
|
|
var error = new Error(message);
|
|
for (var key in params) {
|
|
error[key] = params[key];
|
|
}
|
|
throw error;
|
|
}
|
|
|
|
module.exports = throwError;
|
|
|
|
},{}],16:[function(require,module,exports){
|
|
|
|
var convert = require('./convert.js');
|
|
|
|
// http://stackoverflow.com/questions/18729405/how-to-convert-utf8-string-to-byte-array
|
|
function utf8ToBytes(str) {
|
|
var result = [];
|
|
var offset = 0;
|
|
for (var i = 0; i < str.length; i++) {
|
|
var c = str.charCodeAt(i);
|
|
if (c < 128) {
|
|
result[offset++] = c;
|
|
} else if (c < 2048) {
|
|
result[offset++] = (c >> 6) | 192;
|
|
result[offset++] = (c & 63) | 128;
|
|
} else if (((c & 0xFC00) == 0xD800) && (i + 1) < str.length && ((str.charCodeAt(i + 1) & 0xFC00) == 0xDC00)) {
|
|
// Surrogate Pair
|
|
c = 0x10000 + ((c & 0x03FF) << 10) + (str.charCodeAt(++i) & 0x03FF);
|
|
result[offset++] = (c >> 18) | 240;
|
|
result[offset++] = ((c >> 12) & 63) | 128;
|
|
result[offset++] = ((c >> 6) & 63) | 128;
|
|
result[offset++] = (c & 63) | 128;
|
|
} else {
|
|
result[offset++] = (c >> 12) | 224;
|
|
result[offset++] = ((c >> 6) & 63) | 128;
|
|
result[offset++] = (c & 63) | 128;
|
|
}
|
|
}
|
|
|
|
return convert.arrayify(result);
|
|
};
|
|
|
|
|
|
// http://stackoverflow.com/questions/13356493/decode-utf-8-with-javascript#13691499
|
|
function bytesToUtf8(bytes) {
|
|
bytes = convert.arrayify(bytes);
|
|
|
|
var result = '';
|
|
var i = 0;
|
|
|
|
// Invalid bytes are ignored
|
|
while(i < bytes.length) {
|
|
var c = bytes[i++];
|
|
if (c >> 7 == 0) {
|
|
// 0xxx xxxx
|
|
result += String.fromCharCode(c);
|
|
continue;
|
|
}
|
|
|
|
// Invalid starting byte
|
|
if (c >> 6 == 0x02) { continue; }
|
|
|
|
// Multibyte; how many bytes left for thus character?
|
|
var extraLength = null;
|
|
if (c >> 5 == 0x06) {
|
|
extraLength = 1;
|
|
} else if (c >> 4 == 0x0e) {
|
|
extraLength = 2;
|
|
} else if (c >> 3 == 0x1e) {
|
|
extraLength = 3;
|
|
} else if (c >> 2 == 0x3e) {
|
|
extraLength = 4;
|
|
} else if (c >> 1 == 0x7e) {
|
|
extraLength = 5;
|
|
} else {
|
|
continue;
|
|
}
|
|
|
|
// Do we have enough bytes in our data?
|
|
if (i + extraLength > bytes.length) {
|
|
|
|
// If there is an invalid unprocessed byte, try to continue
|
|
for (; i < bytes.length; i++) {
|
|
if (bytes[i] >> 6 != 0x02) { break; }
|
|
}
|
|
if (i != bytes.length) continue;
|
|
|
|
// All leftover bytes are valid.
|
|
return result;
|
|
}
|
|
|
|
// Remove the UTF-8 prefix from the char (res)
|
|
var res = c & ((1 << (8 - extraLength - 1)) - 1);
|
|
|
|
var count;
|
|
for (count = 0; count < extraLength; count++) {
|
|
var nextChar = bytes[i++];
|
|
|
|
// Is the char valid multibyte part?
|
|
if (nextChar >> 6 != 0x02) {break;};
|
|
res = (res << 6) | (nextChar & 0x3f);
|
|
}
|
|
|
|
if (count != extraLength) {
|
|
i--;
|
|
continue;
|
|
}
|
|
|
|
if (res <= 0xffff) {
|
|
result += String.fromCharCode(res);
|
|
continue;
|
|
}
|
|
|
|
res -= 0x10000;
|
|
result += String.fromCharCode(((res >> 10) & 0x3ff) + 0xd800, (res & 0x3ff) + 0xdc00);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
module.exports = {
|
|
toUtf8Bytes: utf8ToBytes,
|
|
toUtf8String: bytesToUtf8,
|
|
};
|
|
|
|
},{"./convert.js":11}]},{},[2])(2)
|
|
}); |