diff --git a/bitcore-wallet-client.js b/bitcore-wallet-client.js index b7bdbd42..e3c2c48b 100644 --- a/bitcore-wallet-client.js +++ b/bitcore-wallet-client.js @@ -15,15 +15,20 @@ var events = require('events'); var WalletUtils = require('bitcore-wallet-utils'); var Bitcore = WalletUtils.Bitcore; var sjcl = require('sjcl'); +var io = require('socket.io-client'); +var url = require('url'); var request; if (process && !process.browser) { request = require('request'); -} -else { +} else { request = require('browser-request'); } +var PayPro = require('bitcore-payment-protocol'); + + +var PayProRequest = require('./payprorequest'); var log = require('./log'); var Credentials = require('./credentials'); var Verifier = require('./verifier'); @@ -44,7 +49,11 @@ function API(opts) { this.verbose = !!opts.verbose; this.request = opts.request || request; this.baseUrl = opts.baseUrl || BASE_URL; - this.basePath = this.baseUrl.replace(/http.?:\/\/[a-zA-Z0-9:-]*\//, '/'); + var parsedUrl = url.parse(this.baseUrl); + this.basePath = parsedUrl.path; + this.baseHost = parsedUrl.protocol + '//' + parsedUrl.host; + this.payProGetter = null; // Only for testing + if (this.verbose) { log.setLevel('debug'); } else { @@ -54,6 +63,40 @@ function API(opts) { util.inherits(API, events.EventEmitter); +API.prototype.initNotifications = function(cb) { + $.checkState(this.credentials); + + var self = this; + var socket = io.connect(self.baseHost, { + 'force new connection': true, + }); + + socket.on('unauthorized', function() { + return cb(new Error('Could not establish web-sockets connection: Unauthorized')); + }); + + socket.on('authorized', function() { + return cb(); + }); + + socket.on('notification', function(data) { + if (data.creatorId != self.credentials.copayerId) { + self.emit('notification', data); + } + }); + + socket.on('challenge', function(nonce) { + $.checkArgument(nonce); + + var auth = { + copayerId: self.credentials.copayerId, + message: nonce, + signature: WalletUtils.signMessage(nonce, self.credentials.requestPrivKey), + }; + socket.emit('authorize', auth); + }); +}; + /** * Encrypt a message * @private @@ -528,6 +571,27 @@ API.prototype.getStatus = function(cb) { }); }; +API.prototype._computeProposalSignature = function(args) { + $.shouldBeNumber(args.amount); + var hash = WalletUtils.getProposalHash(args.toAddress, args.amount, args.message, args.payProUrl); + return WalletUtils.signMessage(hash, this.credentials.requestPrivKey); +} + +API.prototype.fetchPayPro = function(opts, cb) { + $.checkArgument(opts) + .checkArgument(opts.payProUrl); + + PayProRequest.get({ + url: opts.payProUrl, + getter: this.payProGetter, + }, function(err, paypro) { + if (err) + return cb(err || 'Could not fetch PayPro request'); + + return cb(null, paypro); + }); +}; + /** * Send a transaction proposal * @@ -535,25 +599,23 @@ API.prototype.getStatus = function(cb) { * @param {String} opts.toAddress * @param {Number} opts.amount * @param {String} opts.message + * @param {String} opts.payProUrl Optional: Tx is from a from a payment protocol URL * @returns {Callback} cb - Return error or the transaction proposal */ API.prototype.sendTxProposal = function(opts, cb) { $.checkState(this.credentials && this.credentials.isComplete()); $.checkArgument(opts); - $.shouldBeNumber(opts.amount); - - var self = this; var args = { toAddress: opts.toAddress, amount: opts.amount, - message: API._encryptMessage(opts.message, self.credentials.sharedEncryptingKey), + message: API._encryptMessage(opts.message, this.credentials.sharedEncryptingKey), + payProUrl: opts.payProUrl, }; - var hash = WalletUtils.getProposalHash(args.toAddress, args.amount, args.message); - args.proposalSignature = WalletUtils.signMessage(hash, self.credentials.requestPrivKey); - log.debug('Generating & signing tx proposal hash -> Hash: ', hash, ' Signature: ', args.proposalSignature); + log.debug('Generating & signing tx proposal:', JSON.stringify(args)); + args.proposalSignature = this._computeProposalSignature(args); - self._doPostRequest('/v1/txproposals/', args, function(err, txp) { + this._doPostRequest('/v1/txproposals/', args, function(err, txp) { if (err) return cb(err); return cb(null, txp); }); @@ -636,27 +698,36 @@ API.prototype.getTxProposals = function(opts, cb) { if (err) return cb(err); API._processTxps(txps, self.credentials.sharedEncryptingKey); + async.every(txps, + function(txp, acb) { + if (opts.doNotVerify) return acb(true); - var fake = _.any(txps, function(txp) { - return (!opts.doNotVerify && !Verifier.checkTxProposal(self.credentials, txp)); - }); - - if (fake) - return cb(new ServerCompromisedError('Server sent fake transaction proposal')); + Verifier.checkTxProposal(self.credentials, txp, { + payProGetter: self.payProGetter + }, function(err, isLegit) { + if (err) + return cb(new Error('Cannot check transaction now:' + err)); - var result; - if (opts.forAirGapped) { - result = { - txps: JSON.parse(JSON.stringify(txps)), - encryptedPkr: WalletUtils.encryptMessage(JSON.stringify(self.credentials.publicKeyRing), self.credentials.personalEncryptingKey), - m: self.credentials.m, - n: self.credentials.n, - }; - } else { - result = txps; - } + return acb(isLegit); + }); + }, + function(isLegit) { + if (!isLegit) + return cb(new ServerCompromisedError('Server sent fake transaction proposal')); - return cb(null, result); + var result; + if (opts.forAirGapped) { + result = { + txps: JSON.parse(JSON.stringify(txps)), + encryptedPkr: WalletUtils.encryptMessage(JSON.stringify(self.credentials.publicKeyRing), self.credentials.personalEncryptingKey), + m: self.credentials.m, + n: self.credentials.n, + }; + } else { + result = txps; + } + return cb(null, result); + }); }); }; @@ -676,21 +747,29 @@ API.prototype.signTxProposal = function(txp, cb) { if (!self.canSign() && !txp.signatures) return cb(new Error('You do not have the required keys to sign transactions')); - if (!Verifier.checkTxProposal(self.credentials, txp)) { - return cb(new ServerCompromisedError('Server sent fake transaction proposal')); - } - var signatures = txp.signatures || WalletUtils.signTxp(txp, self.credentials.xPrivKey); + Verifier.checkTxProposal(self.credentials, txp, { + payProGetter: self.payProGetter, + }, function(err, isLegit) { - var url = '/v1/txproposals/' + txp.id + '/signatures/'; - var args = { - signatures: signatures - }; + if (err) + return cb(new Error('Cannot check transaction now:' + err)); - self._doPostRequest(url, args, function(err, txp) { - if (err) return cb(err); - return cb(null, txp); - }); + if (!isLegit) + return cb(new ServerCompromisedError('Server sent fake transaction proposal')); + + var signatures = txp.signatures || WalletUtils.signTxp(txp, self.credentials.xPrivKey); + + var url = '/v1/txproposals/' + txp.id + '/signatures/'; + var args = { + signatures: signatures + }; + + self._doPostRequest(url, args, function(err, txp) { + if (err) return cb(err); + return cb(null, txp); + }); + }) }; /** @@ -725,9 +804,10 @@ API.prototype.signTxProposalFromAirGapped = function(txp, encryptedPkr, m, n) { self.credentials.n = n; self.credentials.addPublicKeyRing(publicKeyRing); - if (!Verifier.checkTxProposal(self.credentials, txp)) { + // When forAirGapped=true -> checkTxProposal is sync + if (!Verifier.checkTxProposalBody(self.credentials, txp)) throw new Error('Fake transaction proposal'); - } + return WalletUtils.signTxp(txp, self.credentials.xPrivKey); }; @@ -798,8 +878,7 @@ API.prototype.removeTxProposal = function(txp, cb) { * Get transaction history * * @param {Object} opts - * @param {Number} opts.minTs (defaults to 0) - * @param {Number} opts.maxTs (defaults to now) + * @param {Number} opts.skip (defaults to 0) * @param {Number} opts.limit * @param {Callback} cb * @return {Callback} cb - Return error or array of transactions @@ -810,8 +889,7 @@ API.prototype.getTxHistory = function(opts, cb) { var self = this; var args = []; if (opts) { - if (opts.minTs) args.push('minTs=' + opts.minTs); - if (opts.maxTs) args.push('maxTs=' + opts.maxTs); + if (opts.skip) args.push('skip=' + opts.skip); if (opts.limit) args.push('limit=' + opts.limit); } var qs = ''; @@ -832,7 +910,7 @@ API.prototype.getTxHistory = function(opts, cb) { module.exports = API; }).call(this,require('_process')) -},{"./clienterror":3,"./credentials":4,"./log":6,"./servercompromisederror":7,"./verifier":8,"_process":252,"async":9,"bitcore-wallet-utils":10,"browser-request":87,"events":243,"lodash":275,"preconditions":276,"request":281,"sjcl":338,"util":272}],3:[function(require,module,exports){ +},{"./clienterror":3,"./credentials":4,"./log":6,"./payprorequest":7,"./servercompromisederror":8,"./verifier":10,"_process":357,"async":11,"bitcore-payment-protocol":12,"bitcore-wallet-utils":108,"browser-request":192,"events":348,"lodash":380,"preconditions":381,"request":386,"sjcl":443,"socket.io-client":444,"url":375,"util":377}],3:[function(require,module,exports){ function ClientError(code, message) { this.code = code; this.message = message; @@ -1036,7 +1114,7 @@ Credentials.importCompressed = function(compressed) { module.exports = Credentials; -},{"bitcore-wallet-utils":10,"lodash":275,"preconditions":276}],5:[function(require,module,exports){ +},{"bitcore-wallet-utils":108,"lodash":380,"preconditions":381}],5:[function(require,module,exports){ /** * The official client library for bitcore-wallet-service. * @module Client @@ -1054,10 +1132,12 @@ var client = module.exports = require('./api'); */ client.Verifier = require('./verifier'); +client.Utils = require('./utils'); + // Expose bitcore client.Bitcore = require('bitcore-wallet-utils').Bitcore; -},{"./api":2,"./verifier":8,"bitcore-wallet-utils":10}],6:[function(require,module,exports){ +},{"./api":2,"./utils":9,"./verifier":10,"bitcore-wallet-utils":108}],6:[function(require,module,exports){ var _ = require('lodash'); /** * @desc @@ -1185,7 +1265,159 @@ var error = new Error(); logger.setLevel('info'); module.exports = logger; -},{"lodash":275}],7:[function(require,module,exports){ +},{"lodash":380}],7:[function(require,module,exports){ +(function (process,Buffer){ +var $ = require('preconditions').singleton(); + +var WalletUtils = require('bitcore-wallet-utils'); +var Bitcore = WalletUtils.Bitcore; +var PayPro = require('bitcore-payment-protocol'); +var PayProRequest = {}; + +PayProRequest._nodeGet = function(opts, cb) { + opts.agent = false; + var http = opts.http || (opts.proto === 'http' ? require("http") : require("https")); + + http.get(opts, function(res) { + if (res.statusCode != 200) + return cb('HTTP Request Error'); + + var data = []; // List of Buffer objects + res.on("data", function(chunk) { + data.push(chunk); // Append Buffer object + }); + res.on("end", function() { + data = Buffer.concat(data); // Make one large Buffer of it + return cb(null, data); + }); + }); +}; + +PayProRequest._browserGet = function(opts, cb) { + var method = (opts.method || 'GET').toUpperCase(); + var url = opts.url; + var req = opts; + + req.headers = req.headers || {}; + req.body = req.body || req.data || ''; + + var xhr = opts.xhr || new XMLHttpRequest(); + xhr.open(method, url, true); + + Object.keys(req.headers).forEach(function(key) { + var val = req.headers[key]; + if (key === 'Content-Length') return; + if (key === 'Content-Transfer-Encoding') return; + xhr.setRequestHeader(key, val); + }); + xhr.responseType = 'arraybuffer'; + + xhr.onload = function(event) { + var response = xhr.response; + return cb(null, new Uint8Array(response)); + }; + + xhr.onerror = function(event) { + var status; + if (xhr.status === 0 || !xhr.statusText) { + status = 'HTTP Request Error'; + } else { + status = xhr.statusText; + } + return cb(status); + }; + + xhr.send(null); +}; + +PayProRequest.get = function(opts, cb) { + $.checkArgument(opts && opts.url); + + var getter = opts.getter; + + opts.headers = opts.headers || { + 'Accept': PayPro.PAYMENT_REQUEST_CONTENT_TYPE, + 'Content-Type': 'application/octet-stream', + }; + + if (!opts.getter) { + var env = opts.env; + if (!env) + env = (process && !process.browser) ? 'node' : 'browser'; + + if (env == "node") { + getter = PayProRequest._nodeGet; + } else { + getter = PayProRequest._browserGet; + } + } + + var match = opts.url.match(/^((http[s]?|ftp):\/)?\/?([^:\/\s]+)((\/\w+)*\/)([\w\-\.]+[^#?\s]+)(.*)?(#[\w\-]+)?$/); + + opts.proto = RegExp.$2; + opts.host = RegExp.$3; + opts.path = RegExp.$4 + RegExp.$6; + + getter(opts, function(err, dataBuffer) { + if (err) return cb(err); + var body = PayPro.PaymentRequest.decode(dataBuffer); + var request = (new PayPro()).makePaymentRequest(body); + + var signature = request.get('signature'); + var serializedDetails = request.get('serialized_payment_details'); + + // Verify the signature + var verified = request.verify(true); + + // Get the payment details + var decodedDetails = PayPro.PaymentDetails.decode(serializedDetails); + var pd = new PayPro(); + pd = pd.makePaymentDetails(decodedDetails); + + var outputs = pd.get('outputs'); + if (outputs.length > 1) + return cb(new Error('Payment Protocol Error: Requests with more that one output are not supported')) + + var output = outputs[0]; + + var amount = output.get('amount'); + amount = amount.low + amount.high * 0x100000000; + + + var network = pd.get('network') == 'test' ? 'testnet' : 'livenet'; + + // We love payment protocol + var offset = output.get('script').offset; + var limit = output.get('script').limit; + + // NOTE: For some reason output.script.buffer + // is only an ArrayBuffer + var buffer = new Buffer(new Uint8Array(output.get('script').buffer)); + var scriptBuf = buffer.slice(offset, limit); + var addr = new Bitcore.Address.fromScript(new Bitcore.Script(scriptBuf), network); + + return cb(null, { + verified: verified.verified, + verifyData: { + caName: verified.caName, + selfSigned: verified.selfSigned, + }, + expires: pd.get('expires'), + memo: pd.get('memo'), + time: pd.get('time'), + toAddress: addr.toString(), + amount: amount, + network: network, + domain: opts.host, + url: opts.url, + }); + }); +}; + +module.exports = PayProRequest; + +}).call(this,require('_process'),require("buffer").Buffer) +},{"_process":357,"bitcore-payment-protocol":12,"bitcore-wallet-utils":108,"buffer":209,"http":349,"https":353,"preconditions":381}],8:[function(require,module,exports){ function ServerCompromisedError(message) { this.code = 'SERVERCOMPROMISED'; this.message = message; @@ -1193,7 +1425,48 @@ function ServerCompromisedError(message) { module.exports = ServerCompromisedError; -},{}],8:[function(require,module,exports){ +},{}],9:[function(require,module,exports){ +'use strict'; + +var _ = require('lodash'); +var $ = require('preconditions').singleton(); + +var Utils = {}; + +var _UNITS = { + btc: { + toSatoshis: 100000000, + decimals: 6 + }, + bit: { + toSatoshis: 100, + decimals: 0 + }, +}; + +Utils.formatAmount = function(satoshis, unit, opts) { + $.shouldBeNumber(satoshis); + $.checkArgument(_.contains(_.keys(_UNITS), unit)); + + function addSeparators(nStr, thousands, decimal) { + nStr = nStr.replace('.', decimal); + var x = nStr.split(decimal); + var x1 = x[0]; + var x2 = x.length > 1 ? decimal + x[1] : ''; + x1 = x1.replace(/\B(?=(\d{3})+(?!\d))/g, thousands); + return x1 + x2; + } + + opts = opts || {}; + + var u = _UNITS[unit]; + var amount = (satoshis / u.toSatoshis).toFixed(u.decimals); + return addSeparators(amount, opts.thousandsSeparator || ',', opts.decimalSeparator || '.'); +}; + +module.exports = Utils; + +},{"lodash":380,"preconditions":381}],10:[function(require,module,exports){ /** @namespace Verifier */ var $ = require('preconditions').singleton(); @@ -1203,6 +1476,7 @@ var WalletUtils = require('bitcore-wallet-utils'); var Bitcore = WalletUtils.Bitcore; var log = require('./log'); +var PayProRequest = require('./payprorequest'); /** * @desc Verifier constructor. Checks data given by the server @@ -1271,14 +1545,7 @@ Verifier.checkCopayers = function(credentials, copayers) { return true; }; -/** - * Check transaction proposal - * - * @param {Function} credentials - * @param {Object} txp - * @returns {Boolean} true or false - */ -Verifier.checkTxProposal = function(credentials, txp) { +Verifier.checkTxProposalBody = function(credentials, txp) { $.checkArgument(txp.creatorId); $.checkState(credentials.isComplete()); @@ -1290,20 +1557,54 @@ Verifier.checkTxProposal = function(credentials, txp) { // TODO: this should be an independent key var creatorSigningPubKey = creatorKeys.requestPubKey; - - var hash = WalletUtils.getProposalHash(txp.toAddress, txp.amount, txp.encryptedMessage || txp.message); + var hash = WalletUtils.getProposalHash(txp.toAddress, txp.amount, txp.encryptedMessage || txp.message, txp.payProUrl); log.debug('Regenerating & verifying tx proposal hash -> Hash: ', hash, ' Signature: ', txp.proposalSignature); - if (!WalletUtils.verifyMessage(hash, txp.proposalSignature, creatorSigningPubKey)) return false; - return Verifier.checkAddress(credentials, txp.changeAddress); + if (!Verifier.checkAddress(credentials, txp.changeAddress)) + return false; + + return true; +}; + + + +/** + * Check transaction proposal + * + * @param {Function} credentials + * @param {Object} txp + * @param {Object} Optional: paypro + * @param {Callback} cb(err, isLegit) + */ +Verifier.checkTxProposal = function(credentials, txp, opts, cb) { + if (!this.checkTxProposalBody(credentials, txp)) + return cb(null, false); + + if (txp.payProUrl) { + PayProRequest.get({ + url: txp.payProUrl, + getter: opts.payProGetter, + }, function(err, paypro) { + if (err) + return cb(err || 'Could not fetch PayPro request'); + + var isLegit = false; + if (txp.toAddress == paypro.toAddress && txp.amount == paypro.amount) { + isLegit = true; + } + return cb(null, isLegit); + }); + } else { + return cb(null, true); + } }; module.exports = Verifier; -},{"./log":6,"bitcore-wallet-utils":10,"lodash":275,"preconditions":276}],9:[function(require,module,exports){ +},{"./log":6,"./payprorequest":7,"bitcore-wallet-utils":108,"lodash":380,"preconditions":381}],11:[function(require,module,exports){ (function (process){ /*! * async @@ -2430,14577 +2731,18182 @@ module.exports = Verifier; }()); }).call(this,require('_process')) -},{"_process":252}],10:[function(require,module,exports){ -var utils = module.exports = require('./lib/walletutils'); -utils.Bitcore = require('bitcore'); - -},{"./lib/walletutils":11,"bitcore":12}],11:[function(require,module,exports){ +},{"_process":357}],12:[function(require,module,exports){ (function (Buffer){ 'use strict'; -var _ = require('lodash'); -var $ = require('preconditions').singleton(); -var sjcl = require('sjcl'); +var KJUR = require('jsrsasign'); +var PaymentProtocol = require('./common'); +var RootCerts = require('./rootcerts'); +var rfc3280 = require('asn1.js/rfc/3280'); -var Bitcore = require('bitcore'); -var Address = Bitcore.Address; -var PrivateKey = Bitcore.PrivateKey; -var PublicKey = Bitcore.PublicKey; -var crypto = Bitcore.crypto; -var encoding = Bitcore.encoding; +// Documentation: +// http://kjur.github.io/jsrsasign/api/symbols/KJUR.crypto.Signature.html#.sign +// http://kjur.github.io/jsrsasign/api/symbols/RSAKey.html -function WalletUtils() {}; +PaymentProtocol.prototype.x509Sign = function(key, returnTrust) { + var pki_type = this.get('pki_type'); + var pki_data = this.get('pki_data'); // contains one or more x509 certs + pki_data = PaymentProtocol.X509Certificates.decode(pki_data); + pki_data = pki_data.certificate; + var type = pki_type !== 'none' ? pki_type.split('+')[1].toUpperCase() : pki_type; + var buf = this.serializeForSig(); -WalletUtils.PATHS = { - BASE_ADDRESS_DERIVATION: "m/45'", - REQUEST_KEY: "m/1'/0", - TXPROPOSAL_KEY: "m/1'/1", -}; + var rsa = new KJUR.RSAKey(); + rsa.readPrivateKeyFromPEMString(key.toString()); + key = rsa; -/* TODO: It would be nice to be compatible with bitcoind signmessage. How - * the hash is calculated there? */ -WalletUtils.hashMessage = function(text) { - $.checkArgument(text); - var buf = new Buffer(text); - var ret = crypto.Hash.sha256sha256(buf); - ret = new Bitcore.encoding.BufferReader(ret).readReverse(); - return ret; -}; + var sig; + if (type !== 'none') { + var jsrsaSig = new KJUR.crypto.Signature({ + alg: type + 'withRSA', + prov: 'cryptojs/jsrsa' + }); -WalletUtils.signMessage = function(text, privKey) { - $.checkArgument(text); - var priv = new PrivateKey(privKey); - var hash = WalletUtils.hashMessage(text); - return crypto.ECDSA.sign(hash, priv, 'little').toString(); + jsrsaSig.init(key); + + jsrsaSig.updateHex(buf.toString('hex')); + + sig = new Buffer(jsrsaSig.sign(), 'hex'); + } else { + sig = ''; + } + + if (returnTrust) { + var cert = pki_data[pki_data.length - 1]; + var der = cert.toString('hex'); + var pem = KJUR.asn1.ASN1Util.getPEMStringFromHex(der, 'CERTIFICATE'); + var caName = RootCerts.getTrusted(pem); + var selfSigned = 0; + if (!caName) { + selfSigned = pki_data.length > 1 ? -1 : 1; + } + return { + selfSigned: selfSigned, + isChain: pki_data.length > 1, + signature: sig, + caTrusted: !!caName, + caName: caName || null + }; + } + + return sig; }; +PaymentProtocol.prototype.x509Verify = function(returnTrust) { + var sig = this.get('signature'); + var pki_type = this.get('pki_type'); + var pki_data = this.get('pki_data'); + pki_data = PaymentProtocol.X509Certificates.decode(pki_data); + pki_data = pki_data.certificate; + var buf = this.serializeForSig(); + var type = pki_type !== 'none' ? pki_type.split('+')[1].toUpperCase() : pki_type; -WalletUtils.verifyMessage = function(text, signature, pubKey) { - $.checkArgument(text); - $.checkArgument(pubKey); + var der; + var pem; + var verified; - if (!signature) - return false; + if (type !== 'none') { + var jsrsaSig = new KJUR.crypto.Signature({ + alg: type + 'withRSA', + prov: 'cryptojs/jsrsa' + }); + var signedCert = pki_data[0]; + der = signedCert.toString('hex'); + pem = KJUR.asn1.ASN1Util.getPEMStringFromHex(der, 'CERTIFICATE'); + jsrsaSig.initVerifyByCertificatePEM(pem); + jsrsaSig.updateHex(buf.toString('hex')); + verified = jsrsaSig.verify(sig.toString('hex')); + } else { + verified = true; + } - var pub = new PublicKey(pubKey); - var hash = WalletUtils.hashMessage(text); + var chain = pki_data; - try { - var sig = new crypto.Signature.fromString(signature); - return crypto.ECDSA.verify(hash, sig, pub, 'little'); - } catch (e) { - return false; + // Get the CA cert's name + + var issuer = chain[chain.length - 1]; + der = issuer.toString('hex'); + pem = KJUR.asn1.ASN1Util.getPEMStringFromHex(der, 'CERTIFICATE'); + var caName = RootCerts.getTrusted(pem); + + if (chain.length === 1 && !caName) { + if (returnTrust) { + return { + selfSigned: 1, // yes + isChain: false, + verified: verified, + caTrusted: false, + caName: null, + chainVerified: false + }; + } + return verified; } -}; -WalletUtils.deriveAddress = function(publicKeyRing, path, m, network) { - var publicKeys = _.map(publicKeyRing, function(item) { - var xpub = new Bitcore.HDPublicKey(item.xPubKey); - return xpub.derive(path).publicKey; - }); + // If there's no trusted root cert, don't + // bother validating the cert chain. + if (!caName) { + if (returnTrust) { + return { + selfSigned: -1, // unknown + isChain: chain.length > 1, + verified: verified, + caTrusted: false, + caName: null, + chainVerified: false + }; + } + return verified; + } - var bitcoreAddress = Address.createMultisig(publicKeys, m, network); + var chainVerified = PaymentProtocol.verifyCertChain(chain, type); - return { - address: bitcoreAddress.toString(), - path: path, - publicKeys: _.invoke(publicKeys, 'toString'), - }; -}; + if (returnTrust) { + return { + selfSigned: 0, // no + isChain: true, + verified: verified, + caTrusted: !!caName, + caName: caName || null, + chainVerified: chainVerified + }; + } -WalletUtils.getProposalHash = function(toAddress, amount, message) { - return [toAddress, amount, (message || '')].join('|'); + return verified && chainVerified; }; -WalletUtils.getCopayerHash = function(name, xPubKey, requestPubKey) { - return [name, xPubKey, requestPubKey].join('|'); -}; +PaymentProtocol.verifyCertChain = function(chain, sigHashAlg) { + if (sigHashAlg === 'none') { + return true; + } + return chain.every(function(cert, i) { + var der = cert.toString('hex'); + var pem = KJUR.asn1.ASN1Util.getPEMStringFromHex(der, 'CERTIFICATE'); + var name = RootCerts.getTrusted(pem); -WalletUtils.xPubToCopayerId = function(xpub) { - var hash = sjcl.hash.sha256.hash(xpub); - return sjcl.codec.hex.fromBits(hash); + var ncert = chain[i + 1]; + // The root cert, check if it's trusted: + if (!ncert || name) { + if (!name) { + return false; + } + chain.length = 0; + return true; + } + var nder = ncert.toString('hex'); + var npem = KJUR.asn1.ASN1Util.getPEMStringFromHex(nder, 'CERTIFICATE'); + + // Get Next Certificate: + var ndata = new Buffer(nder, 'hex'); + var nc = rfc3280.Certificate.decode(ndata, 'der'); + + var npubKey; + // Get Public Key from next certificate (via KJUR because it's a mess): + if (sigHashAlg !== 'none') { + var js = new KJUR.crypto.Signature({ + alg: sigHashAlg + 'withRSA', + prov: 'cryptojs/jsrsa' + }); + js.initVerifyByCertificatePEM(npem); + npubKey = js.pubKey; + } + + // Get Signature Value from current certificate: + var data = new Buffer(der, 'hex'); + var c = rfc3280.Certificate.decode(data, 'der'); + var sig = c.signature.data; + + // Check Validity of Certificates + var validityVerified = PaymentProtocol.validateCertTime(c, nc); + + // Check the Issuer matches the Subject of the next certificate: + var issuerVerified = PaymentProtocol.validateCertIssuer(c, nc); + + var sigVerified; + + // Verify current Certificate signature + if (sigHashAlg !== 'none') { + var jsrsaSig = new KJUR.crypto.Signature({ + alg: sigHashAlg + 'withRSA', + prov: 'cryptojs/jsrsa' + }); + jsrsaSig.initVerifyByPublicKey(npubKey); + + // Get the raw DER TBSCertificate + // from the DER Certificate: + var tbs = PaymentProtocol.getTBSCertificate(data); + + jsrsaSig.updateHex(tbs.toString('hex')); + + sigVerified = jsrsaSig.verify(sig.toString('hex')); + } else { + sigVerified = true; + } + + return validityVerified && issuerVerified && sigVerified; + }); }; -WalletUtils.toSecret = function(walletId, walletPrivKey, network) { - if (_.isString(walletPrivKey)) { - walletPrivKey = Bitcore.PrivateKey.fromString(walletPrivKey); +module.exports = PaymentProtocol; + +}).call(this,require("buffer").Buffer) +},{"./common":13,"./rootcerts":15,"asn1.js/rfc/3280":29,"buffer":209,"jsrsasign":103}],13:[function(require,module,exports){ +(function (Buffer){ +'use strict'; + +var bitcore = require('bitcore'); +var protobufjs = require('protobufjs/dist/ProtoBuf'); +var RootCerts = require('./rootcerts'); + +var PublicKey = bitcore.PublicKey; +var PrivateKey = bitcore.PrivateKey; +var Signature = bitcore.crypto.Signature; +var ECDSA = bitcore.crypto.ECDSA; +var sha256sha256 = bitcore.crypto.Hash.sha256sha256; +var varintBufNum = bitcore.encoding.BufferWriter.varintBufNum; + +// BIP 70 - payment protocol +function PaymentProtocol() { + this.messageType = null; + this.message = null; +} + +PaymentProtocol.PAYMENT_REQUEST_MAX_SIZE = 50000; +PaymentProtocol.PAYMENT_MAX_SIZE = 50000; +PaymentProtocol.PAYMENT_ACK_MAX_SIZE = 60000; +PaymentProtocol.PAYMENT_REQUEST_CONTENT_TYPE = 'application/bitcoin-paymentrequest'; +PaymentProtocol.PAYMENT_CONTENT_TYPE = 'application/bitcoin-payment'; +PaymentProtocol.PAYMENT_ACK_CONTENT_TYPE = 'application/bitcoin-paymentack'; + +// https://www.google.com/search?q=signatureAlgorithm+1.2.840.113549.1.1.1 +// http://msdn.microsoft.com/en-us/library/windows/desktop/aa379057(v=vs.85).aspx +PaymentProtocol.X509_ALGORITHM = { + '1.2.840.113549.1.1.1': 'RSA', + '1.2.840.113549.1.1.2': 'RSA_MD2', + '1.2.840.113549.1.1.4': 'RSA_MD5', + '1.2.840.113549.1.1.5': 'RSA_SHA1', + '1.2.840.113549.1.1.11': 'RSA_SHA256', + '1.2.840.113549.1.1.12': 'RSA_SHA384', + '1.2.840.113549.1.1.13': 'RSA_SHA512', + + '1.2.840.10045.4.3.2': 'ECDSA_SHA256', + '1.2.840.10045.4.3.3': 'ECDSA_SHA384', + '1.2.840.10045.4.3.4': 'ECDSA_SHA512' +}; + +PaymentProtocol.getAlgorithm = function(value, index) { + if (Array.isArray(value)) { + value = value.join('.'); } - var widHex = new Buffer(walletId.replace(/-/g, ''), 'hex'); - var widBase58 = new encoding.Base58(widHex).toString(); - return _.padRight(widBase58, 22, '0') + walletPrivKey.toWIF() + (network == 'testnet' ? 'T' : 'L'); + value = PaymentProtocol.X509_ALGORITHM[value]; + if (typeof(index) !== 'undefined') { + value = value.split('_'); + if (index === true) { + return { + cipher: value[0], + hash: value[1] + }; + } + return value[index]; + } + return value; }; -WalletUtils.fromSecret = function(secret) { - $.checkArgument(secret); +// Grab the raw DER To-Be-Signed Certificate +// from a DER Certificate to verify +PaymentProtocol.getTBSCertificate = function(data) { + // We start by slicing off the first SEQ of the + // Certificate (TBSCertificate is its own SEQ). - function split(str, indexes) { - var parts = []; - indexes.push(str.length); - var i = 0; - while (i < indexes.length) { - parts.push(str.substring(i == 0 ? 0 : indexes[i - 1], indexes[i])); - i++; - }; - return parts; - }; + // The first 10 bytes usually look like: + // [ 48, 130, 5, 32, 48, 130, 4, 8, 160, 3 ] + var start = 0; + var starts = 0; + for (start = 0; start < data.length; start++) { + if (starts === 1 && data[start] === 48) { + break; + } + if (starts < 1 && data[start] === 48) { + starts++; + } + } - try { - var secretSplit = split(secret, [22, 74]); - var widBase58 = secretSplit[0].replace(/0/g, ''); - var widHex = encoding.Base58.decode(widBase58).toString('hex'); - var walletId = split(widHex, [8, 12, 16, 20]).join('-'); + // The bytes *after* the TBS (including the last TBS byte) will look like + // (note the 48 - the start of the sig, and the 122 - the end of the TBS): + // [ 122, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 11, 5, 0, 3, ... ] - var walletPrivKey = Bitcore.PrivateKey.fromString(secretSplit[1]); - var networkChar = secretSplit[2]; + // The certificate in these examples has a `start` of 4, and an `end` of + // 1040. The 4 bytes is the DER SEQ of the Certificate, right before the + // SEQ of the TBSCertificate. + var end = 0; + var ends = 0; + for (end = data.length - 1; end > 0; end--) { + if (ends === 2 && data[end] === 48) { + break; + } + if (ends < 2 && data[end] === 0) { + ends++; + } + } - return { - walletId: walletId, - walletPrivKey: walletPrivKey, - network: networkChar == 'T' ? 'testnet' : 'livenet', - }; - } catch (ex) { - throw new Error('Invalid secret'); + // Return our raw DER TBSCertificate: + return data.slice(start, end); +}; + +// Check Validity of Certificates +PaymentProtocol.validateCertTime = function(c, nc) { + var validityVerified = true; + var now = Date.now(); + var cBefore = c.tbsCertificate.validity.notBefore.value; + var cAfter = c.tbsCertificate.validity.notAfter.value; + var nBefore = nc.tbsCertificate.validity.notBefore.value; + var nAfter = nc.tbsCertificate.validity.notAfter.value; + if (cBefore > now || cAfter < now || nBefore > now || nAfter < now) { + validityVerified = false; } + return validityVerified; }; +// Check the Issuer matches the Subject of the next certificate: +PaymentProtocol.validateCertIssuer = function(c, nc) { + var issuer = c.tbsCertificate.issuer; + var subject = nc.tbsCertificate.subject; + var issuerVerified = issuer.type === subject.type && issuer.value.every(function(issuerArray, i) { + var subjectArray = subject.value[i]; + return issuerArray.every(function(issuerObject, i) { + var subjectObject = subjectArray[i]; -WalletUtils.encryptMessage = function(message, encryptingKey) { - var key = sjcl.codec.base64.toBits(encryptingKey); - return sjcl.encrypt(key, message, { - ks: 128, - iter: 1 + var issuerObjectType = issuerObject.type.join('.'); + var subjectObjectType = subjectObject.type.join('.'); + + var issuerObjectValue = issuerObject.value.toString('hex'); + var subjectObjectValue = subjectObject.value.toString('hex'); + + return issuerObjectType === subjectObjectType && issuerObjectValue === subjectObjectValue; + }); }); + return issuerVerified; +}; + +PaymentProtocol.RootCerts = RootCerts; + +PaymentProtocol.proto = {}; + +PaymentProtocol.proto.Output = 'message Output {\ + optional uint64 amount = 1 [default = 0];\ + optional bytes script = 2;\ +}\n'; + +PaymentProtocol.proto.PaymentDetails = 'message PaymentDetails {\ + optional string network = 1 [default = \"main\"];\ + repeated Output outputs = 2;\ + required uint64 time = 3;\ + optional uint64 expires = 4;\ + optional string memo = 5;\ + optional string payment_url = 6;\ + optional bytes merchant_data = 7;\ +}\n'; + +PaymentProtocol.proto.PaymentRequest = 'message PaymentRequest {\ + optional uint32 payment_details_version = 1 [default = 1];\ + optional string pki_type = 2 [default = \"none\"];\ + optional bytes pki_data = 3;\ + required bytes serialized_payment_details = 4;\ + optional bytes signature = 5;\ +}\n'; + +PaymentProtocol.proto.Payment = 'message Payment {\ + optional bytes merchant_data = 1;\ + repeated bytes transactions = 2;\ + repeated Output refund_to = 3;\ + optional string memo = 4;\ +}\n'; + +PaymentProtocol.proto.PaymentACK = 'message PaymentACK {\ + required Payment payment = 1;\ + optional string memo = 2;\ +}\n'; + +PaymentProtocol.proto.X509Certificates = 'message X509Certificates {\ + repeated bytes certificate = 1;\ +}\n'; + +PaymentProtocol.proto.all = ''; +PaymentProtocol.proto.all = PaymentProtocol.proto.all + PaymentProtocol.proto.Output; +PaymentProtocol.proto.all = PaymentProtocol.proto.all + PaymentProtocol.proto.PaymentDetails; +PaymentProtocol.proto.all = PaymentProtocol.proto.all + PaymentProtocol.proto.PaymentRequest; +PaymentProtocol.proto.all = PaymentProtocol.proto.all + PaymentProtocol.proto.Payment; +PaymentProtocol.proto.all = PaymentProtocol.proto.all + PaymentProtocol.proto.PaymentACK; +PaymentProtocol.proto.all = PaymentProtocol.proto.all + PaymentProtocol.proto.X509Certificates; + +PaymentProtocol.builder = protobufjs.loadProto(PaymentProtocol.proto.all); + +PaymentProtocol.Output = PaymentProtocol.builder.build('Output'); +PaymentProtocol.PaymentDetails = PaymentProtocol.builder.build('PaymentDetails'); +PaymentProtocol.PaymentRequest = PaymentProtocol.builder.build('PaymentRequest'); +PaymentProtocol.Payment = PaymentProtocol.builder.build('Payment'); +PaymentProtocol.PaymentACK = PaymentProtocol.builder.build('PaymentACK'); +PaymentProtocol.X509Certificates = PaymentProtocol.builder.build('X509Certificates'); + +PaymentProtocol.prototype.makeOutput = function(obj) { + this.messageType = 'Output'; + this.message = new PaymentProtocol.Output(); + this.setObj(obj); + return this; }; -WalletUtils.decryptMessage = function(cyphertextJson, encryptingKey) { - var key = sjcl.codec.base64.toBits(encryptingKey); - return sjcl.decrypt(key, cyphertextJson); +PaymentProtocol.prototype.makePaymentDetails = function(obj) { + this.messageType = 'PaymentDetails'; + this.message = new PaymentProtocol.PaymentDetails(); + this.setObj(obj); + return this; }; -WalletUtils.privateKeyToAESKey = function(privKey) { - var pk = Bitcore.PrivateKey.fromString(privKey); - return Bitcore.crypto.Hash.sha256(pk.toBuffer()).slice(0, 16).toString('base64'); +PaymentProtocol.prototype.makePaymentRequest = function(obj) { + this.messageType = 'PaymentRequest'; + this.message = new PaymentProtocol.PaymentRequest(); + this.setObj(obj); + return this; }; -WalletUtils.buildTx = function(txp) { - var t = new Bitcore.Transaction(); +PaymentProtocol.prototype.makePayment = function(obj) { + this.messageType = 'Payment'; + this.message = new PaymentProtocol.Payment(); + this.setObj(obj); + return this; +}; - _.each(txp.inputs, function(i) { - t.from(i, i.publicKeys, txp.requiredSignatures); - }); +PaymentProtocol.prototype.makePaymentACK = function(obj) { + this.messageType = 'PaymentACK'; + this.message = new PaymentProtocol.PaymentACK(); + this.setObj(obj); + return this; +}; - t.to(txp.toAddress, txp.amount) - .change(txp.changeAddress.address); +PaymentProtocol.prototype.makeX509Certificates = function(obj) { + this.messageType = 'X509Certificates'; + this.message = new PaymentProtocol.X509Certificates(); + this.setObj(obj); + return this; +}; - // Shuffle outputs for improved privacy - t.sortOutputs(function(outputs) { - return _.map(txp.outputOrder, function(i) { - return outputs[i]; - }); - }); +PaymentProtocol.prototype.isValidSize = function() { + var s = this.serialize(); + if (this.messageType === 'PaymentRequest') { + return s.length < PaymentProtocol.PAYMENT_REQUEST_MAX_SIZE; + } + if (this.messageType === 'Payment') { + return s.length < PaymentProtocol.PAYMENT_MAX_SIZE; + } + if (this.messageType === 'PaymentACK') { + return s.length < PaymentProtocol.PAYMENT_ACK_MAX_SIZE; + } + return true; +}; - return t; +PaymentProtocol.prototype.getContentType = function() { + if (this.messageType === 'PaymentRequest') { + return PaymentProtocol.PAYMENT_REQUEST_CONTENT_TYPE; + } + + if (this.messageType === 'Payment') { + return PaymentProtocol.PAYMENT_CONTENT_TYPE; + } + + if (this.messageType === 'PaymentACK') { + return PaymentProtocol.PAYMENT_ACK_CONTENT_TYPE; + } + + throw new Error('No known content type for this message type'); }; -WalletUtils.signTxp = function(txp, xPrivKey) { - var self = this; +PaymentProtocol.prototype.set = function(key, val) { + this.message.set(key, val); + return this; +}; - //Derive proper key to sign, for each input - var privs = [], - derived = {}; +PaymentProtocol.prototype.get = function(key) { + var v = this.message.get(key); - var network = new Bitcore.Address(txp.toAddress).network.name; - var xpriv = new Bitcore.HDPrivateKey(xPrivKey, network).derive(WalletUtils.PATHS.BASE_ADDRESS_DERIVATION); + if (v === null) { + return v; + } - _.each(txp.inputs, function(i) { - if (!derived[i.path]) { - derived[i.path] = xpriv.derive(i.path).privateKey; - privs.push(derived[i.path]); - } - }); + //protobuf supports longs, javascript naturally does not + //convert longs (see long.js, e.g. require('long')) to Numbers + if (typeof v.low !== 'undefined' && typeof v.high !== 'undefined') { + return v.toInt(); + } - var t = WalletUtils.buildTx(txp); + if (typeof v.toBuffer !== 'undefined') { + var maybebuf = v.toBuffer(); + return Buffer.isBuffer(maybebuf) ? maybebuf : new Buffer(new Uint8Array(maybebuf)); + } - var signatures = _.map(privs, function(priv, i) { - return t.getSignatures(priv); - }); + return v; +}; - signatures = _.map(_.sortBy(_.flatten(signatures), 'inputIndex'), function(s) { - return s.signature.toDER().toString('hex'); - }); +PaymentProtocol.prototype.setObj = function(obj) { + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + var val = obj[key]; + this.message.set(key, val); + } + } + return this; +}; - return signatures; +PaymentProtocol.prototype.serializeForSig = function() { + if (this.messageType !== 'PaymentRequest') { + throw new Error('serializeForSig is only for PaymentRequest'); + } + + var save = this.message.get('signature'); + this.message.set('signature', new Buffer([])); + var buf = this.serialize(); + this.message.set('signature', save); + return buf; }; -WalletUtils.getNetworkFromXPubKey = function(xPubKey) { - return xPubKey.substr(0, 4) == 'tpub' ? 'testnet' : 'livenet'; +PaymentProtocol.prototype.serialize = function() { + //protobufjs returns either a Buffer or an ArrayBuffer + //but we always want a Buffer (which browserify understands, browser or no) + var maybebuf = this.message.toBuffer(); + var buf = (Buffer.isBuffer(maybebuf)) ? maybebuf : new Buffer(new Uint8Array(maybebuf)); + return buf; }; -module.exports = WalletUtils; +PaymentProtocol.prototype.deserialize = function(buf, messageType) { + this.messageType = messageType || this.messageType; + if (!this.messageType) { + throw new Error('Must specify messageType'); + } + this.message = PaymentProtocol[this.messageType].decode(buf); + return this; +}; -}).call(this,require("buffer").Buffer) -},{"bitcore":12,"buffer":104,"lodash":275,"preconditions":276,"sjcl":338}],12:[function(require,module,exports){ -(function (Buffer){ -var bitcore = module.exports; +PaymentProtocol.prototype.sign = function(key, returnTrust) { + if (this.messageType !== 'PaymentRequest') { + throw new Error('Signing can only be performed on a PaymentRequest'); + } + var pki_type = this.get('pki_type'); -// crypto -bitcore.crypto = {}; -bitcore.crypto.BN = require('./lib/crypto/bn'); -bitcore.crypto.ECDSA = require('./lib/crypto/ecdsa'); -bitcore.crypto.Hash = require('./lib/crypto/hash'); -bitcore.crypto.Random = require('./lib/crypto/random'); -bitcore.crypto.Point = require('./lib/crypto/point'); -bitcore.crypto.Signature = require('./lib/crypto/signature'); + var sig; + if (pki_type === 'SIN') { + sig = this.sinSign(key); + } else if (pki_type === 'x509+sha1' || pki_type === 'x509+sha256') { + sig = this.x509Sign(key, returnTrust); + } else if (pki_type === 'none') { + return this; + } else { + throw new Error('Unsupported pki_type'); + } -// encoding -bitcore.encoding = {}; -bitcore.encoding.Base58 = require('./lib/encoding/base58'); -bitcore.encoding.Base58Check = require('./lib/encoding/base58check'); -bitcore.encoding.BufferReader = require('./lib/encoding/bufferreader'); -bitcore.encoding.BufferWriter = require('./lib/encoding/bufferwriter'); -bitcore.encoding.Varint = require('./lib/encoding/varint'); + this.set('signature', sig); -// utilities -bitcore.util = {}; -bitcore.util.buffer = require('./lib/util/buffer'); -bitcore.util.js = require('./lib/util/js'); -bitcore.util.preconditions = require('./lib/util/preconditions'); + return this; +}; -// errors thrown by the library -bitcore.errors = require('./lib/errors'); +PaymentProtocol.prototype.verify = function(returnTrust) { + if (this.messageType !== 'PaymentRequest') { + throw new Error('Verifying can only be performed on a PaymentRequest'); + } -// main bitcoin library -bitcore.Address = require('./lib/address'); -bitcore.Block = require('./lib/block'); -bitcore.MerkleBlock = require('./lib/block/merkleblock'); -bitcore.BlockHeader = require('./lib/block/blockheader'); -bitcore.HDPrivateKey = require('./lib/hdprivatekey.js'); -bitcore.HDPublicKey = require('./lib/hdpublickey.js'); -bitcore.Networks = require('./lib/networks'); -bitcore.Opcode = require('./lib/opcode'); -bitcore.PrivateKey = require('./lib/privatekey'); -bitcore.PublicKey = require('./lib/publickey'); -bitcore.Script = require('./lib/script'); -bitcore.Transaction = require('./lib/transaction'); -bitcore.URI = require('./lib/uri'); -bitcore.Unit = require('./lib/unit'); + var pki_type = this.get('pki_type'); -// dependencies, subject to change -bitcore.deps = {}; -bitcore.deps.bnjs = require('bn.js'); -bitcore.deps.bs58 = require('bs58'); -bitcore.deps.Buffer = Buffer; -bitcore.deps.elliptic = require('elliptic'); -bitcore.deps._ = require('lodash'); + if (pki_type === 'SIN') { + return this.sinVerify(); + } else if (pki_type === 'x509+sha1' || pki_type === 'x509+sha256') { + return this.x509Verify(returnTrust); + } else if (pki_type === 'none') { + return true; + } -// Internal usage, exposed for testing/advanced tweaking -bitcore._HDKeyCache = require('./lib/hdkeycache'); -bitcore.Transaction.sighash = require('./lib/transaction/sighash'); + throw new Error('Unsupported pki_type'); +}; -// module information -bitcore.version = 'v'+require('./package.json').version; +function magicHash(str) { + var magicBytes = new Buffer('Bitcoin Signed Message:\n'); + var prefix1 = varintBufNum(magicBytes.length); + var message = new Buffer(str); + var prefix2 = varintBufNum(message.length); + var buf = Buffer.concat([prefix1, magicBytes, prefix2, message]); + var hash = sha256sha256(buf); + return hash; +} + +//default signing function for prototype.sign +PaymentProtocol.prototype.sinSign = function(privateKey) { + if ( !(privateKey instanceof PrivateKey) ) { + throw new TypeError('Expects an instance of PrivateKey'); + } + var pubkey = privateKey.toPublicKey().toBuffer(); + this.set('pki_data', pubkey); + var buf = this.serializeForSig(); + var hash = magicHash(buf); + var signature = ECDSA.sign(hash, privateKey); + return signature.toDER(); +}; + +//default verify function +PaymentProtocol.prototype.sinVerify = function() { + var sig = this.get('signature'); + var pubkey = this.get('pki_data'); + var buf = this.serializeForSig(); + var hash = magicHash(buf); + var publicKey = PublicKey.fromBuffer(pubkey); + var signature = new Signature.fromString(sig); + var verified = ECDSA.verify(hash, signature, publicKey); + return verified; +}; + +// Helpers +PaymentProtocol.PEMtoDER = +PaymentProtocol.prototype._PEMtoDER = function(pem) { + return this._PEMtoDERParam(pem); +}; + +PaymentProtocol.PEMtoDERParam = +PaymentProtocol.prototype._PEMtoDERParam = function(pem, param) { + if (Buffer.isBuffer(pem)) { + pem = pem.toString(); + } + var start = new RegExp('(?=-----BEGIN ' + (param || '[^-]+') + '-----)', 'i'); + var end = new RegExp('^-----END ' + (param || '[^-]+') + '-----$', 'gmi'); + pem = pem.replace(end, ''); + var parts = pem.split(start); + return parts.map(function(part) { + var type = /-----BEGIN ([^-]+)-----/.exec(part)[1]; + part = part.replace(/-----BEGIN ([^-]+)-----/g, ''); + part = part.replace(/\s+/g, ''); + if (!param || type !== param) { + return; + } + return new Buffer(part, 'base64'); + }).filter(Boolean); +}; + +PaymentProtocol.DERtoPEM = +PaymentProtocol.prototype._DERtoPEM = function(der, type) { + if (typeof der === 'string') { + der = new Buffer(der, 'hex'); + } + type = type || 'PRIVACY-ENHANCED MESSAGE'; + der = der.toString('base64'); + der = der.replace(/(.{64})/g, '$1\r\n'); + der = der.replace(/\r\n$/, ''); + return '' + + '-----BEGIN ' + type + '-----\r\n' + + der + + '\r\n-----END ' + type + '-----\r\n'; +}; + +// Expose RootCerts +PaymentProtocol.getTrusted = RootCerts.getTrusted; +PaymentProtocol.getCert = RootCerts.getCert; +PaymentProtocol.parsePEM = RootCerts.parsePEM; +PaymentProtocol.certs = RootCerts.certs; +PaymentProtocol.trusted = RootCerts.trusted; + +module.exports = PaymentProtocol; }).call(this,require("buffer").Buffer) -},{"./lib/address":13,"./lib/block":16,"./lib/block/blockheader":15,"./lib/block/merkleblock":17,"./lib/crypto/bn":18,"./lib/crypto/ecdsa":19,"./lib/crypto/hash":20,"./lib/crypto/point":21,"./lib/crypto/random":22,"./lib/crypto/signature":23,"./lib/encoding/base58":24,"./lib/encoding/base58check":25,"./lib/encoding/bufferreader":26,"./lib/encoding/bufferwriter":27,"./lib/encoding/varint":28,"./lib/errors":29,"./lib/hdkeycache":31,"./lib/hdprivatekey.js":32,"./lib/hdpublickey.js":33,"./lib/networks":34,"./lib/opcode":35,"./lib/privatekey":36,"./lib/publickey":37,"./lib/script":38,"./lib/transaction":41,"./lib/transaction/sighash":47,"./lib/unit":51,"./lib/uri":52,"./lib/util/buffer":53,"./lib/util/js":54,"./lib/util/preconditions":55,"./package.json":86,"bn.js":56,"bs58":57,"buffer":104,"elliptic":58,"lodash":79}],13:[function(require,module,exports){ +},{"./rootcerts":15,"bitcore":30,"buffer":209,"protobufjs/dist/ProtoBuf":104}],14:[function(require,module,exports){ +module.exports={ + "GTE CyberTrust Global Root": "-----BEGIN CERTIFICATE-----\nMIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9H\nVEUgQ29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNvbHV0aW9ucywgSW5j\nLjEjMCEGA1UEAxMaR1RFIEN5YmVyVHJ1c3QgR2xvYmFsIFJvb3QwHhcNOTgwODEzMDAyOTAw\nWhcNMTgwODEzMjM1OTAwWjB1MQswCQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0\naW9uMScwJQYDVQQLEx5HVEUgQ3liZXJUcnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMT\nGkdURSBDeWJlclRydXN0IEdsb2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB\ngQCVD6C28FCc6HrHiM3dFw4usJTQGz0O9pTAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwef\nU/ltWJTSr41tiGeA5u2ylc9yMcqlHHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X4\n04Wqk2kmhXBIgD8SFcd5tB8FLztimQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAG3rGwnpXtlR\n22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMWM4ETCJ57NE7fQMh017l93PR2VX2bY1QY6fDq\n81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OFNMQkpw0PlZPvy5TYnh+dXIVtx6quTx8i\ntc2VrbqnzPmrC3p/\n-----END CERTIFICATE-----\n", + "Thawte Server CA": "-----BEGIN CERTIFICATE-----\nMIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkExFTATBgNV\nBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUg\nQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lv\nbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNl\ncnRzQHRoYXd0ZS5jb20wHhcNOTYwODAxMDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkG\nA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0w\nGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT\nZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3\nDQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJ\nAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl/Kj0R1HahbUgdJSGHg91yekIYfUGbTBuFRkC\n6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg71CcEJRCXL+eQbcAoQpnXTEPew/UhbVSf\nXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJ\nKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG7oWDTSEwjsrZqG9JGubaUeNgcGyEYRGhGshIPllD\nfU+VPaGLtwtimHp1it2ITk6eQNuozDJ0uW8NxuOzRAvZim+aKZuZGCg70eNAKJpaPNW15yAb\ni8qkq43pUdniTCxZqdq5snUb9kLy78fyGPmJvKP/iiMucEc=\n-----END CERTIFICATE-----\n", + "Thawte Premium Server CA": "-----BEGIN CERTIFICATE-----\nMIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkExFTATBgNV\nBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUg\nQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lv\nbjEhMB8GA1UEAxMYVGhhd3RlIFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlw\ncmVtaXVtLXNlcnZlckB0aGF3dGUuY29tMB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1\nOVowgc4xCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNh\ncGUgVG93bjEdMBsGA1UEChMUVGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRp\nZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNl\ncnZlciBDQTEoMCYGCSqGSIb3DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNvbTCBnzAN\nBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkEVdbQ7xwblRZH7xhI\nNTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQug2SBhRz1JPLlyoAnFxODLz6\nFVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMRuHM/qgeN9EJN50CdHDcCAwEAAaMTMBEw\nDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJ\neGBeXm43YyJ3Nn6yF8Q0ufUIhfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu\n1bdRiBHjpIUZa4JMpAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcU\nQg==\n-----END CERTIFICATE-----\n", + "Equifax Secure CA": "-----BEGIN CERTIFICATE-----\nMIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJVUzEQMA4G\nA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0\naG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1MVowTjELMAkGA1UEBhMCVVMx\nEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVxdWlmYXggU2VjdXJlIENlcnRpZmljYXRl\nIEF1dGhvcml0eTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2R\nFGiYCh7+2gRvE4RiIcPRfM6fBeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP\n/PvwDN1Dulsr4R+AcJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/\nFP3gx7kCAwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ\nMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUg\nQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgwODIyMTY0MTUxWjAL\nBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gjIBBPM5iQn9QwHQYDVR0OBBYE\nFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQFMAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsF\nVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaS\nbn+2kmOeUJXRmm/kEd5jhW6Y7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA\n2zsmWLIodz2uFHdh1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4\n-----END CERTIFICATE-----\n", + "Digital Signature Trust Co. Global CA 1": "-----BEGIN CERTIFICATE-----\nMIIDKTCCApKgAwIBAgIENnAVljANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJVUzEkMCIG\nA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQLEwhEU1RDQSBFMTAe\nFw05ODEyMTAxODEwMjNaFw0xODEyMTAxODQwMjNaMEYxCzAJBgNVBAYTAlVTMSQwIgYDVQQK\nExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xETAPBgNVBAsTCERTVENBIEUxMIGdMA0G\nCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCgbIGpzzQeJN3+hijM3oMv+V7UQtLodGBmE5gGHKlR\nEmlvMVW5SXIACH7TpWJENySZj9mDSI+ZbZUTu0M7LklOiDfBu1h//uG9+LthzfNHwJmm8fOR\n6Hh8AMthyUQncWlVSn5JTe2io74CTADKAqjuAQIxZA9SLRN0dja1erQtcQIBA6OCASQwggEg\nMBEGCWCGSAGG+EIBAQQEAwIABzBoBgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMx\nJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0Eg\nRTExDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMTAxODEwMjNagQ8yMDE4MTIx\nMDE4MTAyM1owCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFGp5fpFpRhgTCgJ3pVlbYJglDqL4\nMB0GA1UdDgQWBBRqeX6RaUYYEwoCd6VZW2CYJQ6i+DAMBgNVHRMEBTADAQH/MBkGCSqGSIb2\nfQdBAAQMMAobBFY0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4GBACIS2Hod3IEGtgllsofIH160\nL+nEHvI8wbsEkBFKg05+k7lNQseSJqBcNJo4cvj9axY+IO6CizEqkzaFI4iKPANo08kJD038\nbKTaKHKTDomAsH3+gG9lbRgzl4vCa4nuYD3Im+9/KzJic5PLPON74nZ4RbyhkwS7hp86W0N6\nw4pl\n-----END CERTIFICATE-----\n", + "Digital Signature Trust Co. Global CA 3": "-----BEGIN CERTIFICATE-----\nMIIDKTCCApKgAwIBAgIENm7TzjANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJVUzEkMCIG\nA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQLEwhEU1RDQSBFMjAe\nFw05ODEyMDkxOTE3MjZaFw0xODEyMDkxOTQ3MjZaMEYxCzAJBgNVBAYTAlVTMSQwIgYDVQQK\nExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xETAPBgNVBAsTCERTVENBIEUyMIGdMA0G\nCSqGSIb3DQEBAQUAA4GLADCBhwKBgQC/k48Xku8zExjrEH9OFr//Bo8qhbxe+SSmJIi2A7fB\nw18DW9Fvrn5C6mYjuGODVvsoLeE4i7TuqAHhzhy2iCoiRoX7n6dwqUcUP87eZfCocfdPJmyM\nvMa1795JJ/9IKn3oTQPMx7JSxhcxEzu1TdvIxPbDDyQq2gyd55FbgM2UnQIBA6OCASQwggEg\nMBEGCWCGSAGG+EIBAQQEAwIABzBoBgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMx\nJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0Eg\nRTIxDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMDkxOTE3MjZagQ8yMDE4MTIw\nOTE5MTcyNlowCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFB6CTShlgDzJQW6sNS5ay97u+Dlb\nMB0GA1UdDgQWBBQegk0oZYA8yUFurDUuWsve7vg5WzAMBgNVHRMEBTADAQH/MBkGCSqGSIb2\nfQdBAAQMMAobBFY0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4GBAEeNg61i8tuwnkUiBbmi1gMO\nOHLnnvx75pO2mqWilMg0HZHRxdf0CiUPPXiBng+xZ8SQTGPdXqfiup/1902lMXucKS1M/mQ+\n7LZT/uqb7YLbdHVLB3luHtgZg3Pe9T7Qtd7nS2h9Qy4qIOF+oHhEngj1mPnHfxsb1gYgAlih\nw6ID\n-----END CERTIFICATE-----\n", + "Verisign Class 3 Public Primary Certification Authority": "-----BEGIN CERTIFICATE-----\nMIICPDCCAaUCEDyRMcsf9tAbDpq40ES/Er4wDQYJKoZIhvcNAQEFBQAwXzELMAkGA1UEBhMC\nVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQ\ncmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgw\nMjIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYD\nVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGf\nMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ\n2RHP7gJYHyX3KqhEBarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaO\nIG+YD/isI19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G\nCSqGSIb3DQEBBQUAA4GBABByUqkFFBkyCEHwxWsKzH4PIRnN5GfcX6kb5sroc50i2JhucwNh\nkcV8sEVAbkSdjbCxlnRhLQ2pRdKkkirWmnWXbj9T/UWZYB2oK0z5XqcJ2HUw19JlYD1n1khV\ndWk/kfVIC0dpImmClr7JyDiGSnoscxlIaU5rfGW/D/xwzoiQ\n-----END CERTIFICATE-----\n", + "Verisign Class 3 Public Primary Certification Authority - G2": "-----BEGIN CERTIFICATE-----\nMIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJBgNVBAYT\nAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMg\nUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5\nOCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZW\nZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVow\ngcExCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh\nc3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYD\nVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5\nMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GN\nADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4pO0M8RcPO/mn+SXX\nwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg013gfqLptQ5GVj0VXXn7F+8qk\nBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFFN\nzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSkU01UbSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzo\nKQm5EWR0zLVznxxIqbxhAe7iF6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcm\neQD2+A2iMzAo1KpYoJ2daZH9\n-----END CERTIFICATE-----\n", + "GlobalSign Root CA": "-----BEGIN CERTIFICATE-----\nMIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMC\nQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNV\nBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBa\nMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdS\nb290IENBMRswGQYDVQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUA\nA4IBDwAwggEKAoIBAQDaDuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtI\nK+6NiY6arymAZavpxy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCO\nXkNz8kHp1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG\nsnUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3\ndLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DP\nAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRg\ne2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUFAAOCAQEA1nPnfE920I2/7LqivjTF\nKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY7\n76BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9\nLhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr\n+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME\nHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==\n-----END CERTIFICATE-----\n", + "GlobalSign Root CA - R2": "-----BEGIN CERTIFICATE-----\nMIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4GA1UECxMX\nR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMT\nCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1MDgwMDAwWjBMMSAwHgYDVQQL\nExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UE\nAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8o\nmUVCxKs+IVSbC9N/hHD6ErPLv4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7\nSqbKSaZeqKeMWhG8eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQ\nBoZfXklqtTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd\nC9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pazq+r1feq\nCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCBmTAOBgNVHQ8BAf8E\nBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IHV2ccHsBqBt5ZtJot39wZhi4w\nNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9iYWxzaWduLm5ldC9yb290LXIyLmNy\nbDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEA\nmYFThxxol4aR7OBKuEQLq4GsJ0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkI\nk7mpM0sYmsL4h4hO291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRD\nLenVOavSot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd\nAfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7TBj0/VLZ\njmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==\n-----END CERTIFICATE-----\n", + "ValiCert Class 1 VA": "-----BEGIN CERTIFICATE-----\nMIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlk\nYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlD\nZXJ0IENsYXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw\nOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29t\nMB4XDTk5MDYyNTIyMjM0OFoXDTE5MDYyNTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0\nIFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsT\nLFZhbGlDZXJ0IENsYXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQD\nExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl\ncnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9YLqdUHAZu\n9OqNSLwxlBfw8068srg1knaw0KWlAdcAAxIiGQj4/xEjm84H9b9pGib+TunRf50sQB1ZaG6m\n+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCmDuJWBQ8YTfwggtFzVXSNdnKgHZ0dwN0/\ncQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0LBwGlN+VYH+Wexf+T3GtZMjdd9LvWVXo\nP+iOBSoh8gfStadS/pyxtuJbdxdA6nLWI8sogTLDAHkY7FkXicnGah5xyf23dKUlRWnFSKsZ\n4UWKJWsZ7uW7EvV/96aNUcPwnXS3qT6gpf+2SQMT2iLM7XGCK5nPOrf1LXLI\n-----END CERTIFICATE-----\n", + "ValiCert Class 2 VA": "-----BEGIN CERTIFICATE-----\nMIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlk\nYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlD\nZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw\nOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29t\nMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYyNjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0\nIFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsT\nLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQD\nExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl\ncnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vYdA757tn2\nVUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9WlmpZdRJEy0kTRxQ\nb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QSv4dk+NoS/zcnwbNDu+97bi5p\n9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9vUJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6\nEILLGACOTb2oWH+heQC1u+mNr0HZDzTuIYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2az\nSiGM5bUMMj4QssxsodyamEwCW/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd\n-----END CERTIFICATE-----\n", + "RSA Root Certificate 1": "-----BEGIN CERTIFICATE-----\nMIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlk\nYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlD\nZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw\nOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29t\nMB4XDTk5MDYyNjAwMjIzM1oXDTE5MDYyNjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0\nIFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsT\nLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQD\nExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl\ncnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDjmFGWHOjVsQaBalfDcnWTq8+e\npvzzFlLWLU2fNUSoLgRNB0mKOCn1dzfnt6td3zZxFJmP3MKS8edgkpfs2Ejcv8ECIMYkpChM\nMFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89HBFx1cQqYJJgpp0lZpd34t0NiYfPT4tBV\nPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliEZwgs3x/be0kz9dNnnfS0ChCzycUs4pJq\ncXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJn0WuPIqpsHEzXcjFV9+vqDWzf4mH6eglkrh/hXqu\n1rweN1gqZ8mRzyqBPu3GOd/APhmcGcwTTYJBtYze4D1gCCAPRX5ron+jjBXu\n-----END CERTIFICATE-----\n", + "Verisign Class 3 Public Primary Certification Authority - G3": "-----BEGIN CERTIFICATE-----\nMIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQG\nEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0\nIE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv\ncml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1h\ncnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3\nMTYyMzU5NTlaMIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAd\nBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlT\naWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu\nIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCC\nASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8bN3O9+MlrlBIwT/A2\nR/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2tKmFZpGcmTNDovFJbcCAEWNF6\nyaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGukxUccLwgTS8Y3pKI6GyFVxEa6X7jJhFU\nokWWVYPKMIno3Nij7SqAP395ZVc+FSBmCC+Vk7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyo\nw0xZVYnm6FNcHOqd8GIWC6fJXwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBte\nHRJTW8cs54NJOxWuimi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my\n/uRan2Te2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5fj267Cz3qWhMe\nDGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC/Y4wjylG\nsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565pF4ErWjfJXir0xuKh\nXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGtTxzhT5yvDwyd93gN2PQ1VoDa\nt20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ==\n-----END CERTIFICATE-----\n", + "Verisign Class 4 Public Primary Certification Authority - G3": "-----BEGIN CERTIFICATE-----\nMIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQG\nEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0\nIE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv\ncml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1h\ncnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3\nMTYyMzU5NTlaMIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAd\nBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlT\naWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu\nIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCC\nASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK3LpRFpxlmr8Y+1GQ9Wzsy1HyDkniYl\nS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaStBO3IFsJ+mGuqPKljYXCKtbeZjbSmwL0\nqJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0GbdU6LM8BDcVHOLBKFGMzNcF0C5nk3T875V\ng+ixiY5afJqWIpA7iCXy0lOIAgwLePLmNxdLMEYH5IBtptiWLugs+BGzOA1mppvqySNb247i\n8xOOGlktqgLw7KSHZtzBP/XYufTsgsbSPZUd5cBPhMnZo0QoBmrXRazwa2rvTl/4EYIeOGM0\nZlDUPpNz+jDDZq3/ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAj/ola09b5KROJ1Wr\nIhVZPMq1CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXttmhwwjIDLk5Mq\ng6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKmfjaF3H48\nZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c2NU8Qh0XwRJdRTjD\nOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/bLvSHgCwIe34QWKCudiyxLtG\nUPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg==\n-----END CERTIFICATE-----\n", + "Entrust.net Secure Server CA": "-----BEGIN CERTIFICATE-----\nMIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMCVVMxFDAS\nBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5uZXQvQ1BTIGluY29y\ncC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5u\nZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVzdC5uZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZp\nY2F0aW9uIEF1dGhvcml0eTAeFw05OTA1MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQsw\nCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0\nLm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykg\nMTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUg\nU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCB\nhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQaO2f55M28Qpku0f1BBc/I0dNxScZgSYMVHIN\niC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5gXpa0zf3wkrYKZImZNHkmGw6AIr1NJtl\n+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OCAdcwggHTMBEGCWCGSAGG+EIBAQQEAwIA\nBzCCARkGA1UdHwSCARAwggEMMIHeoIHboIHYpIHVMIHSMQswCQYDVQQGEwJVUzEUMBIGA1UE\nChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBi\neSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBM\naW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp\nb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVudHJ1c3Qu\nbmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0MFqBDzIwMTkwNTI1\nMTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8BdiE1U9s/8KAGv7UISX8+1i0Bow\nHQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAaMAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9\nB0EABAwwChsEVjQuMAMCBJAwDQYJKoZIhvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7\nRw7/JXyNEwr75Ji174z4xRAN95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7\nqIcyunL2POI9n9cd2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G\n+bI=\n-----END CERTIFICATE-----\n", + "Entrust.net Premium 2048 Secure Server CA": "-----BEGIN CERTIFICATE-----\nMIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVz\ndC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJl\nZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0\nZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4\nKTAeFw05OTEyMjQxNzUwNTFaFw0xOTEyMjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0\nLm5ldDFAMD4GA1UECxQ3d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVm\nLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRl\nZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtK\nTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/EC\nDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ\n/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzWnLLPKQP5L6RQstRIzgUyVYr9smRM\nDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVC\nwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo3QwcjARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0j\nBBgwFoAUVeSB0RGAvtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdERgL7YibkIozH5oSQJ\nFrlwMB0GCSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEA\nWUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFhfGPjK50xA3B20qMooPS7mmNz\n7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVUKcgF7bISKo30Axv/55IQh7A6tcOdBTcSo8f0\nFbnVpDkWm1M6I5HxqIKiaohowXkCIryqptau37AUX7iH0N18f3v/rxzP5tsHrV7bhZ3QKw0z\n2wTR5klAEyt2+z7pnIkPFc4YsIV4IU9rTw76NmfNB/L/CNDi3tm/Kq+4h4YhPATKt5Rof888\n6ZjXOP/swNlQ8C5LWK5Gb9Auw2DaclVyvUxFnmG6v4SBkgPR0ml8xQ==\n-----END CERTIFICATE-----\n", + "Baltimore CyberTrust Root": "-----BEGIN CERTIFICATE-----\nMIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJRTESMBAG\nA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYDVQQDExlCYWx0aW1v\ncmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjEL\nMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEi\nMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQAD\nggEPADCCAQoCggEBAKMEuyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2ygu\nzmKiYv60iNoS6zjrIZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo\n6vWrJYeKmpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu\nXmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3z\nyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkC\nAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1BE3wMBIGA1UdEwEB/wQIMAYB\nAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27\nTyclhAO992T9Ldcw46QQF+vaKSm2eT929hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukM\nJY2GQE/szKN+OMY3EU/t3WgxjkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhS\nNzkE1akxehi/oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67\nG7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS\nR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp\n-----END CERTIFICATE-----\n", + "Equifax Secure Global eBusiness CA": "-----BEGIN CERTIFICATE-----\nMIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEcMBoGA1UE\nChMTRXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBTZWN1cmUgR2xvYmFs\nIGVCdXNpbmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIwMDYyMTA0MDAwMFowWjELMAkG\nA1UEBhMCVVMxHDAaBgNVBAoTE0VxdWlmYXggU2VjdXJlIEluYy4xLTArBgNVBAMTJEVxdWlm\nYXggU2VjdXJlIEdsb2JhbCBlQnVzaW5lc3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw\ngYkCgYEAuucXkAJlsTRVPEnCUdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/Ka\nelpzmKNc6fuKcxtc58O/gGzNqfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuo\nWcDNM50/o5brhTMhHD4ePmBudpxnhcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAH\nMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUvqigdHJQa0S3ySPY+6j/s1draGwwHQYD\nVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hsMA0GCSqGSIb3DQEBBAUAA4GBADDiAVGqx+pf\n2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okENI7SS+RkAZ70Br83gcfxaz2TE4JaY0KNA\n4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv8qIYNMR1pHMc8Y3c7635s3a0kr/clRAe\nvsvIO1qEYBlWlKlV\n-----END CERTIFICATE-----\n", + "Equifax Secure eBusiness CA 1": "-----BEGIN CERTIFICATE-----\nMIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEcMBoGA1UE\nChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2lu\nZXNzIENBLTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQwMDAwWjBTMQswCQYDVQQGEwJV\nUzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1\ncmUgZUJ1c2luZXNzIENBLTEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fe\nk6lfWg0XTzQaDJj0ItlZ1MRoRvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2D\nKocKIdMSODRsjQBuWqDZQu4aIZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6r\nXyo4YgKwEnv+j6YDAgMBAAGjZjBkMBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTAD\nAQH/MB8GA1UdIwQYMBaAFEp4MlIR21kWNl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRKeDJSEdtZ\nFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQFAAOBgQB1W6ibAxHm6VZMzfmpTMANmvPMZWnm\nJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5lSE/9dR+WB5Hh1Q+WKG1tfgq73HnvMP2\nsUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN/Bf+KpYrtWKmpj29f5JZzVoqgrI3eQ==\n-----END CERTIFICATE-----\n", + "Equifax Secure eBusiness CA 2": "-----BEGIN CERTIFICATE-----\nMIIDIDCCAomgAwIBAgIEN3DPtTANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJVUzEXMBUG\nA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2VjdXJlIGVCdXNpbmVz\ncyBDQS0yMB4XDTk5MDYyMzEyMTQ0NVoXDTE5MDYyMzEyMTQ0NVowTjELMAkGA1UEBhMCVVMx\nFzAVBgNVBAoTDkVxdWlmYXggU2VjdXJlMSYwJAYDVQQLEx1FcXVpZmF4IFNlY3VyZSBlQnVz\naW5lc3MgQ0EtMjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA5Dk5kx5SBhsoNviyoynF\n7Y6yEb3+6+e0dMKP/wXn2Z0GvxLIPw7y1tEkshHe0XMJitSxLJgJDR5QRrKDpkWNYmi7hRsg\ncDKqQM2mll/EcTc/BPO3QSQ5BxoeLmFYoBIL5aXfxavqN3HMHMg3OrmXUqesxWoklE6ce8/A\natbfIb0CAwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEX\nMBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2VjdXJlIGVCdXNp\nbmVzcyBDQS0yMQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTkwNjIzMTIxNDQ1WjAL\nBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUUJ4L6q9euSBIplBqy/3YIHqngnYwHQYDVR0OBBYE\nFFCeC+qvXrkgSKZQasv92CB6p4J2MAwGA1UdEwQFMAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsF\nVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GBAAyGgq3oThr1jokn4jVYPSm0B482UJW/bsGe\n68SQsoWou7dC4A8HOd/7npCy0cE+U58DRLB+S/Rv5Hwf5+Kx5Lia78O9zt4LMjTZ3ijtM2vE\n1Nc9ElirfQkty3D1E4qUoSek1nDFbZS1yX2doNLGCEnZZpum0/QL3MUmV+GRMOrN\n-----END CERTIFICATE-----\n", + "AddTrust Low-Value Services Root": "-----BEGIN CERTIFICATE-----\nMIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEUMBIGA1UE\nChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQD\nExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMwMTAzODMxWhcNMjAwNTMwMTAz\nODMxWjBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFk\nZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3Qw\nggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH\n+9ZOEQpnXvUGW2ulCDtbKRY654eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7\nBo8wBN6ntGO0/7Gcrjyvd7ZWxbWroulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyl\ndI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1Zmne3yzxbrww2ywkEtvrNTVokMsAsJchPXQhI2U0\nK7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJuiGMx1I4S+6+JNM3GOGvDC+Mcdoq0Dlyz4zyXG\n9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8wHQYDVR0OBBYEFJWxtPCUtr3H2tERCSG+\nwa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MIGPBgNVHSMEgYcwgYSAFJWx\ntPCUtr3H2tERCSG+wa9J/RB7oWmkZzBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1\nc3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVz\ndCBDbGFzcyAxIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxtZBsfzQ3duQH6lmM0\nMkhHma6X7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0PhiVYrqW9yTkkz\n43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MYeDdXL+gz\nB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJlpz/+0WatC7xrmYbv\nP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOAWiFeIc9TVPC6b4nbqKqVz4vj\nccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk=\n-----END CERTIFICATE-----\n", + "AddTrust External Root": "-----BEGIN CERTIFICATE-----\nMIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEUMBIGA1UE\nChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3Jr\nMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoX\nDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMSYw\nJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5hbCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1\nc3QgRXh0ZXJuYWwgQ0EgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3\nGjPm8gAELTngTlvtH7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCw\nSXrbLpX9uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX\nmk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LXa0Tkx63u\nbUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzNE0S3ySvdQwAl+mG5\naWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0WicCAwEAAaOB3DCB2TAdBgNV\nHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYDVR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMB\nAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYT\nAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwg\nVFRQIE5ldHdvcmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJ\nKoZIhvcNAQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH\nYINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw56wwCURQt\njr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvCNr4TDea9Y355e6cJ\nDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEXc4g/VhsxOBi0cQ+azcgOno4u\nG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5amnkPIAou1Z5jJh5VkpTYghdae9C8x49O\nhgQ=\n-----END CERTIFICATE-----\n", + "AddTrust Public Services Root": "-----BEGIN CERTIFICATE-----\nMIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEUMBIGA1UE\nChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSAwHgYDVQQD\nExdBZGRUcnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAxMDQxNTBaFw0yMDA1MzAxMDQx\nNTBaMGQxCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRk\nVHJ1c3QgVFRQIE5ldHdvcmsxIDAeBgNVBAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIB\nIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4\njsIMEZBRpS9mVEBV6tsfSlbunyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrH\nAZcHF/nXGCwwfQ56HmIexkvA/X1id9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnP\ndzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSGAa2Il+tmzV7R/9x98oTaunet3IAIx6eH1lWfl2ro\nyBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAwHM+A+WD+eeSI8t0A65RF62WUaUC6wNW0uLp9\nBBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0GA1UdDgQWBBSBPjfYkrAfd59ctKtzquf2\nNGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zCBjgYDVR0jBIGGMIGDgBSBPjfY\nkrAfd59ctKtzquf2NGAv+qFopGYwZDELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0\nIEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29yazEgMB4GA1UEAxMXQWRkVHJ1c3Qg\nUHVibGljIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4JNojVhaTdt02KLmu\nG7jD8WS6IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL+YPoRNWyQSW/\niHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/AoGEjwxrzQ\nvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh4SINhwBk/ox9Yjll\npu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQmXiLsks3/QppEIW1cxeMiHV9H\nEufOX1362KqxMy3ZdvJOOjMMK7MtkAY=\n-----END CERTIFICATE-----\n", + "AddTrust Qualified Certificates Root": "-----BEGIN CERTIFICATE-----\nMIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEUMBIGA1UE\nChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSMwIQYDVQQD\nExpBZGRUcnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1MzAxMDQ0NTBaFw0yMDA1MzAx\nMDQ0NTBaMGcxCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMU\nQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIzAhBgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBS\nb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTb\nYjx5eLfpMLXsDBwqxBb/4Oxx64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqz\nZwFZ8V1G87B4pfYOQnrjfxvM0PC3KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i\n2O+tCBGaKZnhqkRFmhJePp1tUvznoD1oL/BLcHwTOK28FSXx1s6rosAx1i+f4P8UWfyEk9mH\nfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GRwVY18BTcZTYJbqukB8c10cIDMzZbdSZtQvES\na0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HUMIHRMB0GA1UdDgQWBBQ5lYtii1zJ1IC6\nWA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zCBkQYDVR0jBIGJMIGG\ngBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6FrpGkwZzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0Fk\nZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29yazEjMCEGA1UEAxMaQWRk\nVHJ1c3QgUXVhbGlmaWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBABmrder4i2Vh\nlRO6aQTvhsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxGGuoYQ992zPlm\nhpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6XdgWTP5XH\nAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3P6CxB9bpT9zeRXEw\nMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9YiQBCYz95OdBEsIJuQRno3eDB\niFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5noxqE=\n-----END CERTIFICATE-----\n", + "Entrust Root Certification Authority": "-----BEGIN CERTIFICATE-----\nMIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMCVVMxFjAU\nBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0Lm5ldC9DUFMgaXMg\naW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMWKGMpIDIwMDYgRW50cnVzdCwg\nSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4X\nDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIwNTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQK\nEw1FbnRydXN0LCBJbmMuMTkwNwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29y\ncG9yYXRlZCBieSByZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4x\nLTArBgNVBAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ\nKoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFoNu3s/poB\nj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf44LlAcTfFy0cOlypo\nwCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9KlmaI5UXLEWeH25DeW0MXJj+\nSKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGIrb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rV\nvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2\nHNjnogQi+dPa2MsCAwEAAaOBsDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB\n/zArBgNVHRAEJDAigA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSME\nGDAWgBRokORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE\nvW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4IBAQCT\n1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9tO1KzKtvn1ISMY/YP\nyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6ZuaAGAT/3B+XxFNSRuzFVJ7yVTa\nv52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE\n2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPc\nj2A781q0tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8\n-----END CERTIFICATE-----\n", + "RSA Security 2048 v3": "-----BEGIN CERTIFICATE-----\nMIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUFADA6MRkwFwYD\nVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0EgU2VjdXJpdHkgMjA0OCBWMzAe\nFw0wMTAyMjIyMDM5MjNaFw0yNjAyMjIyMDM5MjNaMDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0\neSBJbmMxHTAbBgNVBAsTFFJTQSBTZWN1cml0eSAyMDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEF\nAAOCAQ8AMIIBCgKCAQEAt49VcdKA3XtpeafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37\nRqtBaB4Y6lXIL5F4iSj7Jylg/9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E0S1PRsNO3Ng3\nOTsor8udGuorryGlwSMiuLgbWhOHV4PR8CDn6E8jQrAApX2J6elhc5SYcSa8LWrg903w8bYq\nODGBDSnhAMFRD0xS+ARaqn1y07iHKrtjEAMqs6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2\nPcYJk5qjEoAAVZkZR73QpXzDuvsf9/UP+Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpuAWgXIszA\nCwIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAW\ngBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4EFgQUB8NRMKSq6UWuNST6/yQsM9CxnYww\nDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYcHnmYv/3VEhF5Ug7uMYm83X/50cYVIeiK\nAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/Zb5gEydxiKRz44Rj0aRV4VCT5hsOedBnvEbIvz8X\nDZXmxpBp3ue0L96VfdASPz0+f00/FGj1EVDVwfSQpQgdMWD/YIwjVAqv/qFuxdF6Kmh4zx6C\nCiC0H63lhbJqaHVOrSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395nzIlQnQFgCi/vcEk\nllgVsRch6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kApKnXwiJPZ9d3\n7CAFYd4=\n-----END CERTIFICATE-----\n", + "GeoTrust Global CA": "-----BEGIN CERTIFICATE-----\nMIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVTMRYwFAYD\nVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9iYWwgQ0EwHhcNMDIw\nNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2Vv\nVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0B\nAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEH\nCIjaWC9mOSm9BXiLnTjoBbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIu\nT8rxh0PBFpVXLVDviS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386D\nGXHKTubU1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+\nbw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoWMPRfwCvo\ncWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTAephojYn7qwVkDBF9\nqn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1luMrMTjANBgkqhkiG9w0BAQUF\nAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKInZ57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VS\nsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfStQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfO\nEVEiIuCl6rYVSAlk6l5PdPcFPseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQd\ntqvmlKXBx4Ot2/Unhw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeX\nxx12E6nV5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==\n-----END CERTIFICATE-----\n", + "GeoTrust Global CA 2": "-----BEGIN CERTIFICATE-----\nMIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEWMBQGA1UE\nChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwHhcNMDQw\nMzA0MDUwMDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2Vv\nVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwggEiMA0GCSqGSIb3\nDQEBAQUAA4IBDwAwggEKAoIBAQDvPE1APRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6Csgncbz\nYEbYwbLVjDHZ3CB5JIG/NTL8Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5S\nJBri1WeR0IIQ13hLTytCOb1kLUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHq\nZ38MN5aL5mkWRxHCJ1kDs6ZgwiFAVvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7\nS4wMcoKK+xfNAGw6EzywhIdLFnopsk/bHdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe2HSPqht/\nXvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFHE4NvICMVNHK266\nZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNHK266ZUapEBVYIAUJMA4GA1UdDwEB/wQE\nAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6tdEPx7srJerJsOflN4WT5CBP51o62sgU7X\nAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv/NgdRN3ggX+d6YvhZJFiCzkIjKx0nVnZellSlxG5\nFntvRdOW2TF9AjYPnDtuzywNA0ZF66D0f0hExghAzN4bcLUprbqLOzRldRtxIR0sFAqwlpW4\n1uryZfspuk/qkZN0abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkCx1YAzUm5s2x7UwQa\n4qjJqhIFI8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqFH4z1Ir+rzoPz\n4iIprn2DQKi6bA==\n-----END CERTIFICATE-----\n", + "GeoTrust Universal CA": "-----BEGIN CERTIFICATE-----\nMIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEWMBQGA1UE\nChMNR2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVyc2FsIENBMB4XDTA0\nMDMwNDA1MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdl\nb1RydXN0IEluYy4xHjAcBgNVBAMTFUdlb1RydXN0IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZI\nhvcNAQEBBQADggIPADCCAgoCggIBAKYVVaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckU\nHUWCq8YdgNY96xCcOq9tJPi8cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDg\nFgDgEB8rMQ7XlFTTQjOgNB0eRXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEY\nfyh3peFhF7em6fgemdtzbvQKoiFs7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2v\nc7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d8Lsrlh/eezJS/R27tQahsiFepdaVaH/wmZ7cRQg+\n59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7VqnJNk22CDtucvc+081xdVHppCZbW2xHBjXWo\ntM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3CgaRr0BHdCXteGYO8A3ZNY9lO4L4fUorgtW\nv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZf9hBZ3KiKN9gg6meyHv8U3NyWfWTehd2\nDs735VzZC1U0oqpbtWpU5xPKV+yXbfReBi9Fi1jUIxaS5BZuKGNZMN9QAZxjiRqf2xeUgnA3\nwySemkfWWspOqGmJch+RbNt+nhutxx9z3SxPGWX9f5NAEC7S8O08ni4oPmkmM8V7AgMBAAGj\nYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0XG0D08DYj3rWMB8G\nA1UdIwQYMBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG\n9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRcaanQmjg8\n+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fXIwjhmF7DWgh2qaav\ndy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzynANXH/KttgCJwpQzgXQQpAvvL\noJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0zuzYYm4UPFd3uLax2k7nZAY1IEKj79TiG\n8dsKxr2EoyNB3tZ3b4XUhRxQ4K5RirqNPnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzn\ns0ccjkxFKyDuSN/n3QmOGKjaQI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3k\nt0tm7wNFYGm2DFKWkoRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkD\nMBmhLMi9ER/frslKxfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQt\nDF4JbAiXfKM9fJP/P6EUp8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/SfuvmbJxPgWp6\nZKy7PtXny3YuxadIwVyQD8vIP/rmMuGNG2+k5o7Y+SlIis5z/iw=\n-----END CERTIFICATE-----\n", + "GeoTrust Universal CA 2": "-----BEGIN CERTIFICATE-----\nMIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEWMBQGA1UE\nChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwHhcN\nMDQwMzA0MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN\nR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwggIiMA0G\nCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6Gq\ndHtXr0om/Nj1XqduGdt0DE81WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSC\negx2oG9NzkEtoBUGFF+3Qs17j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O\n64ceJHdqXbboW0W63MOhBW9Wjo8QJqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxL\nse4YuU6W3Nx2/zu+z18DwPw76L5GG//aQMJS9/7jOvdqdzXQ2o3rXhhqMcceujwbKNZrVMaq\nW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2WP0+GfPtDCapkzj4T8FdIgbQl+rhrcZV4IEr\nKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP20gaXT73y/Zl92zxlfgCOzJWgjl6W70v\niRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRthAAnZqzwcEAJQpKtT5MNYQlRJNiS1QuU\nYbKHsu3/mjX/hVTK7URDrBs8FmtISgocQIgfksILAAX/8sgCSqSqqcyZlpwvWOB94b67B9xf\nBHJcMTTD7F8t4D1kkCLm0ey4Lt1ZrtmhN79UNdxzMk+MBB4zsslG8dhcyFVQyWi9qLo2CQID\nAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2+/CfXGJx7Tz0RzgQ\nKzAfBgNVHSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8EBAMCAYYwDQYJ\nKoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+zdXkzoS9t\ncBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQL1EuxBRa3ugZ4T7G\nzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgrFg5fNuH8KrUwJM/gYwx7WBr+\nmbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSoag/HtPQTxORb7QrSpJdMKu0vbBKJPfEn\ncKpqA1Ihn0CoZ1Dy81of398j9tx4TuaYT1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8p\nRPPphXpgY+RdM4kX2TGq2tbzGDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp\n8RW04eWe3fiPpm8m1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Bas\nx7InQJJVOCiNUW7dFGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH\n6aLcr34YEoP9VhdBLtUpgn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwXQMAJKOSL\nakhT2+zNVVXxxvjpoixMptEmX36vWkzaH6byHCx+rgIW0lbQL1dTR+iS\n-----END CERTIFICATE-----\n", + "America Online Root Certification Authority 1": "-----BEGIN CERTIFICATE-----\nMIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEcMBoGA1UE\nChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBPbmxpbmUgUm9vdCBD\nZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyODA2MDAwMFoXDTM3MTExOTIwNDMw\nMFowYzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNV\nBAMTLUFtZXJpY2EgT25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIw\nDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCaxlCyfqXfaE0b\nfA+2l2h9LaaLl+lkhsmj76CGv2BlnEtUiMJIxUo5vxTjWVXlGbR0yLQFOVwWpeKVBeASrlmL\nojNoWBym1BW32J/X3HGrfpq/m44zDyL9Hy7nBzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsW\nOqMFf6Dch9Wc/HKpoH145LcxVR5lu9RhsCFg7RAycsWSJR74kEoYeEfffjA3PlAb2xzTa5qG\nUwew76wGePiEmf4hjUyAtgyC9mZweRrTT6PP8c9GsEsPPt2IYriMqQkoO3rHl+Ee5fSfwMCu\nJKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUAK3Z\no/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAUAK3Zo/Z59m50qX8zPYEX10zPM94wDgYD\nVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBBQUAA4IBAQB8itEfGDeC4Liwo+1WlchiYZwFos3C\nYiZhzRAW18y0ZTTQEYqtqKkFZu90821fnZmv9ov761KyBZiibyrFVL0lvV+uyIbqRizBs73B\n6UlwGBaXCBOMIOAbLjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft3OJvx8Fi8eNy1gTI\ndGcL+oiroQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43gKd8hdIaC2y+C\nMMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j8uB9Gr784N/Xx6dssPmuujz9\ndLQR6FgNgLzTqIA6me11zEZ7\n-----END CERTIFICATE-----\n", + "America Online Root Certification Authority 2": "-----BEGIN CERTIFICATE-----\nMIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEcMBoGA1UE\nChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBPbmxpbmUgUm9vdCBD\nZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyODA2MDAwMFoXDTM3MDkyOTE0MDgw\nMFowYzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNV\nBAMTLUFtZXJpY2EgT25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIw\nDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssNt79Hc9PwVU3d\nxgz6sWYFas14tNwC206B89enfHG8dWOgXeMHDEjsJcQDIPT/DjsS/5uN4cbVG7RtIuOx238h\nZK+GvFciKtZHgVdEglZTvYYUAQv8f3SkWq7xuhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2\nJxhP7JsowtS013wMPgwr38oE18aO6lhOqKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9BoInLRBY\nBbV4Bbkv2wxrkJB+FFk4u5QkE+XRnRTf04JNRvCAOVIyD+OEsnpD8l7eXz8d3eOyG6ChKiMD\nbi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0gBe4lL8BPeraunzgWGcXuVjgiIZGZ2yd\nEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67Xnfn6KVuY8INXWHQjNJsWiEOyiijzirp\nlcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEqZ8A9W6Wa6897GqidFEXlD6CaZd4vKL3Ob5Rmg0gp\n2OpljK+T2WSfVVcmv2/LNzGZo2C7HK2JNDJiuEMhBnIMoVxtRsX6Kc8w3onccVvdtjc+31D1\nuAclJuW8tf48ArO3+L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnjB453cMor9H124Hhn\nAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3OpaaEg5+31IqEj\nFNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNeeMA4GA1UdDwEB/wQEAwIBhjAN\nBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypLM7PmG2tZTiLMubekJcmnxPBUlgtk87FYT15R\n/LKXeydlwuXK5w0MJXti4/qftIe3RUavg6WXSIylvfEWK5t2LHo1YGwRgJfMqZJS5ivmae2p\n+DYtLHe/YUjRYwu5W1LtGLBDQiKmsXeu3mnFzcccobGlHBD7GL4acN3Bkku+KVqdPzW+5X1R\n+FXgJXUjhx5c3LqdsKyzadsXg8n33gy8CNyRnqjQ1xU3c6U1uPx+xURABsPr+CKAXEfOAuMR\nn0T//ZoyzH1kUQ7rVyZ2OuMeIjzCpjbdGe+n/BLzJsBZMYVMnNjP36TMzCmT/5RtdlwTCJfy\n7aULTd3oyWgOZtMADjMSW7yV5TKQqLPGbIOtd+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7\nlyoKZy2FAjgQ5ANh1NolNscIWC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUX\nOm/9riW99XJZZLF0KjhfGEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPbAZO1XB4Y\n3WRayhgoPmMEEf0cjQAPuDffZ4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQlZvqz2cK6Kb6aSDiC\nmfS/O0oxGfm/jiEzFMpPVF/7zvuPcX/9XhmgD0uRuMRUvAawRY8mkaKO/qk=\n-----END CERTIFICATE-----\n", + "Visa eCommerce Root": "-----BEGIN CERTIFICATE-----\nMIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBrMQswCQYD\nVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNl\ncnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1lcmNlIFJvb3QwHhcNMDIw\nNjI2MDIxODM2WhcNMjIwNjI0MDAxNjEyWjBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklT\nQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAa\nBgNVBAMTE1Zpc2EgZUNvbW1lcmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK\nAoIBAQCvV95WHm6h2mCxlCfLF9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVI\nsZHBAk4ElpF7sDPwsRROEW+1QK8bRaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdV\nZqW1LS7YgFmypw23RuwhY/81q6UCzyr0TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq299yOIzz\nlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI/k4+oKsGGelT84ATB+0tvz8KPFUgOSwsAGl0\nlUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzsGHxBvfaLdXe6YJ2E5/4tAgMBAAGjQjBA\nMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBQVOIMPPyw/cDMe\nzUb+B4wg4NfDtzANBgkqhkiG9w0BAQUFAAOCAQEAX/FBfXxcCLkr4NWSR/pnXKUTwwMhmytM\niUbPWU3J/qVAtmPN3XEolWcRzCSs00Rsca4BIGsDoo8Ytyk6feUWYFN4PMCvFYP3j1IzJL1k\nk5fui/fbGKhtcbP3LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pzzkWKsKZJ/0x9nXGI\nxHYdkFsd7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBuYQa7FkKMcPcw\n++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt398znM/j\nra6O1I7mT1GvFpLgXPYHDw==\n-----END CERTIFICATE-----\n", + "Certum Root CA": "-----BEGIN CERTIFICATE-----\nMIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBMMRswGQYD\nVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBDQTAeFw0wMjA2MTEx\nMDQ2MzlaFw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQKExJVbml6ZXRv\nIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP\nADCCAQoCggEBAM6xwS7TT3zNJc4YPk/EjG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYV\nM42sLQnFdvkrOYCJ5JdLkKWoePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82Kxu\njZlakE403Daaj4GIULdtlkIJ89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2\nbu4lXapuOb7kky/ZR6By6/qmW6/KUz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUg\nAKpoC6EahQGcxEZjgoi2IrHu/qpGWX7PNSzVttpd90gzFFS269lvzs2I1qsb2pY7HVkCAwEA\nAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAuI3O7+cUus/usESS\nbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+GXYkHAQaTOs9qmdvLdTN/mUxcMUbpgIK\numB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTgxSvgGrZgFCdsMneMvLJymM/NzD+5yCRC\nFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1qCjqTE5s7FCMTY5w/0YcneeVMUeMBrYVdGjux1XMQ\npNPyvG5k9VpWkKjHDkx0Dy5xO/fIR/RpbxXyEV6DHpx8Uq79AtoSqFlnGNu8cN2bsWntgM6J\nQEhqDjXKKWYVIZQs6GAqm4VKQPNriiTsBhYscw==\n-----END CERTIFICATE-----\n", + "Comodo AAA Services root": "-----BEGIN CERTIFICATE-----\nMIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEbMBkGA1UE\nCAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21v\nZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0\nMDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdy\nZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENB\nIExpbWl0ZWQxITAfBgNVBAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZI\nhvcNAQEBBQADggEPADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686td\nUIoWMQuaBtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe\n3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4YgNW8Ioa\nE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZRrOme9Hg6jc8P2ULi\nmAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cmez6KJcfA3Z3mNWgQIJ2P2N7S\nw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQUoBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYD\nVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDov\nL2NybC5jb21vZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0\ndHA6Ly9jcmwuY29tb2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG\n9w0BAQUFAAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q\nGE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLzRt0vxuBq\nw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2G9w84FoVxp7Z8VlI\nMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsil2D4kF501KKaU73yqWjgom7C\n12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==\n-----END CERTIFICATE-----\n", + "Comodo Secure Services root": "-----BEGIN CERTIFICATE-----\nMIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEbMBkGA1UE\nCAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21v\nZG8gQ0EgTGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRpZmljYXRlIFNlcnZpY2VzMB4X\nDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowfjELMAkGA1UEBhMCR0IxGzAZBgNVBAgM\nEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2Rv\nIENBIExpbWl0ZWQxJDAiBgNVBAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIw\nDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6\nEfQlhfPMcm3ye5drswfxdySRXyWP9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3S\nHpR7LZQdqnXXs5jLrLxkU0C8j6ysNstcrbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996CF23uPJA\nGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rCoznl2yY4rYsK7hljxxwk3wN42ubqwUcaCwtG\nCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3Vp6ea5EQz6YiO/O1R65NxTq0B50SOqy3L\nqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNVHQ4EFgQUPNiTiMLAggnMAZkGkyDpnnAJ\nY08wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgYEGA1UdHwR6MHgwO6A5oDeG\nNWh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL1NlY3VyZUNlcnRpZmljYXRlU2VydmljZXMuY3Js\nMDmgN6A1hjNodHRwOi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlmaWNhdGVTZXJ2aWNl\ncy5jcmwwDQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm4J4oqF7Tt/Q0\n5qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmjZ55B+glS\nzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtIgKvcnDe4IRRLDXE9\n7IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJaD61JlfutuC23bkpgHl9j6Pw\npCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDlizeauan5Hb/qmZJhlv8BzaFfDbxxvA6s\nCx1HRR3B7Hzs/Sk=\n-----END CERTIFICATE-----\n", + "Comodo Trusted Services root": "-----BEGIN CERTIFICATE-----\nMIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEbMBkGA1UE\nCAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21v\nZG8gQ0EgTGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAe\nFw0wNDAxMDEwMDAwMDBaFw0yODEyMzEyMzU5NTlaMH8xCzAJBgNVBAYTAkdCMRswGQYDVQQI\nDBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9k\nbyBDQSBMaW1pdGVkMSUwIwYDVQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIB\nIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWa\nHiWsnOWWfnJSoBVC21ndZHoa0Lh73TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMt\nTGo87IvDktJTdyR0nAducPy9C1t2ul/y/9c3S0pgePfw+spwtOpZqqPOSC+pw7ILfhdyFgym\nBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6juljatEPmsbS9Is6FARW1O24zG71++IsWL1/\nT2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsSivnkBbA7kUlcsutT6vifR4buv5XAwAaf\n0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0GA1UdDgQWBBTFe1i97doladL3WRaoszLA\neydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zCBgwYDVR0fBHwwejA8oDqg\nOIY2aHR0cDovL2NybC5jb21vZG9jYS5jb20vVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMu\nY3JsMDqgOKA2hjRodHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENlcnRpZmljYXRlU2Vy\ndmljZXMuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8NtwuleGFTQQuS9/\nHrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32pSxBvzwG\na+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxISjBc/lDb+XbDABHcT\nuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+xqFx7D+gIIxmOom0jtTYsU0l\nR+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/AtyjcndBInTMu2l+nZrghtWjlA3QVHdWpaIbOj\nGM9O9y5Xt5hwXsjEeLBi\n-----END CERTIFICATE-----\n", + "QuoVadis Root CA": "-----BEGIN CERTIFICATE-----\nMIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJCTTEZMBcG\nA1UEChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0aWZpY2F0aW9uIEF1\ndGhvcml0eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0\neTAeFw0wMTAzMTkxODMzMzNaFw0yMTAzMTcxODMzMzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYD\nVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0\naG9yaXR5MS4wLAYDVQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTR\nvM16z/Ypli4kVEAkOPcahdxYTMukJ0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2D\nrOpm2RgbaIr1VxqYuvXtdj182d6UajtLF8HVj71lODqV0D1VNk7feVcxKh7YWWVJWCCYfqtf\nfp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeLYzcS19Dsw3sgQUSj7cugF+FxZc4dZjH3dgEZ\nyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWenAScOospUxbF6lR1xHkopigPcakXBpBle\nbzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCCAk4wPQYIKwYBBQUHAQEEMTAvMC0GCCsG\nAQUFBzABhiFodHRwczovL29jc3AucXVvdmFkaXNvZmZzaG9yZS5jb20wDwYDVR0TAQH/BAUw\nAwEB/zCCARoGA1UdIASCAREwggENMIIBCQYJKwYBBAG+WAABMIH7MIHUBggrBgEFBQcCAjCB\nxxqBxFJlbGlhbmNlIG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmljYXRlIGJ5IGFueSBw\nYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFy\nZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJhY3RpY2Vz\nLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYIKwYBBQUHAgEWFmh0\ndHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3TKbkGGew5Oanwl4Rqy+/fMIGu\nBgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rqy+/foYGEpIGBMH8xCzAJBgNVBAYTAkJN\nMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRp\nb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0\naG9yaXR5ggQ6tlCLMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70\nmpKnGdSkfnIYj9lofFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf8\n7C9TqnN7Az10buYWnuulLsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1RcHhXHTMe\n/QKZnAzNCgVPx7uOpHX6Sm2xgI4JVrmcGmD+XcHXetwReNDWXcG31a0ymQM6isxUJTkxgXsT\nIlG6Rmyhu576BGxJJnSP0nPrzDCi5upZIof4l/UO/erMkqQWxFIY6iHOsfHmhIHluqmGKPJD\nWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi5nrQNiOKSnQ2+Q==\n-----END CERTIFICATE-----\n", + "QuoVadis Root CA 2": "-----BEGIN CERTIFICATE-----\nMIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNV\nBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMjAeFw0w\nNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBR\ndW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDIwggIiMA0GCSqG\nSIb3DQEBAQUAA4ICDwAwggIKAoICAQCaGMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4Gt\nMh6QRr+jhiYaHv5+HBg6XJxgFyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp\n3MJGF/hd/aTa/55JWpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsR\nE8Scd3bBrrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp\n+ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1ksOR1YqI\n0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/iUcw6UwxI5g69ybR2\nBlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIizPtGo/KPaHbDRsSNU30R2be1B\n2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og/zOhD7osFRXql7PSorW+8oyWHhqPHWyk\nYTe5hnMz15eWniN9gqRMgeKh0bpnX5UHoycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyP\nZFwDwzqLID9ujWc9Otb+fVuIyV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQAB\no4GwMIGtMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwz\nJQTU7tD2A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTEL\nMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1Zh\nZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2fBluornFdLwUvZ+YT\nRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzng/iN/Ae42l9NLmeyhP3ZRPx3\nUIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2BlfF/nJrP3MpCYUNQ3cVX2kiF495V5+vgt\nJodmVjB3pjd4M1IQWK4/YY7yarHvGH5KWWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q8\n0m/DShcK+JDSV6IZUaUtl0HaB0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W\n6ZM/57Es3zrWIozchLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQj\nrLhVoQPRTUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWD\nmbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0ZohEUGW6y\nhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y4aOTHcyKJloJONDO\n1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza8eOx79+Rj1QqCyXBJhnEUhAF\nZdWCEOrCMc0u\n-----END CERTIFICATE-----\n", + "QuoVadis Root CA 3": "-----BEGIN CERTIFICATE-----\nMIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNV\nBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMzAeFw0w\nNjExMjQxOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBR\ndW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDMwggIiMA0GCSqG\nSIb3DQEBAQUAA4ICDwAwggIKAoICAQDMV0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTP\nkrgEQK0CSzGrvI2RaNggDhoB4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZ\nz3HmDyl2/7FWeUUrH556VOijKTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2Objyj\nPtr7guXd8lyyBTNvijbO0BNO/79KDDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9Cabwv\nvWhDFlaJKjdhkf2mrk7AyxRllDdLkgbvBNDInIjbC3uBr7E9KsRlOni27tyAsdLTmZw67mta\na7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwpp5ijJUMv7/FfJuGITfhebtfZFG4ZM2mnO4SJ\nk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8nT8KKdjcT5EOE7zelaTfi5m+rJsziO+1\nga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDtWAEXMJPpGovgc2PZapKUSU60rUqFxKMi\nMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZc6tsgLjoC2SToJyMGf+z0gzskSaHirOi4XCPLArl\nzW1oUevaPwV/izLmE1xr/l9A4iLItLRkT9a6fUg+qGkM17uGcclzuD87nSVL2v9A6wIDAQAB\no4IBlTCCAZEwDwYDVR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHTBgkrBgEEAb5YAAMw\ngcUwgZMGCCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0\naXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0aWZpY2F0\nZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudC4wLQYIKwYBBQUH\nAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2NwczALBgNVHQ8EBAMCAQYwHQYD\nVR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4GA1UdIwRnMGWAFPLAE+CCQz777i9nMpY1\nXNu4ywLQoUmkRzBFMQswCQYDVQQGEwJCTTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEb\nMBkGA1UEAxMSUXVvVmFkaXMgUm9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62g\nLEz6wPJv92ZVqyM07ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon\n24QRiSemd1o417+shvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd\n+LJ2w/w4E6oM3kJpK27zPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B4f/xI4hR\nOJ/yZlZ25w9Rl6VSDE1JUZU2Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadNt54CrnMAyNojA+j5\n6hl0YgCUyyIgvpSnWbWCar6ZeXqp8kokUvd0/bpO5qgdAm6xDYBEwa7TIzdfu4V8K5Iu6H6l\ni92Z4b8nby1dqnuH/grdS/yO9SbkbnBCbjPsMZ57k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8S\nh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6szHXug/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7\nj2G4aSgWQgRecCocIdiP4b0jWy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEo\nkt4YutUqKLsRixeTmJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7\nzTSMmfXK4SVhM7JZG+Ju1zdXtg2pEto=\n-----END CERTIFICATE-----\n", + "Security Communication Root CA": "-----BEGIN CERTIFICATE-----\nMIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEYMBYGA1UE\nChMPU0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJv\nb3RDQTEwHhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5WjBQMQswCQYDVQQGEwJKUDEY\nMBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0\naW9uIFJvb3RDQTEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8\nV6UMbXaKL0u/ZPtM7orw8yl89f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzG\njGdnSj74cbAZJ6kJDKaVv0uMDPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1ae\nV+7AwFb9Ms+k2Y7CI9eNqPPYJayX5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/N\nQV3Is00qVUarH9oe4kA92819uZKAnDfdDJZkndwi92SL32HeFZRSFaB9UslLqCHJxrHty8OV\nYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2JChzAgMBAAGjPzA9MB0GA1UdDgQWBBSgc0mZ\naNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG\n9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vGkl3g0dNq/vu+m22/xwVtWSDEHPC32oRY\nAmP6SBbvT6UL90qY8j+eG61Ha2POCEfrUj94nK9NrvjVT8+amCoQQTlSxN3Zmw7vkwGusi7K\naEIkQmywszo+zenaSMQVy+n5Bw+SUEmK3TGXX8npN6o7WWWXlDLJs58+OmJYxUmtYg5xpTKq\nL8aJdkNAExNnPaJUJRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ6rBK+1YWc26sTfci\noU+tHXotRSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAiFL39vmwLAw==\n-----END CERTIFICATE-----\n", + "Sonera Class 2 Root CA": "-----BEGIN CERTIFICATE-----\nMIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEPMA0GA1UE\nChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAxMDQwNjA3Mjk0MFoX\nDTIxMDQwNjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UE\nAxMQU29uZXJhIENsYXNzMiBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJAX\nSjWdyvANlsdE+hY3/Ei9vX+ALTU74W+oZ6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gX\nGM2RX/uJ4+q/Tl18GybTdXnt5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7\nJp12W5dCsv+u8E7s3TmVToMGf+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCW\nctRUz2EjvOr7nQKV0ba5cTppCD8PtOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu\n8nYybieDwnPz3BjotJPqdURrBGAgcVeHnfO+oJAjPYok4doh28MCAwEAAaMzMDEwDwYDVR0T\nAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITTXjwwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEB\nBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt0jSv9zilzqsWuasvfDXLrNAPtEwr/IDv\na4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/3DEIcbCdjdY0RzKQxmUk96BKfARzjzlv\nF4xytb1LyHr4e4PDKE6cCepnP7JnBBvDFNr450kkkdAdavphOe9r5yF1BgfYErQhIHBCcYHa\nPJo2vqZbDWpsmh+Re/n570K6Tk6ezAyNlNzZRZxe7EJQY670XcSxEtzKO6gunRRaBXW37Ndj\n4ro1tgQIkejanZz2ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLHllpwrN9M\n-----END CERTIFICATE-----\n", + "Staat der Nederlanden Root CA": "-----BEGIN CERTIFICATE-----\nMIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJOTDEeMBwG\nA1UEChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQDEx1TdGFhdCBkZXIgTmVkZXJs\nYW5kZW4gUm9vdCBDQTAeFw0wMjEyMTcwOTIzNDlaFw0xNTEyMTYwOTE1MzhaMFUxCzAJBgNV\nBAYTAk5MMR4wHAYDVQQKExVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xJjAkBgNVBAMTHVN0YWF0\nIGRlciBOZWRlcmxhbmRlbiBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC\nAQEAmNK1URF6gaYUmHFtvsznExvWJw56s2oYHLZhWtVhCb/ekBPHZ+7d89rFDBKeNVU+LCeI\nQGv33N0iYfXCxw719tV2U02PjLwYdjeFnejKScfST5gTCaI+Ioicf9byEGW07l8Y1Rfj+MX9\n4p2i71MOhXeiD+EwR+4A5zN9RGcaC1Hoi6CeUJhoNFIfLm0B8mBF8jHrqTFoKbt6QZ7GGX+U\ntFE5A3+y3qcym7RHjm+0Sq7lr7HcsBthvJly3uSJt3omXdozSVtSnA71iq3DuD3oBmrC1SoL\nbHuEvVYFy4ZlkuxEK7COudxwC0barbxjiDn622r+I/q85Ej0ZytqERAhSQIDAQABo4GRMIGO\nMAwGA1UdEwQFMAMBAf8wTwYDVR0gBEgwRjBEBgRVHSAAMDwwOgYIKwYBBQUHAgEWLmh0dHA6\nLy93d3cucGtpb3ZlcmhlaWQubmwvcG9saWNpZXMvcm9vdC1wb2xpY3kwDgYDVR0PAQH/BAQD\nAgEGMB0GA1UdDgQWBBSofeu8Y6R0E3QA7Jbg0zTBLL9s+DANBgkqhkiG9w0BAQUFAAOCAQEA\nBYSHVXQ2YcG70dTGFagTtJ+k/rvuFbQvBgwp8qiSpGEN/KtcCFtREytNwiphyPgJWPwtArI5\nfZlmgb9uXJVFIGzmeafR2Bwp/MIgJ1HI8XxdNGdphREwxgDS1/PTfLbwMVcoEoJz6TMvplW0\nC5GUR5z6u3pCMuiufi3IvKwUv9kP2Vv8wfl6leF9fpb8cbDCTMjfRTTJzg3ynGQI0DvDKcWy\n7ZAEwbEpkcUwb8GpcjPM/l0WFywRaed+/sWDCN+83CI6LiBpIzlWYGeQiy52OfsRiJf2fL1L\nuCAWZwWN4jvBcj+UlTfHXbme2JOhF4//DGYVwSR8MnwDHTuhWEUykw==\n-----END CERTIFICATE-----\n", + "TDC Internet Root CA": "-----BEGIN CERTIFICATE-----\nMIIEKzCCAxOgAwIBAgIEOsylTDANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJESzEVMBMG\nA1UEChMMVERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTAeFw0w\nMTA0MDUxNjMzMTdaFw0yMTA0MDUxNzAzMTdaMEMxCzAJBgNVBAYTAkRLMRUwEwYDVQQKEwxU\nREMgSW50ZXJuZXQxHTAbBgNVBAsTFFREQyBJbnRlcm5ldCBSb290IENBMIIBIjANBgkqhkiG\n9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxLhAvJHVYx/XmaCLDEAedLdInUaMArLgJF/wGROnN4Nr\nXceO+YQwzho7+vvOi20jxsNuZp+Jpd/gQlBn+h9sHvTQBda/ytZO5GhgbEaqHF1j4QeGDmUA\npy6mcca8uYGoOn0a0vnRrEvLznWv3Hv6gXPU/Lq9QYjUdLP5Xjg6PEOo0pVOd20TDJ2PeAG3\nWiAfAzc14izbSysseLlJ28TQx5yc5IogCSEWVmb/Bexb4/DPqyQkXsN/cHoSxNK1EKC2IeGN\neGlVRGn1ypYcNIUXJXfi9i8nmHj9eQY6otZaQ8H/7AQ77hPv01ha/5Lr7K7a8jcDR0G2l8kt\nCkEiu7vmpwIDAQABo4IBJTCCASEwEQYJYIZIAYb4QgEBBAQDAgAHMGUGA1UdHwReMFwwWqBY\noFakVDBSMQswCQYDVQQGEwJESzEVMBMGA1UEChMMVERDIEludGVybmV0MR0wGwYDVQQLExRU\nREMgSW50ZXJuZXQgUm9vdCBDQTENMAsGA1UEAxMEQ1JMMTArBgNVHRAEJDAigA8yMDAxMDQw\nNTE2MzMxN1qBDzIwMjEwNDA1MTcwMzE3WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUbGQB\nx/2FbazI2p5QCIUItTxWqFAwHQYDVR0OBBYEFGxkAcf9hW2syNqeUAiFCLU8VqhQMAwGA1Ud\nEwQFMAMBAf8wHQYJKoZIhvZ9B0EABBAwDhsIVjUuMDo0LjADAgSQMA0GCSqGSIb3DQEBBQUA\nA4IBAQBOQ8zR3R0QGwZ/t6T609lN+yOfI1Rb5osvBCiLtSdtiaHsmGnc540mgwV5dOy0uaOX\nwTUA/RXaOYE6lTGQ3pfphqiZdwzlWqCE/xIWrG64jcN7ksKsLtB9KOy282A4aW8+2ARVPp7M\nVdK6/rtHBNcK2RYKNCn1WBPVT8+PVkuzHu7TmHnaCB4Mb7j4Fifvwm899qNLPg7kbWzbO0ES\nm70NRyN/PErQr8Cv9u8btRXE64PECV90i9kR+8JWsTz4cMo0jUNAE4z9mQNUecYu6oah9jrU\nCbz0vGbMPVjQV0kK7iXiQe4T+Zs4NNEA9X7nlB38aQNiuJkFBT1reBK9sG9l\n-----END CERTIFICATE-----\n", + "UTN DATACorp SGC Root CA": "-----BEGIN CERTIFICATE-----\nMIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCBkzELMAkG\nA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UE\nChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVz\ndC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3JwIFNHQzAeFw05OTA2MjQxODU3MjFaFw0x\nOTA2MjQxOTA2MzBaMIGTMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNh\nbHQgTGFrZSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsT\nGGh0dHA6Ly93d3cudXNlcnRydXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dD\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6\nE5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZD0/Ww5y0\nvpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK4ESGoE1O1kduSUrL\nZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykqlXvY8qdOD1R8oQ2AswkDwf9c\n3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulWbfXv33i+Ybqypa4ETLyorGkVl73v67SM\nvzX41MPRKA5cOp9wGDMgd8SirwIDAQABo4GrMIGoMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8E\nBTADAQH/MB0GA1UdDgQWBBRTMtGzz3/64PGgXYVOktKeRR20TzA9BgNVHR8ENjA0MDKgMKAu\nhixodHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dDLmNybDAqBgNVHSUE\nIzAhBggrBgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3DQEBBQUAA4IB\nAQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowftGzet/Hy+\nUUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyjj98C5OBxOvG0I3Kg\nqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVHKWss5nbZqSl9Mt3JNjy9rjXx\nEZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jF\nVkwPDPafepE39peC4N1xaf92P2BNPM/3mfnGV/TJVTl4uix5yaaIK/QI\n-----END CERTIFICATE-----\n", + "UTN USERFirst Hardware Root CA": "-----BEGIN CERTIFICATE-----\nMIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCBlzELMAkG\nA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UE\nChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVz\ndC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQy\nWhcNMTkwNzA5MTgxOTIyWjCBlzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQH\nEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYD\nVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt\nSGFyZHdhcmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn\n0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJM6Rsl7Ho\nxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4aMXcMmgF6sTLjKwEH\nOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNdoI6yqqr2jmmIBsX6iSHzCJ1p\nLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqIDsjfPe58BEydCl5rkdbux+0ojatNh4lz\n0G6k0B4WixThdkQDf2Os5M1JnMWS9KsyoUhbAgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8G\nA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9\nMDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3\nYXJlLmNybDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEF\nBQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM//bey1Wi\nCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28GpgoiskliCE7/yMgUsogWXecB\n5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gECJChicsZUN/KHAG8HQQZexB2\nlzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t3XbWOTCC8KucUvIqx69JXn7HaOWCgchq\nJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSSKqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnAS\nfxAynB67nfhmqA==\n-----END CERTIFICATE-----\n", + "Camerfirma Chambers of Commerce Root": "-----BEGIN CERTIFICATE-----\nMIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEnMCUGA1UE\nChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3\nLmNoYW1iZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdDAe\nFw0wMzA5MzAxNjEzNDNaFw0zNzA5MzAxNjEzNDRaMH8xCzAJBgNVBAYTAkVVMScwJQYDVQQK\nEx5BQyBDYW1lcmZpcm1hIFNBIENJRiBBODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cu\nY2hhbWJlcnNpZ24ub3JnMSIwIAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIB\nIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1\nc2VHfRtbunXF/KGIJPov7coISjlUxFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0d\nBmpAPrMMhe5cG3nCYsS4No41XQEMIwRHNaqbYE6gZj3LJgqcQKH0XZi/caulAGgq7YN6D6IU\ntdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jWDA+wWFjbw2Y3npuRVDM30pQcakjJyfKl2qUM\nI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFVd9oKDMyXroDclDZK9D7ONhMeU+SsTjoF\n7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIGA1UdEwEB/wQIMAYBAf8CAQwwPAYDVR0f\nBDUwMzAxoC+gLYYraHR0cDovL2NybC5jaGFtYmVyc2lnbi5vcmcvY2hhbWJlcnNyb290LmNy\nbDAdBgNVHQ4EFgQU45T1sU3p26EpW1eLTXYGduHRooowDgYDVR0PAQH/BAQDAgEGMBEGCWCG\nSAGG+EIBAQQEAwIABzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hhbWJlcnNpZ24ub3Jn\nMCcGA1UdEgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYDVR0gBFEwTzBN\nBgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJzaWduLm9y\nZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEBAAxBl8IahsAifJ/7\nkPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZdp0AJPaxJRUXcLo0waLIJuvvD\nL8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QU\nu/wNUPf6s+xCX6ndbcj0dc97wXImsQEcXCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34Oi\nrsrXdx/nADydb47kMgkdTXg0eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuz\nPu5ifdmA6Ap1erfutGWaIZDgqtCYvDi1czyL+Nw=\n-----END CERTIFICATE-----\n", + "Camerfirma Global Chambersign Root": "-----BEGIN CERTIFICATE-----\nMIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEnMCUGA1UE\nChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3\nLmNoYW1iZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwHhcN\nMDMwOTMwMTYxNDE4WhcNMzcwOTMwMTYxNDE4WjB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe\nQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNo\nYW1iZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0G\nCSqGSIb3DQEBAQUAA4IBDQAwggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQK\nkotgVvq0Mi+ITaFgCPS3CU6gSS9J1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/s\nQJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8Oby4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpVeAp3qdjq\nGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl6DJWk0aJqCWKZQbua795B9Dxt6/tLE2Su8Co\nX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c8lCrEqWhz0hQpe/SyBoT+rB/sYIcd2oP\nX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0TAQH/BAgwBgEB/wIBDDA/BgNVHR8EODA2\nMDSgMqAwhi5odHRwOi8vY3JsLmNoYW1iZXJzaWduLm9yZy9jaGFtYmVyc2lnbnJvb3QuY3Js\nMB0GA1UdDgQWBBRDnDafsJ4wTcbOX60Qq+UDpfqpFDAOBgNVHQ8BAf8EBAMCAQYwEQYJYIZI\nAYb4QgEBBAQDAgAHMCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBjaGFtYmVyc2lnbi5v\ncmcwKgYDVR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9yZzBbBgNVHSAE\nVDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hhbWJlcnNp\nZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0BAQUFAAOCAQEAPDtw\nkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUMbKGKfKX0j//U2K0X1S0E0T9Y\ngOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXiryQZVgICsroPFOrGimbBhkVVi76Svpyk\nBMdJPJ7oKXqJ1/6v/2j1pReQvayZzKWGVwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHR\nJw0lyDL4IBHNfTIzSJRUTN3cecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxK\noHflCStFREest2d/AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A==\n-----END CERTIFICATE-----\n", + "NetLock Notary (Class A) Root": "-----BEGIN CERTIFICATE-----\nMIIGfTCCBWWgAwIBAgICAQMwDQYJKoZIhvcNAQEEBQAwga8xCzAJBgNVBAYTAkhVMRAwDgYD\nVQQIEwdIdW5nYXJ5MREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxv\nemF0Yml6dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UE\nAxMtTmV0TG9jayBLb3pqZWd5em9pIChDbGFzcyBBKSBUYW51c2l0dmFueWtpYWRvMB4XDTk5\nMDIyNDIzMTQ0N1oXDTE5MDIxOTIzMTQ0N1owga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQIEwdI\ndW5nYXJ5MREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6\ndG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0\nTG9jayBLb3pqZWd5em9pIChDbGFzcyBBKSBUYW51c2l0dmFueWtpYWRvMIIBIjANBgkqhkiG\n9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvHSMD7tM9DceqQWC2ObhbHDqeLVu0ThEDaiDzl3S1tWB\nxdRL51uUcCbbO51qTGL3cfNk1mE7PetzozfZz+qMkjvN9wfcZnSX9EUi3fRc4L9t875lM+QV\nOr/bmJBVOMTtplVjC7B4BPTjbsE/jvxReB+SnoPC/tmwqcm8WgD/qaiYdPv2LD4VOQ22BFWo\nDpggQrOxJa1+mm9dU7GrDPzr4PN6s6iz/0b2Y6LYOph7tqyF/7AlT3Rj5xMHpQqPBffAZG9+\npyeAlt7ULoZgx2srXnN7F+eRP2QM2EsiNCubMvJIH5+hCoR64sKtlz2O1cH5VqNQ6ca0+pii\n7pXmKgOM3wIDAQABo4ICnzCCApswDgYDVR0PAQH/BAQDAgAGMBIGA1UdEwEB/wQIMAYBAf8C\nAQQwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1GSUdZRUxFTSEg\nRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pvbGdhbHRhdGFz\naSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQuIEEgaGl0\nZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2VnLWJp\nenRvc2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0\nZXRlbGUgYXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGph\ncmFzIGxlaXJhc2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxh\ncGphbiBhIGh0dHBzOi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRv\nIGF6IGVsbGVub3J6ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRo\nZSBpc3N1YW5jZSBhbmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3Qg\ndG8gdGhlIE5ldExvY2sgQ1BTIGF2YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRsb2NrLm5l\ndC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBjcHNAbmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUA\nA4IBAQBIJEb3ulZv+sgoA0BO5TE5ayZrU3/b39/zcT0mwBQOxmd7I6gMc90Bu8bKbjc5VdXH\njFYgDigKDtIqpLBJUsY4B/6+CgmM0ZjPytoUMaFP0jn8DxEsQ8Pdq5PHVT5HfBgaANzze9jy\nf1JsIPQLX2lS9O74silg6+NJMSEN1rUQQeJBCWziGppWS3cC9qCbmieH6FUpccKQn0V4GuEV\nZD3QDtigdp+uxdAu6tYPVuxkf1qbFFgBJ34TUMdrKuZoPL9coAob4Q566eKAw+np9v1sEZ7Q\n5SgnK1QyQhSCdeZK8CtmdWOMovsEPoMOmzbwGOQmIMOM8CgHrTwXZoi1/baI\n-----END CERTIFICATE-----\n", + "NetLock Business (Class B) Root": "-----BEGIN CERTIFICATE-----\nMIIFSzCCBLSgAwIBAgIBaTANBgkqhkiG9w0BAQQFADCBmTELMAkGA1UEBhMCSFUxETAPBgNV\nBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0b25zYWdpIEtmdC4x\nGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMTIwMAYDVQQDEylOZXRMb2NrIFV6bGV0aSAo\nQ2xhc3MgQikgVGFudXNpdHZhbnlraWFkbzAeFw05OTAyMjUxNDEwMjJaFw0xOTAyMjAxNDEw\nMjJaMIGZMQswCQYDVQQGEwJIVTERMA8GA1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExv\nY2sgSGFsb3phdGJpenRvbnNhZ2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sx\nMjAwBgNVBAMTKU5ldExvY2sgVXpsZXRpIChDbGFzcyBCKSBUYW51c2l0dmFueWtpYWRvMIGf\nMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCx6gTsIKAjwo84YM/HRrPVG/77uZmeBNwcf4xK\ngZjupNTKihe5In+DCnVMm8Bp2GQ5o+2So/1bXHQawEfKOml2mrriRBf8TKPV/riXiK+IA4kf\npPIEPsgHC+b5sy96YhQJRhTKZPWLgLViqNhr1nGTLbO/CVRY7QbrqHvcQ7GhaQIDAQABo4IC\nnzCCApswEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNVHQ8BAf8EBAMCAAYwEQYJYIZIAYb4QgEB\nBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1GSUdZRUxFTSEgRXplbiB0YW51c2l0dmFu\neSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pvbGdhbHRhdGFzaSBGZWx0ZXRlbGVpYmVu\nIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQuIEEgaGl0ZWxlc2l0ZXMgZm9seWFt\nYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2VnLWJpenRvc2l0YXNhIHZlZGku\nIEEgZGlnaXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYXogZWxvaXJ0\nIGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJhc2EgbWVn\ndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBhIGh0dHBzOi8v\nd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVub3J6ZXNA\nbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1YW5jZSBhbmQg\ndGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sg\nQ1BTIGF2YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUt\nbWFpbCBhdCBjcHNAbmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4GBAATbrowXr/gOkDFO\nzT4JwG06sPgzTEdM43WIEJessDgVkcYplswhwG08pXTP2IKlOcNl40JwuyKQ433bNXbhoLXa\nn3BukxowOR0w2y7jfLKRstE3Kfq51hdcR0/jHTjrn9V7lagonhVK0dHQKwCXoOKSNitjrFgB\nazMpUIaD8QFI\n-----END CERTIFICATE-----\n", + "NetLock Express (Class C) Root": "-----BEGIN CERTIFICATE-----\nMIIFTzCCBLigAwIBAgIBaDANBgkqhkiG9w0BAQQFADCBmzELMAkGA1UEBhMCSFUxETAPBgNV\nBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0b25zYWdpIEtmdC4x\nGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMTQwMgYDVQQDEytOZXRMb2NrIEV4cHJlc3N6\nIChDbGFzcyBDKSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNTE0MDgxMVoXDTE5MDIyMDE0\nMDgxMVowgZsxCzAJBgNVBAYTAkhVMREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0\nTG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRv\nazE0MDIGA1UEAxMrTmV0TG9jayBFeHByZXNzeiAoQ2xhc3MgQykgVGFudXNpdHZhbnlraWFk\nbzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA6+ywbGGKIyWvYCDj2Z/8kwvbXY2wobNA\nOoLO/XXgeDIDhlqGlZHtU/qdQPzm6N3ZW3oDvV3zOwzDUXmbrVWg6dADEK8KuhRC2VImESLH\n0iDMgqSaqf64gXadarfSNnU+sYYJ9m5tfk63euyucYT2BDMIJTLrdKwWRMbkQJMdf60CAwEA\nAaOCAp8wggKbMBIGA1UdEwEB/wQIMAYBAf8CAQQwDgYDVR0PAQH/BAQDAgAGMBEGCWCGSAGG\n+EIBAQQEAwIABzCCAmAGCWCGSAGG+EIBDQSCAlEWggJNRklHWUVMRU0hIEV6ZW4gdGFudXNp\ndHZhbnkgYSBOZXRMb2NrIEtmdC4gQWx0YWxhbm9zIFN6b2xnYWx0YXRhc2kgRmVsdGV0ZWxl\naWJlbiBsZWlydCBlbGphcmFzb2sgYWxhcGphbiBrZXN6dWx0LiBBIGhpdGVsZXNpdGVzIGZv\nbHlhbWF0YXQgYSBOZXRMb2NrIEtmdC4gdGVybWVrZmVsZWxvc3NlZy1iaXp0b3NpdGFzYSB2\nZWRpLiBBIGRpZ2l0YWxpcyBhbGFpcmFzIGVsZm9nYWRhc2FuYWsgZmVsdGV0ZWxlIGF6IGVs\nb2lydCBlbGxlbm9yemVzaSBlbGphcmFzIG1lZ3RldGVsZS4gQXogZWxqYXJhcyBsZWlyYXNh\nIG1lZ3RhbGFsaGF0byBhIE5ldExvY2sgS2Z0LiBJbnRlcm5ldCBob25sYXBqYW4gYSBodHRw\nczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIGNpbWVuIHZhZ3kga2VyaGV0byBheiBlbGxlbm9y\nemVzQG5ldGxvY2submV0IGUtbWFpbCBjaW1lbi4gSU1QT1JUQU5UISBUaGUgaXNzdWFuY2Ug\nYW5kIHRoZSB1c2Ugb2YgdGhpcyBjZXJ0aWZpY2F0ZSBpcyBzdWJqZWN0IHRvIHRoZSBOZXRM\nb2NrIENQUyBhdmFpbGFibGUgYXQgaHR0cHM6Ly93d3cubmV0bG9jay5uZXQvZG9jcyBvciBi\neSBlLW1haWwgYXQgY3BzQG5ldGxvY2submV0LjANBgkqhkiG9w0BAQQFAAOBgQAQrX/XDDKA\nCtiG8XmYta3UzbM2xJZIwVzNmtkFLp++UOv0JhQQLdRmF/iewSf98e3ke0ugbLWrmldwpu2g\npO0u9f38vf5NNwgMvOOWgyL1SRt/Syu0VMGAfJlOHdCM7tCs5ZL6dVb+ZKATj7i4Fp1hBWeA\nyNDYpQcCNJgEjTME1A==\n-----END CERTIFICATE-----\n", + "XRamp Global CA Root": "-----BEGIN CERTIFICATE-----\nMIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCBgjELMAkG\nA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJh\nbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlm\naWNhdGlvbiBBdXRob3JpdHkwHhcNMDQxMTAxMTcxNDA0WhcNMzUwMTAxMDUzNzE5WjCBgjEL\nMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMb\nWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2Vy\ndGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCY\nJB69FbS638eMpSe2OAtp87ZOqCwuIR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCP\nKZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMxfoArtYzAQDsRhtDLooY2YKTVMIJt2W7QDxIEM5df\nT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FEzG+gSqmUsE3a56k0enI4qEHMPJQRfevIpoy3\nhsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqsAxcZZPRaJSKNNCyy9mgdEm3Tih4U2sSP\npuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNViPvryxS3T/dRlAgMBAAGjgZ8wgZwwEwYJ\nKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O\nBBYEFMZPoj0GY4QJnM5i5ASsjVy16bYbMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwu\neHJhbXBzZWN1cml0eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQEwDQYJKoZIhvcN\nAQEFBQADggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc/Kh4ZzXxHfAR\nvbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxtqZ4Bfj8p\nzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLaIR9NmXmd4c8nnxCb\nHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSyi6mx5O+aGtA9aZnuqCij4Tyz\n8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQO+7ETPTsJ3xCwnR8gooJybQDJbw=\n-----END CERTIFICATE-----\n", + "Go Daddy Class 2 CA": "-----BEGIN CERTIFICATE-----\nMIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEhMB8GA1UE\nChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAy\nIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3MDYyMFoXDTM0MDYyOTE3MDYy\nMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjEx\nMC8GA1UECxMoR28gRGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAw\nDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWiz\nV3GgXne77ZtJ6XCAPVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HF\niH7Eux6wwdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi\nEqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lN\nf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+YihfukEHU1jPEX44\ndMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLEsNKR1EwRcbNhyz2h/t2oatTj\nMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h/t2oatTjoWekZTBjMQswCQYDVQQGEwJV\nUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRk\neSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJ\nKoZIhvcNAQEFBQADggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYX\nMP80kWNyOO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P\nTMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQHmyW74cN\nxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mERdEr/VxqHD3VILs9R\naRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5CufReYNnyicsbkqWletNw+vHX/b\nvZ8=\n-----END CERTIFICATE-----\n", + "Starfield Class 2 CA": "-----BEGIN CERTIFICATE-----\nMIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzElMCMGA1UE\nChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZpZWxkIENs\nYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNjI5MTczOTE2WhcNMzQwNjI5\nMTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2ll\ncywgSW5jLjEyMDAGA1UECxMpU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRo\nb3JpdHkwggEgMA0GCSqGSIb3DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N\n78gDGIc/oav7PKaf8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMe\nj2YcOadN+lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0\nX9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aaK4Umkhyn\nArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA1W4TNSNe35tfPe/W\n93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0GA1UdDgQWBBS/X7fRzt0fhvRb\nVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fRzt0fhvRbVazc1xDCDqmI56FspGowaDEL\nMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAw\nBgNVBAsTKVN0YXJmaWVsZCBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwG\nA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1ep\noXkJKtv3L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D\neruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJlxy16paq8\nU4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynpVSJYACPq4xJDKVtH\nCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEYWQPJIrSPnNVeKtelttQKbfi3\nQBFGmh95DmK/D5fs4C8fF5Q=\n-----END CERTIFICATE-----\n", + "StartCom Certification Authority": "-----BEGIN CERTIFICATE-----\nMIIHhzCCBW+gAwIBAgIBLTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UE\nChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUg\nU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcN\nMDYwOTE3MTk0NjM3WhcNMzYwOTE3MTk0NjM2WjB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN\nU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2ln\nbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0G\nCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul3\n8kMKogZkpMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf\nOQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/CJi/6tRYc\ncjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYTKqi5pquDSR3l8u/d\n5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNiHzvEvqBTViVsUQn3qqvKv3b9\nbZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMMAv+Z6+hsTXBbKWWc3apdzK8BMewM69KN\n6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w+2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHu\nEhANxjJ/GP/89PrNbpHoNkm+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZP\nV/+Qt+OR0t3vwmC3Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOz\nEmDyei+B26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID\nAQABo4ICEDCCAgwwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE\nFE4L7xqkQFulF2mHMMo0aEPQQa7yMB8GA1UdIwQYMBaAFE4L7xqkQFulF2mHMMo0aEPQQa7y\nMIIBWgYDVR0gBIIBUTCCAU0wggFJBgsrBgEEAYG1NwEBATCCATgwLgYIKwYBBQUHAgEWImh0\ndHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93\nd3cuc3RhcnRzc2wuY29tL2ludGVybWVkaWF0ZS5wZGYwgc8GCCsGAQUFBwICMIHCMCcWIFN0\nYXJ0IENvbW1lcmNpYWwgKFN0YXJ0Q29tKSBMdGQuMAMCAQEagZZMaW1pdGVkIExpYWJpbGl0\neSwgcmVhZCB0aGUgc2VjdGlvbiAqTGVnYWwgTGltaXRhdGlvbnMqIG9mIHRoZSBTdGFydENv\nbSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBQb2xpY3kgYXZhaWxhYmxlIGF0IGh0dHA6Ly93\nd3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG\n+EIBDQQrFilTdGFydENvbSBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkq\nhkiG9w0BAQsFAAOCAgEAjo/n3JR5fPGFf59Jb2vKXfuM/gTFwWLRfUKKvFO3lANmMD+x5wqn\nUCBVJX92ehQN6wQOQOY+2IirByeDqXWmN3PH/UvSTa0XQMhGvjt/UfzDtgUx3M2FIk5xt/Jx\nXrAaxrqTi3iSSoX4eA+D/i+tLPfkpLst0OcNOrg+zvZ49q5HJMqjNTbOx8aHmNrs++myzieb\niMMEofYLWWivydsQD032ZGNcpRJvkrKTlMeIFw6Ttn5ii5B/q06f/ON1FE8qMt9bDeD1e5MN\nq6HPh+GlBEXoPBKlCcWw0bdT82AUuoVpaiF8H3VhFyAXe2w7QSlc4axa0c2Mm+tgHRns9+Ww\n2vl5GKVFP0lDV9LdJNUso/2RjSe15esUBppMeyG7Oq0wBhjA2MFrLH9ZXF2RsXAiV+uKa0hK\n1Q8p7MZAwC+ITGgBF3f0JBlPvfrhsiAhS90a2Cl9qrjeVOwhVYBsHvUwyKMQ5bLmKhQxw4Ut\njJixhlpPiVktucf3HMiKf8CdBUrmQk9io20ppB+Fq9vlgcitKj1MXVuEJnHEhV5xJMqlG2zY\nYdMa4FTbzrqpMrUi9nNBCV24F10OD5mQ1kfabwo6YigUZ4LZ8dCAWZvLMdibD4x3TrVoivJs\n9iQOLWxwxXPR3hTQcY+203sC9uO41Alua551hDnmfyWl8kgAwKQB2j8=\n-----END CERTIFICATE-----\n", + "Taiwan GRCA": "-----BEGIN CERTIFICATE-----\nMIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUFADA/MQswCQYD\nVQQGEwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENlcnRpZmljYXRpb24gQXV0aG9y\naXR5MB4XDTAyMTIwNTEzMjMzM1oXDTMyMTIwNTEzMjMzM1owPzELMAkGA1UEBhMCVFcxMDAu\nBgNVBAoMJ0dvdmVybm1lbnQgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJ\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN8\n6aXfTEc2pBsBHH8eV4qNw8XRIePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UKIXZ3/6m3xnOU\nT0b3EEk3+qhZSV1qgQdW8or5BtD3cCJNtLdBuTK4sfCxw5w/cP1T3YGq2GN49thTbqGsaoQk\nclSGxtKyyhwOeYHWtXBiCAEuTk8O1RGvqa/lmr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAts\nF/tnyMKtsc2AtJfcdgEWFelq16TheEfOhtX7MfP6Mb40qij7cEwdScevLJ1tZqa2jWR+tSBq\nnTuBto9AAGdLiYa4zGX+FVPpBMHWXx1E1wovJ5pGfaENda1UhhXcSTvxls4Pm6Dso3pdvtUq\ndULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7Q3hub/FCVGqY8A2tl+lSXunVanLeavcb\nYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHKYS1tB6iEfC3uUSXxY5Ce/eFXiGvviiNt\nsea9P63RPZYLhY3Naye7twWb7LuRqQoHEgKXTiCQ8P8NHuJBO9NAOueNXdpm5AKwB1KYXA6O\nM5zCppX7VRluTI6uSw+9wThNXo+EHWbNxWCWtFJaBYmOlXqYwZE8lSOyDvR5tMl8wUohAgMB\nAAGjajBoMB0GA1UdDgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNVHRMEBTADAQH/MDkG\nBGcqBwAEMTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg209yewDL7MTqK\nUWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2WPWus4MzeKR6dBcZTulStbng\nCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2JyftB8M3jh+Vzj8jeJPXgyfqzvS/3WXy6TjZwj/\n5cAWtUgBfen5Cv8b5Wppv3ghqMKnI6mGq3ZW6A4M9hPdKmaKZEk9GhiHkASfQlK3T8v+R0F2\nNe//AHY2RTKbxkaFXeIksB7jSJaYV0eUVXoPQbFEJPPB/hprv4j9wabak2BegUqZIJxIZhm1\nAHlUD7gsL0u8qV1bYH+Mh6XgUmMqvtg7hUAV/h62ZT/FS9p+tXo1KaMuephgIqP0fSdOLeq0\ndDzpD6QzDxARvBMB1uUO07+1EqLhRSPAzAhuYbeJq4PjJB7mXQfnHyA+z2fI56wwbSdLaG5L\nKlwCCDTb+HbkZ6MmnD+iMsJKxYEYMRBWqoTvLQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05e\nr/ayl4WXudpVBrkk7tfGOB5jGxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44Vbnz\nssQwmSNOXfJIoRIM3BKQCZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDeLMDDav7v\n3Aun+kbfYNucpllQdSNpc5Oy+fwC00fmcc4QAu4njIT/rEUNE1yDMuAlpYYsfPQS\n-----END CERTIFICATE-----\n", + "Firmaprofesional Root CA": "-----BEGIN CERTIFICATE-----\nMIIEVzCCAz+gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBnTELMAkGA1UEBhMCRVMxIjAgBgNV\nBAcTGUMvIE11bnRhbmVyIDI0NCBCYXJjZWxvbmExQjBABgNVBAMTOUF1dG9yaWRhZCBkZSBD\nZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODEmMCQGCSqGSIb3\nDQEJARYXY2FAZmlybWFwcm9mZXNpb25hbC5jb20wHhcNMDExMDI0MjIwMDAwWhcNMTMxMDI0\nMjIwMDAwWjCBnTELMAkGA1UEBhMCRVMxIjAgBgNVBAcTGUMvIE11bnRhbmVyIDI0NCBCYXJj\nZWxvbmExQjBABgNVBAMTOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVz\naW9uYWwgQ0lGIEE2MjYzNDA2ODEmMCQGCSqGSIb3DQEJARYXY2FAZmlybWFwcm9mZXNpb25h\nbC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDnIwNvbyOlXnjOlSztlB5u\nCp4Bx+ow0Syd3Tfom5h5VtP8c9/Qit5Vj1H5WuretXDE7aTt/6MNbg9kUDGvASdYrv5sp0ov\nFy3Tc9UTHI9ZpTQsHVQERc1ouKDAA6XPhUJHlShbz++AbOCQl4oBPB3zhxAwJkh91/zpnZFx\n/0GaqUC1N5wpIE8fUuOgfRNtVLcK3ulqTgesrBlf3H5idPayBQC6haD9HThuy1q7hryUZzM1\ngywfI834yJFxzJeL764P3CkDG8A563DtwW4O2GcLiam8NeTvtjS0pbbELaW+0MOUJEjb35bT\nALVmGotmBQ/dPz/LP6pemkr4tErvlTcbAgMBAAGjgZ8wgZwwKgYDVR0RBCMwIYYfaHR0cDov\nL3d3dy5maXJtYXByb2Zlc2lvbmFsLmNvbTASBgNVHRMBAf8ECDAGAQH/AgEBMCsGA1UdEAQk\nMCKADzIwMDExMDI0MjIwMDAwWoEPMjAxMzEwMjQyMjAwMDBaMA4GA1UdDwEB/wQEAwIBBjAd\nBgNVHQ4EFgQUMwugZtHq2s7eYpMEKFK1FH84aLcwDQYJKoZIhvcNAQEFBQADggEBAEdz/o0n\nVPD11HecJ3lXV7cVVuzH2Fi3AQL0M+2TUIiefEaxvT8Ub/GzR0iLjJcG1+p+o1wqu00vR+L4\nOQbJnC4xGgN49Lw4xiKLMzHwFgQEffl25EvXwOaD7FnMP97/T2u3Z36mhoEyIwOdyPdfwUpg\npZKpsaSgYMN4h7Mi8yrrW6ntBas3D7Hi05V2Y1Z0jFhyGzflZKG+TQyTmAyX9odtsz/ny4Cm\n7YjHX1BiAuiZdBbQ5rQ58SfLyEDW44YQqSMSkuBpQWOnryULwMWSyx6Yo1q6xTMPoJcB3X/g\ne9YGVM+h4k0460tQtcsm9MracEpqoeJ5quGnM/b9Sh/22WA=\n-----END CERTIFICATE-----\n", + "Wells Fargo Root CA": "-----BEGIN CERTIFICATE-----\nMIID5TCCAs2gAwIBAgIEOeSXnjANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UEBhMCVVMxFDAS\nBgNVBAoTC1dlbGxzIEZhcmdvMSwwKgYDVQQLEyNXZWxscyBGYXJnbyBDZXJ0aWZpY2F0aW9u\nIEF1dGhvcml0eTEvMC0GA1UEAxMmV2VsbHMgRmFyZ28gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRo\nb3JpdHkwHhcNMDAxMDExMTY0MTI4WhcNMjEwMTE0MTY0MTI4WjCBgjELMAkGA1UEBhMCVVMx\nFDASBgNVBAoTC1dlbGxzIEZhcmdvMSwwKgYDVQQLEyNXZWxscyBGYXJnbyBDZXJ0aWZpY2F0\naW9uIEF1dGhvcml0eTEvMC0GA1UEAxMmV2VsbHMgRmFyZ28gUm9vdCBDZXJ0aWZpY2F0ZSBB\ndXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVqDM7Jvk0/82bfuUE\nR84A4n135zHCLielTWi5MbqNQ1mXx3Oqfz1cQJ4F5aHiidlMuD+b+Qy0yGIZLEWukR5zcUHE\nSxP9cMIlrCL1dQu3U+SlK93OvRw6esP3E48mVJwWa2uv+9iWsWCaSOAlIiR5NM4OJgALTqv9\ni86C1y8IcGjBqAr5dE8Hq6T54oN+J3N0Prj5OEL8pahbSCOz6+MlsoCultQKnMJ4msZoGK43\nYjdeUXWoWGPAUe5AeH6orxqg4bB4nVCMe+ez/I4jsNtlAHCEAQgAFG5Uhpq6zPk3EPbg3oQt\nnaSFN9OH4xXQwReQfhkhahKpdv0SAulPIV4XAgMBAAGjYTBfMA8GA1UdEwEB/wQFMAMBAf8w\nTAYDVR0gBEUwQzBBBgtghkgBhvt7hwcBCzAyMDAGCCsGAQUFBwIBFiRodHRwOi8vd3d3Lndl\nbGxzZmFyZ28uY29tL2NlcnRwb2xpY3kwDQYJKoZIhvcNAQEFBQADggEBANIn3ZwKdyu7IvIC\ntUpKkfnRLb7kuxpo7w6kAOnu5+/u9vnldKTC2FJYxHT7zmu1Oyl5GFrvm+0fazbuSCUlFLZW\nohDo7qd/0D+j0MNdJu4HzMPBJCGHHt8qElNvQRbn7a6U+oxy+hNH8Dx+rn0ROhPs7fpvcmR7\nnX1/Jv16+yWt6j4pf0zjAFcysLPp7VMX2YuyFA4w6OXVE8Zkr8QA1dhYJPz1j+zxx32l2w8n\n0cbyQIjmH/ZhqPRCyLk306m+LFZ4wnKbWV01QIroTmMatukgalHizqSQ33ZwmVxwQ023tqcZ\nZE6St8WRPH9IFmV7Fv3L/PvZ1dZPIWU7Sn9Ho/s=\n-----END CERTIFICATE-----\n", + "Swisscom Root CA 1": "-----BEGIN CERTIFICATE-----\nMIIF2TCCA8GgAwIBAgIQXAuFXAvnWUHfV8w/f52oNjANBgkqhkiG9w0BAQUFADBkMQswCQYD\nVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2VydGlmaWNh\ndGUgU2VydmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3QgQ0EgMTAeFw0wNTA4MTgxMjA2\nMjBaFw0yNTA4MTgyMjA2MjBaMGQxCzAJBgNVBAYTAmNoMREwDwYDVQQKEwhTd2lzc2NvbTEl\nMCMGA1UECxMcRGlnaXRhbCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Nj\nb20gUm9vdCBDQSAxMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0LmwqAzZuz8h\n+BvVM5OAFmUgdbI9m2BtRsiMMW8Xw/qabFbtPMWRV8PNq5ZJkCoZSx6jbVfd8StiKHVFXqrW\nW/oLJdihFvkcxC7mlSpnzNApbjyFNDhhSbEAn9Y6cV9Nbc5fuankiX9qUvrKm/LcqfmdmUc/\nTilftKaNXXsLmREDA/7n29uj/x2lzZAeAR81sH8A25Bvxn570e56eqeqDFdvpG3FEzuwpdnt\nMhy0XmeLVNxzh+XTF3xmUHJd1BpYwdnP2IkCb6dJtDZd0KTeByy2dbcokdaXvij1mB7qWybJ\nvbCXc9qukSbraMH5ORXWZ0sKbU/Lz7DkQnGMU3nn7uHbHaBuHYwadzVcFh4rUx80i9Fs/PJn\nB3r1re3WmquhsUvhzDdf/X/NTa64H5xD+SpYVUNFvJbNcA78yeNmuk6NO4HLFWR7uZToXTNS\nhXEuT46iBhFRyePLoW4xCGQMwtI89Tbo19AOeCMgkckkKmUpWyL3Ic6DXqTz3kvTaI9GdVyD\nCW4pa8RwjPWd1yAv/0bSKzjCL3UcPX7ape8eYIVpQtPM+GP+HkM5haa2Y0EQs3MevNP6yn0W\nR+Kn1dCjigoIlmJWbjTb2QK5MHXjBNLnj8KwEUAKrNVxAmKLMb7dxiNYMUJDLXT5xp6mig/p\n/r+D5kNXJLrvRjSq1xIBOO0CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0hBBYw\nFDASBgdghXQBUwABBgdghXQBUwABMBIGA1UdEwEB/wQIMAYBAf8CAQcwHwYDVR0jBBgwFoAU\nAyUv3m+CATpcLNwroWm1Z9SM0/0wHQYDVR0OBBYEFAMlL95vggE6XCzcK6FptWfUjNP9MA0G\nCSqGSIb3DQEBBQUAA4ICAQA1EMvspgQNDQ/NwNurqPKIlwzfky9NfEBWMXrrpA9gzXrzvsMn\njgM+pN0S734edAY8PzHyHHuRMSG08NBsl9Tpl7IkVh5WwzW9iAUPWxAaZOHHgjD5Mq2eUCzn\neAXQMbFamIp1TpBcahQq4FJHgmDmHtqBsfsUC1rxn9KVuj7QG9YVHaO+htXbD8BJZLsuUBlL\n0iT43R4HVtA4oJVwIHaM190e3p9xxCPvgxNcoyQVTSlAPGrEqdi3pkSlDfTgnXceQHAm/NrZ\nNuR55LU/vJtlvrsRls/bxig5OgjOR1tTWsWZ/l2p3e9M1MalrQLmjAcSHm8D0W+go/MpvRLH\nUKKwf4ipmXeascClOS5cfGniLLDqN2qk4Vrh9VDlg++luyqI54zb/W1elxmofmZ1a3Hqv7HH\nb6D0jqTsNFFbjCYDcKF31QESVwA12yPeDooomf2xEG9L/zgtYE4snOtnta1J7ksfrK/7DZBa\nZmBwXarNeNQk7shBoJMBkpxqnvy5JMWzFYJ+vq6VK+uxwNrjAWALXmmshFZhvnEX/h0TD/7G\nh0Xp/jKgGg0TpJRVcaUWi7rKibCyx/yP2FS1k2Kdzs9Z+z0YzirLNRWCXf9UIltxUvu3yf5g\nmwBBZPCqKuy2QkPOiWaByIufOVQDJdMWNY6E0F/6MBr1mmz0DlP5OlvRHA==\n-----END CERTIFICATE-----\n", + "DigiCert Assured ID Root CA": "-----BEGIN CERTIFICATE-----\nMIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBlMQswCQYD\nVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu\nY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMDYxMTEwMDAw\nMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQg\nSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1\ncmVkIElEIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOA\nXLGH87dg+XESpa7cJpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lT\nXDGEKvYPmDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+\nwRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4VYcgoc/l\nbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/AUaG9ih5yLHa5FcX\nxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMBAAGjYzBhMA4GA1UdDwEB/wQE\nAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRF66Kv9JLLgjEtUYunpyGd823IDzAf\nBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog68\n3+Lt8ONyc3pklL/3cmbYMuRCdWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqo\nR+pWxnmrEthngYTffwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+\nfT8r87cmNW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx\nH2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe+o0bJW1s\nj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g==\n-----END CERTIFICATE-----\n", + "DigiCert Global Root CA": "-----BEGIN CERTIFICATE-----\nMIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBhMQswCQYD\nVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu\nY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBa\nFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx\nGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBS\nb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKP\nC3eQyaKl7hLOllsBCSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscF\ns3YnFo97nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt\n43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7PT19sdl6g\nSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4gdW7jVg/tRvoSSii\ncNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAYYwDwYD\nVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbRTLtm8KPiGxvDl7I90VUwHwYDVR0jBBgw\nFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1E\nnE9SsPTfrgT1eXkIoyQY/EsrhMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDi\nqw8cvpOp/2PV5Adg06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBA\nI+0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls\nYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQkCAUw7C29\nC79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=\n-----END CERTIFICATE-----\n", + "DigiCert High Assurance EV Root CA": "-----BEGIN CERTIFICATE-----\nMIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYD\nVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu\nY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2\nMTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERp\nZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNl\ncnQgSGlnaCBBc3N1cmFuY2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC\nAQoCggEBAMbM5XPm+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlB\nWTrT3JTWPNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM\nxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeB\nQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5\nOYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsgEsxBu24LUTi4S8sCAwEAAaNj\nMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9H\nAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3\nDQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1\nntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VH\nMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2\nYzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCevEsXCS+0\nyx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K\n-----END CERTIFICATE-----\n", + "Certplus Class 2 Primary CA": "-----BEGIN CERTIFICATE-----\nMIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAwPTELMAkG\nA1UEBhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFzcyAyIFByaW1hcnkg\nQ0EwHhcNOTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9MQswCQYDVQQGEwJGUjERMA8G\nA1UEChMIQ2VydHBsdXMxGzAZBgNVBAMTEkNsYXNzIDIgUHJpbWFyeSBDQTCCASIwDQYJKoZI\nhvcNAQEBBQADggEPADCCAQoCggEBANxQltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxv\nc0NXYKwzCkTsA18cgCSR5aiRVhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLR\nYE2+L0ER4/YXJQyLkcAbmXuZVg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v\n0lPubNCdEgETjdyAYveVqUSISnFOYFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yas\nH7WLO7dDWWuwJKZtkIvEcupdM5i3y95ee++U8Rs+yskhwcWYAqqi9lt3m/V+llU0HGdpwPFC\n40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRMECDAGAQH/AgEKMAsGA1UdDwQEAwIBBjAdBgNV\nHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJYIZIAYb4QgEBBAQDAgEGMDcGA1UdHwQw\nMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMuY29tL0NSTC9jbGFzczIuY3JsMA0GCSqG\nSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/AN9WM2K191EBkOvDP9GIROkkXe/nFL0gt5o8AP5t\nn9uQ3Nf0YtaLcF3n5QRIqWh8yfFC82x/xXp8HVGIutIKPidd3i1RTtMTZGnkLuPT55sJmabg\nlZvOGtd/vjzOUrMRFcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+7UCmnYR0ObncHoUW\n2ikbhiMAybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW//1IMwrh3KWB\nkJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7l7+ijrRU\n-----END CERTIFICATE-----\n", + "DST Root CA X3": "-----BEGIN CERTIFICATE-----\nMIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/MSQwIgYD\nVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMTDkRTVCBSb290IENB\nIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVowPzEkMCIGA1UEChMbRGlnaXRh\nbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQDEw5EU1QgUm9vdCBDQSBYMzCCASIwDQYJ\nKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdA\nwRgUi+DoM3ZJKuM/IUmTrE4Orz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwG\nMoOifooUMM0RoOEqOLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4X\nLh7dIN9bxiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw\n7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaDaeQQmxkq\ntilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw\nHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqGSIb3DQEBBQUAA4IBAQCjGiyb\nFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69ikugdB/OEIKcdBodfpga3csTS7MgROSR\n6cz8faXbauX+5v3gTt23ADq1cEmv8uXrAvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaL\nbumR9YbK+rlmM6pZW87ipxZzR8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir\n/md2cXjbDaJWFBM5JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06Xyx\nV3bqxbYoOb8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ\n-----END CERTIFICATE-----\n", + "DST ACES CA X6": "-----BEGIN CERTIFICATE-----\nMIIECTCCAvGgAwIBAgIQDV6ZCtadt3js2AdWO4YV2TANBgkqhkiG9w0BAQUFADBbMQswCQYD\nVQQGEwJVUzEgMB4GA1UEChMXRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QxETAPBgNVBAsTCERT\nVCBBQ0VTMRcwFQYDVQQDEw5EU1QgQUNFUyBDQSBYNjAeFw0wMzExMjAyMTE5NThaFw0xNzEx\nMjAyMTE5NThaMFsxCzAJBgNVBAYTAlVTMSAwHgYDVQQKExdEaWdpdGFsIFNpZ25hdHVyZSBU\ncnVzdDERMA8GA1UECxMIRFNUIEFDRVMxFzAVBgNVBAMTDkRTVCBBQ0VTIENBIFg2MIIBIjAN\nBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuT31LMmU3HWKlV1j6IR3dma5WZFcRt2SPp/5\nDgO0PWGSvSMmtWPuktKe1jzIDZBfZIGxqAgNTNj50wUoUrQBJcWVHAx+PhCEdc/BGZFjz+io\nkYi5Q1K7gLFViYsx+tC3dr5BPTCapCIlF3PoHuLTrCq9Wzgh1SpL11V94zpVvddtawJXa+ZH\nfAjIgrrep4c9oW24MFbCswKBXy314powGCi4ZtPLAZZv6opFVdbgnf9nKxcCpk4aahELfrd7\n55jWjHZvwTvbUJN+5dCOHze4vbrGn2zpfDPyMjwmR/onJALJfh1biEITajV8fTXpLmaRcpPV\nMibEdPVTo7NdmvYJywIDAQABo4HIMIHFMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD\nAgHGMB8GA1UdEQQYMBaBFHBraS1vcHNAdHJ1c3Rkc3QuY29tMGIGA1UdIARbMFkwVwYKYIZI\nAWUDAgEBATBJMEcGCCsGAQUFBwIBFjtodHRwOi8vd3d3LnRydXN0ZHN0LmNvbS9jZXJ0aWZp\nY2F0ZXMvcG9saWN5L0FDRVMtaW5kZXguaHRtbDAdBgNVHQ4EFgQUCXIGThhDD+XWzMNqizF7\neI+og7gwDQYJKoZIhvcNAQEFBQADggEBAKPYjtay284F5zLNAdMEA+V25FYrnJmQ6AgwbN99\nPe7lv7UkQIRJ4dEorsTCOlMwiPH1d25Ryvr/ma8kXxug/fKshMrfqfBfBC6tFr8hlxCBPeP/\nh40y3JTlR4peahPJlJU90u7INJXQgNStMgiAVDzgvVJT11J8smk/f3rPanTK+gQqnExaBqXp\nIK1FZg9p8d2/6eMyi/rgwYZNcjwu2JN4Cir42NInPRmJX1p7ijvMDNpRrscL9yuwNwXsvFcj\n4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf29w4LTJxoeHtxMcfrHuBnQfO3\noKfN5XozNmr6mis=\n-----END CERTIFICATE-----\n", + "TURKTRUST Certificate Services Provider Root 1": "-----BEGIN CERTIFICATE-----\nMIID+zCCAuOgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBtzE/MD0GA1UEAww2VMOcUktUUlVT\nVCBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQG\nDAJUUjEPMA0GA1UEBwwGQU5LQVJBMVYwVAYDVQQKDE0oYykgMjAwNSBUw5xSS1RSVVNUIEJp\nbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWe\nLjAeFw0wNTA1MTMxMDI3MTdaFw0xNTAzMjIxMDI3MTdaMIG3MT8wPQYDVQQDDDZUw5xSS1RS\nVVNUIEVsZWt0cm9uaWsgU2VydGlmaWthIEhpem1ldCBTYcSfbGF5xLFjxLFzxLExCzAJBgNV\nBAYMAlRSMQ8wDQYDVQQHDAZBTktBUkExVjBUBgNVBAoMTShjKSAyMDA1IFTDnFJLVFJVU1Qg\nQmlsZ2kgxLBsZXRpxZ9pbSB2ZSBCaWxpxZ9pbSBHw7x2ZW5sacSfaSBIaXptZXRsZXJpIEEu\nxZ4uMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAylIF1mMD2Bxf3dJ7XfIMYGFb\nazt0K3gNfUW9InTojAPBxhEqPZW8qZSwu5GXyGl8hMW0kWxsE2qkVa2kheiVfrMArwDCBRj1\ncJ02i67L5BuBf5OI+2pVu32Fks66WJ/bMsW9Xe8iSi9BB35JYbOG7E6mQW6EvAPs9TscyB/C\n7qju6hJKjRTP8wrgUDn5CDX4EVmt5yLqS8oUBt5CurKZ8y1UiBAG6uEaPj1nH/vO+3yC6BFd\nSsG5FOpU2WabfIl9BJpiyelSPJ6c79L1JuTm5Rh8i27fbMx4W09ysstcP4wFjdFMjK2Sx+F4\nf2VsSQZQLJ4ywtdKxnWKWU51b0dewQIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3\nDQEBBQUAA4IBAQAV9VX/N5aAWSGk/KEVTCD21F/aAyT8z5Aa9CEKmu46sWrv7/hg0Uw2ZkUd\n82YCdAR7kjCo3gp2D++Vbr3JN+YaDayJSFvMgzbC9UZcWYJWtNX+I7TYVBxEq8Sn5RTOPEFh\nfEPmzcSBCYsk+1Ql1haolgxnB2+zUEfjHCQo3SqYpGH+2+oSN7wBGjSFvW5P55FyB0SFHljK\nVETd96y5y4khctuPwGkplyqjrhgjlxxBKot8KsF8kOipKMDTkcatKIdAaLX/7KfS0zgYnNN9\naV3wxqUeJBujR/xpB2jn5Jq07Q+hh4cCzofSSE7hvP/L8XKSRGQDJereW26fyfJOrN3H\n-----END CERTIFICATE-----\n", + "TURKTRUST Certificate Services Provider Root 2": "-----BEGIN CERTIFICATE-----\nMIIEPDCCAySgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvjE/MD0GA1UEAww2VMOcUktUUlVT\nVCBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQG\nEwJUUjEPMA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSwbGV0\nacWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgS2Fz\nxLFtIDIwMDUwHhcNMDUxMTA3MTAwNzU3WhcNMTUwOTE2MTAwNzU3WjCBvjE/MD0GA1UEAww2\nVMOcUktUUlVTVCBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8Sx\nMQswCQYDVQQGEwJUUjEPMA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJp\nbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWe\nLiAoYykgS2FzxLFtIDIwMDUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCpNn7D\nkUNMwxmYCMjHWHtPFoylzkkBH3MOrHUTpvqeLCDe2JAOCtFp0if7qnefJ1Il4std2NiDUBd9\nirWCPwSOtNXwSadktx4uXyCcUHVPr+G1QRT0mJKIx+XlZEdhR3n9wFHxwZnn3M5q+6+1ATDc\nRhzviuyV79z/rxAc653YsKpqhRgNF8k+v/Gb0AmJQv2gQrSdiVFVKc8bcLyEVK3BEx+Y9C52\nYItdP5qtygy/p1Zbj3e41Z55SZI/4PGXJHpsmxcPbe9TmJEr5A++WXkHeLuXlfSfadRYhwqp\n48y2WBmfJiGxxFmNskF1wK1pzpwACPI2/z7woQ8arBT9pmAPAgMBAAGjQzBBMB0GA1UdDgQW\nBBTZN7NOBf3Zz58SFq62iS/rJTqIHDAPBgNVHQ8BAf8EBQMDBwYAMA8GA1UdEwEB/wQFMAMB\nAf8wDQYJKoZIhvcNAQEFBQADggEBAHJglrfJ3NgpXiOFX7KzLXb7iNcX/nttRbj2hWyfIvwq\nECLsqrkw9qtY1jkQMZkpAL2JZkH7dN6RwRgLn7Vhy506vvWolKMiVW4XSf/SKfE4Jl3vpao6\n+XF75tpYHdN0wgH6PmlYX63LaL4ULptswLbcoCb6dxriJNoaN+BnrdFzgw2lGh1uEpJ+hGIA\nF728JRhX8tepb1mIvDS3LoV4nZbcFMMsilKbloxSZj2GFotHuFEJjOp9zYhys2AzsfAKRO8P\n9Qk3iCQOLGsgOqL6EfJANZxEaGM7rDNvY7wsu/LSy3Z9fYjYHcgFHW68lKlmjHdxx/qR+i9R\nnuk5UrbnBEI=\n-----END CERTIFICATE-----\n", + "SwissSign Gold CA - G2": "-----BEGIN CERTIFICATE-----\nMIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkNI\nMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2lnbiBHb2xkIENBIC0g\nRzIwHhcNMDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBFMQswCQYDVQQGEwJDSDEVMBMG\nA1UEChMMU3dpc3NTaWduIEFHMR8wHQYDVQQDExZTd2lzc1NpZ24gR29sZCBDQSAtIEcyMIIC\nIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJC\nEyq8ZVeCQD5XJM1QiyUqt2/876LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcf\nDmJlD909Vopz2q5+bbqBHH5CjCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpi\nkJKVyh+c6bM8K8vzARO/Ws/BtQpgvd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqE\nemA8atufK+ze3gE/bk3lUIbLtK/tREDFylqM2tIrfKjuvqblCqoOpd8FUrdVxyJdMmqXl2MT\n28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvRAiTysybUa9oEVeXBCsdtMDeQKuSeFDNeFhdV\nxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuendjIj3o02yMszYF9rNt85mndT9Xv+9lz4p\nded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69yFGkOpeUDDniOJihC8AcLYiAQZzlG+qkD\nzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPiaG59je883WX0XaxR7ySArqpWl2/5rX3aYT+Ydzyl\nkbYcjCbaZaIJbcHiVOO5ykxMgI93e2CaHt+28kgeDrpOVG2Y4OGiGqJ3UM/EY5LsRxmd6+Zr\nzsECAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E\nFgQUWyV7lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64OfPAeGZe6Drn\n8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDovL3JlcG9z\naXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe645R88a7A3hfm5djV\n9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczOUYrHUDFu4Up+GC9pWbY9ZIEr\n44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5O1M/wySTVltpkuzFwbs4AOPsF6m43Md8\nAYOfMke6UiI0HTJ6CVanfCU2qT1L2sCCbwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0V\nqbe/vd6mGu6uLftIdxf+u+yvGPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9Qkvfsywe\nxcZdylU6oJxpmo/a77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/Eb\nMFYOkrCChdiDyyJkvC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid3\n92qgQmwLOM7XdVAyksLfKzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEppLd6leNcG\n2mqeSz53OiATIgHQv2ieY2BrNU0LbbqhPcCT4H8js1WtciVORvnSFu+wZMEBnunKoGqYDs/Y\nYPIvSbjkQuE4NRb0yG5P94FW6LqjviOvrv1vA+ACOzB2+httQc8Bsem4yWb02ybzOqR08kkk\nW8mw0FfB+j564ZfJ\n-----END CERTIFICATE-----\n", + "SwissSign Silver CA - G2": "-----BEGIN CERTIFICATE-----\nMIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCQ0gx\nFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAt\nIEcyMB4XDTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0NlowRzELMAkGA1UEBhMCQ0gxFTAT\nBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcy\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dO\ncbpLj6VzHVxumK4DV644N0MvFz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGi\nTSf5YXu6t+WiE7brYT7QbNHm+/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi\n0R86TieFnbAVlDLaYQ1HTWBCrpJH6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH\n6ATK72oxh9TAtvmUcXtnZLi2kUpCe2UuMGoM9ZDulebyzYLs2aFK7PayS+VFheZteJMELpyC\nbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5hqAaEuSh6XzjZG6k4sIN/c8HDO0gqgg8hm7jM\nqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5FZGkECwJMoBgs5PAKrYYC51+jUnyEEp/\n+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRHHTBsROopN4WSaGa8gzj+ezku01DwH/te\nYLappvonQfGbGHLy9YR0SslnxFSuSGTfjNFusB3hB48IHpmccelM2KX3RxIfdNFRnobzwqIj\nQAtz20um53MGjMGg6cFZrEb65i/4z3GcRm25xBWNOHkDRUjvxF3XCO6HOSKGsg0PWEP3calI\nLv3q1h8CAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV\nHQ4EFgQUF6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRBtjpbO8tFnb0c\nwpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0cDovL3Jl\ncG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBAHPGgeAn0i0P4JUw\n4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShpWJHckRE1qTodvBqlYJ7YH39F\nkWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcS\nH9/L3XWgwF15kIwb4FDm3jH+mHtwX6WQ2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkD\nlm4fS/Bx/uNncqCxv1yL5PqZIseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakM\nDHiqYMZWjwFaDGi8aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHk\nFlt4dR2Xem1ZqSqPe97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQR\ndAtq/gsD/KNVV4n+SsuuWxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/OMpXEA29\nMC/HpeZBoNquBYeaoKRlbEwJDIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+hAhm0sQ2fac+EPyI\n4NSA5QC9qvNOBqN6avlicuMJT+ubDgEj8Z+7fNzcbBGXJbLytGMU0gYqZ4yD9c7qB9iaah7s\n5Aq7KkzrCWA5zspi2C5u\n-----END CERTIFICATE-----\n", + "GeoTrust Primary Certification Authority": "-----BEGIN CERTIFICATE-----\nMIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBYMQswCQYD\nVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMoR2VvVHJ1c3QgUHJp\nbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMjcwMDAwMDBaFw0zNjA3MTYy\nMzU5NTlaMFgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTEwLwYDVQQD\nEyhHZW9UcnVzdCBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG\n9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92\n/ZV+zmEwu3qDXwK9AWbK7hWNb6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa\n9OBesYjAZIVcFU2Ix7e64HXprQU9nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE0\n7e9GceBrAqg1cmuXm2bgyxx5X9gaBGgeRwLmnWDiNpcB3841kt++Z8dtd1k7j53WkBWUvEI0\nEME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGttm/81w7a4DSwDRp35+MImO9Y+pyEtzavwt+s\n0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV\nHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJKoZIhvcNAQEFBQADggEBAFpwfyzdtzRP\n9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ16CePbJC/kRYkRj5KTs4rFtULUh38H2eiAkUxT87z\n+gOneZ1TatnaYzr4gNfTmeGl4b7UVXGYNTq+k+qurUKykG/g/CFNNWMziUnWm07Kx+dOCQD3\n2sfvmWKZd7aVIl6KoKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHaFloxt/m0cYASSJly\nc1pZU8FjUjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG1riR/aYNKxoU\nAT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk=\n-----END CERTIFICATE-----\n", + "thawte Primary Root CA": "-----BEGIN CERTIFICATE-----\nMIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCBqTELMAkG\nA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlv\nbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0g\nRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3Qg\nQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTAT\nBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBE\naXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6\nZWQgdXNlIG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqG\nSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsoPD7gFnUnMekz52hWXMJEEUMDSxuaPFsW0hoSVk3\n/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ1CRfBsDMRJSUjQJib+ta3RGNKJpchJAQeg29\ndGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGcq/gcfomk6KHYcWUNo1F77rzSImANuVud\n37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6Sk/KaAcdHJ1KxtUvkcx8cXIcxcBn6zL9\nyZJclNqFwJu/U30rCfSMnZEfl2pSy94JNqR32HuHUETVPm4pafs5SSYeCaWAe0At6+gnhcn+\nYf1+5nyXHdWdAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G\nA1UdDgQWBBR7W0XPr87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAeRHAS7OR\ntvzw6WfUDW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeEuzLlQRHAd9mz\nYJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAXxPcW6cTY\ncvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2/qxAeeWsEG89jxt5\ndovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/LHbTY5xZ3Y+m4Q6gLkH3LpVH\nz7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7jVaMaA==\n-----END CERTIFICATE-----\n", + "VeriSign Class 3 Public Primary Certification Authority - G5": "-----BEGIN CERTIFICATE-----\nMIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCByjELMAkG\nA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBU\ncnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBh\ndXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQ\ncmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcN\nMzYwNzE2MjM1OTU5WjCByjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMu\nMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBW\nZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp\nU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0g\nRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1nmAMqudLO07cfLw8\nRRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbext0uz/o9+B1fs70PbZmIVYc9g\nDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIzSdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ0\n23tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQGBO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9\nr911kTMZHRxAy3QkGSGT2RT+rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MU\nCH7lP59zuDMKz10/NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNV\nHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH\nBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVyaXNpZ24u\nY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKvMzEzMA0GCSqGSIb3\nDQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzEp6B4Eq1iDkVwZMXnl2YtmAl+\nX6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU\n7qKEKQsTb47bDN0lAtukixlE0kF6BWlKWE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMt\nEMze/aiCKm0oHw0LxOXnGiYZ4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7\nMzVIcbidJ4vEZV8NhnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq\n-----END CERTIFICATE-----\n", + "SecureTrust CA": "-----BEGIN CERTIFICATE-----\nMIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBIMQswCQYD\nVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xFzAVBgNVBAMTDlNl\nY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIzMTE5NDA1NVowSDELMAkGA1UE\nBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENvcnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1\ncmVUcnVzdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7C\nT8rU4niVWJxB4Q2ZQCQXOZEzZum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29\nvo6pQT64lO0pGtSO0gMdA+9tDWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZ\nbf2IzIaowW8xQmxSPmjL8xk037uHGFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj\n7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b01k/unK8RCSc43Oz969XL0Imnal0ugBS8kvNU3xH\nCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmHursCAwEAAaOBnTCBmjATBgkrBgEEAYI3FAIE\nBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUQjK2FvoE\n/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL2NybC5zZWN1cmV0cnVz\ndC5jb20vU1RDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBADDt\nT0rhWDpSclu1pqNlGKa7UTt36Z3q059c4EVlew3KW+JwULKUBRSuSceNQQcSc5R+DCMh/bwQ\nf2AQWnL1mA6s7Ll/3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHfmbx8IVQr5Fiiu1cp\nrp6poxkmD5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS\nCPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR3ItHuuG5\n1WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE=\n-----END CERTIFICATE-----\n", + "Secure Global CA": "-----BEGIN CERTIFICATE-----\nMIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBKMQswCQYD\nVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNl\nY3VyZSBHbG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkxMjMxMTk1MjA2WjBKMQswCQYD\nVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNl\nY3VyZSBHbG9iYWwgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxV\naQZx5RNoJLNP2MwhR/jxYDiJiQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6Mpjh\nHZevj8fcyTiW89sa/FHtaMbQbqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ\n/kG5VacJjnIFHovdRIWCQtBJwB1g8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnI\nHmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYVHDGA76oYa8J719rO+TMg1fW9ajMtgQT7sFzUnKPi\nXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi0XPnj3pDAgMBAAGjgZ0wgZowEwYJKwYBBAGC\nNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFK9E\nBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCswKaAnoCWGI2h0dHA6Ly9jcmwuc2VjdXJl\ndHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsGAQQBgjcVAQQDAgEAMA0GCSqGSIb3DQEBBQUAA4IB\nAQBjGghAfaReUw132HquHw0LURYD7xh8yOOvaliTFGCRsoTciE6+OYo68+aCiV0BN7OrJKQV\nDpI1WkpEXk5X+nXOH0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cnCDpOGR86p1hcF895\nP4vkp9MmI50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/53CYNv6ZHdAbY\niNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xcf8LDmBxr\nThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW\n-----END CERTIFICATE-----\n", + "COMODO Certification Authority": "-----BEGIN CERTIFICATE-----\nMIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCBgTELMAkG\nA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9y\nZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNVBAMTHkNPTU9ETyBDZXJ0aWZp\nY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAwMDBaFw0yOTEyMzEyMzU5NTlaMIGBMQsw\nCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxm\nb3JkMRowGAYDVQQKExFDT01PRE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRp\nZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECL\ni3LjkRv3UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI\n2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8Q5sVW7eu\nNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp+2dtQem8Ob0y2WIC\n8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+DT+nHbrTUcELpNqsOO9VUCQF\nZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5OnKVIrLsm9wIDAQABo4GOMIGLMB0GA1Ud\nDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW/zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw\nAwEB/zBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9D\nZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5\nt3iuHXIYSdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv\nIC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/RxdMosIG\nlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4zJVSk/BwJVmcIGfE\n7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5ddBA6+C4OmF4O5MBKgxTMVBbkN\n+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IBZQ==\n-----END CERTIFICATE-----\n", + "Network Solutions Certificate Authority": "-----BEGIN CERTIFICATE-----\nMIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBiMQswCQYD\nVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydO\nZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDYxMjAxMDAwMDAw\nWhcNMjkxMjMxMjM1OTU5WjBiMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1\ndGlvbnMgTC5MLkMuMTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBB\ndXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xG\nzuAnlt7e+foS0zwzc7MEL7xxjOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQ\nNJIg6nPPOCwGJgl6cvf6UDL4wpPTaaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rl\nmGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXTcrA/vGp97Eh/jcOrqnErU2lBUzS1sLnFBgrEsEX1\nQV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc/Qzpf14Dl847ABSHJ3A4qY5usyd2mFHgBeMh\nqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMBAAGjgZcwgZQwHQYDVR0OBBYEFCEwyfsA\n106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MFIGA1Ud\nHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwubmV0c29sc3NsLmNvbS9OZXR3b3JrU29sdXRpb25z\nQ2VydGlmaWNhdGVBdXRob3JpdHkuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQC7rkvnt1frf6ot\nt3NHhWrB5KUd5Oc86fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q4LqILPxFzBiwmZVR\nDuwduIj/h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/GGUsyfJj4akH\n/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3HtvwKeI8lN3\ns2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHNpGxlaKFJdlxDydi8\nNmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey\n-----END CERTIFICATE-----\n", + "WellsSecure Public Root Certificate Authority": "-----BEGIN CERTIFICATE-----\nMIIEvTCCA6WgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBhTELMAkGA1UEBhMCVVMxIDAeBgNV\nBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5r\nIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRo\nb3JpdHkwHhcNMDcxMjEzMTcwNzU0WhcNMjIxMjE0MDAwNzU0WjCBhTELMAkGA1UEBhMCVVMx\nIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJn\nbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0\nZSBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDub7S9eeKPCCGe\nOARBJe+rWxxTkqxtnt3CxC5FlAM1iGd0V+PfjLindo8796jE2yljDpFoNoqXjopxaAkH5OjU\nDk/41itMpBb570OYj7OeUt9tkTmPOL13i0Nj67eT/DBMHAGTthP796EfvyXhdDcsHqRePGj4\nS78NuR4uNuip5Kf4D8uCdXw1LSLWwr8L87T8bJVhHlfXBIEyg1J55oNjz7fLY4sR4r1e6/aN\n7ZVyKLSsEmLpSjPmgzKuBXWVvYSV2ypcm44uDLiBK0HmOFafSZtsdvqKXfcBeYF8wYNABf5x\n/Qw/zE5gCQ5lRxAvAcAFP4/4s0HvWkJ+We/SlwxlAgMBAAGjggE0MIIBMDAPBgNVHRMBAf8E\nBTADAQH/MDkGA1UdHwQyMDAwLqAsoCqGKGh0dHA6Ly9jcmwucGtpLndlbGxzZmFyZ28uY29t\nL3dzcHJjYS5jcmwwDgYDVR0PAQH/BAQDAgHGMB0GA1UdDgQWBBQmlRkQ2eihl5H/3BnZtQQ+\n0nMKajCBsgYDVR0jBIGqMIGngBQmlRkQ2eihl5H/3BnZtQQ+0nMKaqGBi6SBiDCBhTELMAkG\nA1UEBhMCVVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNX\nZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBD\nZXJ0aWZpY2F0ZSBBdXRob3JpdHmCAQEwDQYJKoZIhvcNAQEFBQADggEBALkVsUSRzCPIK013\n4/iaeycNzXK7mQDKfGYZUMbVmO2rvwNa5U3lHshPcZeG1eMd/ZDJPHV3V3p9+N701NX3leZ0\nbh08rnyd2wIDBSxxSyU+B+NemvVmFymIGjifz6pBA4SXa5M4esowRBskRDPQ5NHcKDj0E0M1\nNSljqHyita04pO2t/caaH/+Xc/77szWnk4bGdpEA5qxRFsQnMlzbc9qlk1eOPm01JghZ1edE\n13YgY+esE2fDbbFwRnzVlhE9iW9dqKHrjQrawx0zbKPqZxmamX9LPYNRKh3KL4YMon4QLSvU\nFpULB6ouFJJJtylv2G0xffX8oRAHh84vWdw+WNs=\n-----END CERTIFICATE-----\n", + "COMODO ECC Certification Authority": "-----BEGIN CERTIFICATE-----\nMIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTELMAkGA1UE\nBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEa\nMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlm\naWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTEL\nMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2Fs\nZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0Mg\nQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmC\nFYX7deSRFtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J\ncfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQWBBR1cacZ\nSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggq\nhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDmfQjGGoe9GKhzvSbKYAydzpmf\nz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdvGDeAU/7dIOA1mjbRxwG55tzd8/8dLDoW\nV9mSOdY=\n-----END CERTIFICATE-----\n", + "IGC/A": "-----BEGIN CERTIFICATE-----\nMIIEAjCCAuqgAwIBAgIFORFFEJQwDQYJKoZIhvcNAQEFBQAwgYUxCzAJBgNVBAYTAkZSMQ8w\nDQYDVQQIEwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYD\nVQQLEwVEQ1NTSTEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5w\nbS5nb3V2LmZyMB4XDTAyMTIxMzE0MjkyM1oXDTIwMTAxNzE0MjkyMlowgYUxCzAJBgNVBAYT\nAkZSMQ8wDQYDVQQIEwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0RO\nMQ4wDAYDVQQLEwVEQ1NTSTEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FA\nc2dkbi5wbS5nb3V2LmZyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsh/R0GLF\nMzvABIaIs9z4iPf930Pfeo2aSVz2TqrMHLmh6yeJ8kbpO0px1R2OLc/mratjUMdUC24SyZA2\nxtgv2pGqaMVy/hcKshd+ebUyiHDKcMCWSo7kVc0dJ5S/znIq7Fz5cyD+vfcuiWe4u0dzEvfR\nNWk68gq5rv9GQkaiv6GFGvm/5P9JhfejcIYyHF2fYPepraX/z9E0+X1bF8bc1g4oa8Ld8fUz\naJ1O/Id8NhLWo4DoQw1VYZTqZDdH6nfK0LJYBcNdfrGoRpAxVs5wKpayMLh35nnAvSk7/ZR3\nTL0gzUEl4C7HG7vupARB0l2tEmqKm0f7yd1GQOGdPDPQtQIDAQABo3cwdTAPBgNVHRMBAf8E\nBTADAQH/MAsGA1UdDwQEAwIBRjAVBgNVHSAEDjAMMAoGCCqBegF5AQEBMB0GA1UdDgQWBBSj\nBS8YYFDCiQrdKyFP/45OqDAxNjAfBgNVHSMEGDAWgBSjBS8YYFDCiQrdKyFP/45OqDAxNjAN\nBgkqhkiG9w0BAQUFAAOCAQEABdwm2Pp3FURo/C9mOnTgXeQp/wYHE4RKq89toB9RlPhJy3Q2\nFLwV3duJL92PoF189RLrn544pEfMs5bZvpwlqwN+Mw+VgQ39FuCIvjfwbF3QMZsyK10XZZOY\nYLxuj7GoPB7ZHPOpJkL5ZB3C55L29B5aqhlSXa/oovdgoPaN8In1buAKBQGVyYsgCrpa/Jos\nPL3Dt8ldeCUFP1YUmwza+zpI/pdpXsoQhvdOlgQITeywvl3cO45Pwf2aNjSaTFR+FwNIlQgR\nHAdvhQh+XU3Endv7rs6y0bO4g2wdsrN58dhwmX7wEwLOXt1R0982gaEbeC9xs/FZTEYYKKuF\n0mBWWg==\n-----END CERTIFICATE-----\n", + "Security Communication EV RootCA1": "-----BEGIN CERTIFICATE-----\nMIIDfTCCAmWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJKUDElMCMGA1UE\nChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEqMCgGA1UECxMhU2VjdXJpdHkgQ29t\nbXVuaWNhdGlvbiBFViBSb290Q0ExMB4XDTA3MDYwNjAyMTIzMloXDTM3MDYwNjAyMTIzMlow\nYDELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4x\nKjAoBgNVBAsTIVNlY3VyaXR5IENvbW11bmljYXRpb24gRVYgUm9vdENBMTCCASIwDQYJKoZI\nhvcNAQEBBQADggEPADCCAQoCggEBALx/7FebJOD+nLpCeamIivqA4PUHKUPqjgo0No0c+qe1\nOXj/l3X3L+SqawSERMqm4miO/VVQYg+kcQ7OBzgtQoVQrTyWb4vVog7P3kmJPdZkLjjlHmy1\nV4qe70gOzXppFodEtZDkBp2uoQSXWHnvIEqCa4wiv+wfD+mEce3xDuS4GBPMVjZd0ZoeUWs5\nbmB2iDQL87PRsJ3KYeJkHcFGB7hj3R4zZbOOCVVSPbW9/wfrrWFVGCypaZhKqkDFMxRldAD5\nkd6vA0jFQFTcD4SQaCDFkpbcLuUCRarAX1T4bepJz11sS6/vmsJWXMY1VkJqMF/Cq/biPT+z\nyRGPMUzXn0kCAwEAAaNCMEAwHQYDVR0OBBYEFDVK9U2vP9eCOKyrcWUXdYydVZPmMA4GA1Ud\nDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQCoh+ns+EBn\nXcPBZsdAS5f8hxOQWsTvoMpfi7ent/HWtWS3irO4G8za+6xmiEHO6Pzk2x6Ipu0nUBsCMCRG\nef4Eh3CXQHPRwMFXGZpppSeZq51ihPZRwSzJIxXYKLerJRO1RuGGAv8mjMSIkh1W/hln8lXk\ngKNrnKt34VFxDSDbEJrbvXZ5B3eZKK2aXtqxT0QsNY6llsf9g/BYxnnWmHyojf6GPgcWkuF7\n5x3sM3Z+Qi5KhfmRiWiEA4Glm5q+4zfFVKtWOxgtQaQM+ELbmaDgcm+7XeEWT1MKZPlO9L9O\nVL14bIjqv5wTJMJwaaJ/D8g8rQjJsJhAoyrniIPtd490\n-----END CERTIFICATE-----\n", + "OISTE WISeKey Global Root GA CA": "-----BEGIN CERTIFICATE-----\nMIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCBijELMAkG\nA1UEBhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHlyaWdodCAoYykgMjAw\nNTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUg\nV0lTZUtleSBHbG9iYWwgUm9vdCBHQSBDQTAeFw0wNTEyMTExNjAzNDRaFw0zNzEyMTExNjA5\nNTFaMIGKMQswCQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJp\nZ2h0IChjKSAyMDA1MSIwIAYDVQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYD\nVQQDEx9PSVNURSBXSVNlS2V5IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEF\nAAOCAQ8AMIIBCgKCAQEAy0+zAJs9Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxR\nVVuuk+g3/ytr6dTqvirdqFEr12bDYVxgAsj1znJ7O7jyTmUIms2kahnBAbtzptf2w93NvKSL\ntZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbDd50kc3vkDIzh2TbhmYsFmQvtRTEJysIA2/dy\noJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ/yxViJGg4E8HsChWjBgbl0SOid3gF27n\nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t94B3RLoGbw9ho972WG6xwsRYUC9tguSYB\nBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUswN+\nrja8sHnR3JQmthG+IbJphpQwEAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEB\nAEuh/wuHbrP5wUOxSPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vImMMkQyh2I+3QZH4VF\nvbBsUfk2ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4+vg1YFkCExh8\nvPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXahNVQA7bi\nhKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZiFj4A4xylNoEYokxS\ndsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ/L7fCg0=\n-----END CERTIFICATE-----\n", + "Microsec e-Szigno Root CA": "-----BEGIN CERTIFICATE-----\nMIIHqDCCBpCgAwIBAgIRAMy4579OKRr9otxmpRwsDxEwDQYJKoZIhvcNAQEFBQAwcjELMAkG\nA1UEBhMCSFUxETAPBgNVBAcTCEJ1ZGFwZXN0MRYwFAYDVQQKEw1NaWNyb3NlYyBMdGQuMRQw\nEgYDVQQLEwtlLVN6aWdubyBDQTEiMCAGA1UEAxMZTWljcm9zZWMgZS1Temlnbm8gUm9vdCBD\nQTAeFw0wNTA0MDYxMjI4NDRaFw0xNzA0MDYxMjI4NDRaMHIxCzAJBgNVBAYTAkhVMREwDwYD\nVQQHEwhCdWRhcGVzdDEWMBQGA1UEChMNTWljcm9zZWMgTHRkLjEUMBIGA1UECxMLZS1Temln\nbm8gQ0ExIjAgBgNVBAMTGU1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EwggEiMA0GCSqGSIb3\nDQEBAQUAA4IBDwAwggEKAoIBAQDtyADVgXvNOABHzNuEwSFpLHSQDCHZU4ftPkNEU6+r+ICb\nPHiN1I2uuO/TEdyB5s87lozWbxXGd36hL+BfkrYn13aaHUM86tnsL+4582pnS4uCzyL4ZVX+\nLMsvfUh6PXX5qqAnu3jCBspRwn5mS6/NoqdNAoI/gqyFxuEPkEeZlApxcpMqyabAvjxWTHOS\nJ/FrtfX9/DAFYJLG65Z+AZHCabEeHXtTRbjcQR/Ji3HWVBTji1R4P770Yjtb9aPs1ZJ04nQw\n7wHb4dSrmZsqa/i9phyGI0Jf7Enemotb9HI6QMVJPqW+jqpx62z69Rrkav17fVVA71hu5tnV\nvCSrwe+3AgMBAAGjggQ3MIIEMzBnBggrBgEFBQcBAQRbMFkwKAYIKwYBBQUHMAGGHGh0dHBz\nOi8vcmNhLmUtc3ppZ25vLmh1L29jc3AwLQYIKwYBBQUHMAKGIWh0dHA6Ly93d3cuZS1zemln\nbm8uaHUvUm9vdENBLmNydDAPBgNVHRMBAf8EBTADAQH/MIIBcwYDVR0gBIIBajCCAWYwggFi\nBgwrBgEEAYGoGAIBAQEwggFQMCgGCCsGAQUFBwIBFhxodHRwOi8vd3d3LmUtc3ppZ25vLmh1\nL1NaU1ovMIIBIgYIKwYBBQUHAgIwggEUHoIBEABBACAAdABhAG4A+gBzAO0AdAB2AOEAbgB5\nACAA6QByAHQAZQBsAG0AZQB6AOkAcwDpAGgAZQB6ACAA6QBzACAAZQBsAGYAbwBnAGEAZADh\nAHMA4QBoAG8AegAgAGEAIABTAHoAbwBsAGcA4QBsAHQAYQB0APMAIABTAHoAbwBsAGcA4QBs\nAHQAYQB0AOEAcwBpACAAUwB6AGEAYgDhAGwAeQB6AGEAdABhACAAcwB6AGUAcgBpAG4AdAAg\nAGsAZQBsAGwAIABlAGwAagDhAHIAbgBpADoAIABoAHQAdABwADoALwAvAHcAdwB3AC4AZQAt\nAHMAegBpAGcAbgBvAC4AaAB1AC8AUwBaAFMAWgAvMIHIBgNVHR8EgcAwgb0wgbqggbeggbSG\nIWh0dHA6Ly93d3cuZS1zemlnbm8uaHUvUm9vdENBLmNybIaBjmxkYXA6Ly9sZGFwLmUtc3pp\nZ25vLmh1L0NOPU1pY3Jvc2VjJTIwZS1Temlnbm8lMjBSb290JTIwQ0EsT1U9ZS1Temlnbm8l\nMjBDQSxPPU1pY3Jvc2VjJTIwTHRkLixMPUJ1ZGFwZXN0LEM9SFU/Y2VydGlmaWNhdGVSZXZv\nY2F0aW9uTGlzdDtiaW5hcnkwDgYDVR0PAQH/BAQDAgEGMIGWBgNVHREEgY4wgYuBEGluZm9A\nZS1zemlnbm8uaHWkdzB1MSMwIQYDVQQDDBpNaWNyb3NlYyBlLVN6aWduw7MgUm9vdCBDQTEW\nMBQGA1UECwwNZS1TemlnbsOzIEhTWjEWMBQGA1UEChMNTWljcm9zZWMgS2Z0LjERMA8GA1UE\nBxMIQnVkYXBlc3QxCzAJBgNVBAYTAkhVMIGsBgNVHSMEgaQwgaGAFMegSXUWYYTbMUuE0vE3\nQJDvTtz3oXakdDByMQswCQYDVQQGEwJIVTERMA8GA1UEBxMIQnVkYXBlc3QxFjAUBgNVBAoT\nDU1pY3Jvc2VjIEx0ZC4xFDASBgNVBAsTC2UtU3ppZ25vIENBMSIwIAYDVQQDExlNaWNyb3Nl\nYyBlLVN6aWdubyBSb290IENBghEAzLjnv04pGv2i3GalHCwPETAdBgNVHQ4EFgQUx6BJdRZh\nhNsxS4TS8TdAkO9O3PcwDQYJKoZIhvcNAQEFBQADggEBANMTnGZjWS7KXHAM/IO8VbH0jgds\nZifOwTsgqRy7RlRw7lrMoHfqaEQn6/Ip3Xep1fvj1KcExJW4C+FEaGAHQzAxQmHl7tnlJNUb\n3+FKG6qfx1/4ehHqE5MAyopYse7tDk2016g2JnzgOsHVV4Lxdbb9iV/a86g4nzUGCM4ilb7N\n1fy+W955a9x6qWVmvrElWl/tftOsRm1M9DKHtCAE4Gx4sHfRhUZLphK3dehKyVZs15KrnfVJ\nONJPU+NVkBHbmJbGSfI+9J8b4PeI3CVimUTYc78/MPMMNz7UwiiAc7EBt51alhQBS6kRnSlq\nLtBdgcDPsiBDxwPgN05dCtxZICU=\n-----END CERTIFICATE-----\n", + "Certigna": "-----BEGIN CERTIFICATE-----\nMIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNVBAYTAkZS\nMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4XDTA3MDYyOTE1MTMw\nNVoXDTI3MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczER\nMA8GA1UEAwwIQ2VydGlnbmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ\n1tazNHUmgh7stL7qXOEm7RFHYeGifBZ4QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lI\nzw7sebYs5zRLcAglozyHGxnygQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxr\nyIRWijOp5yIVUxbwzBfsV1/pogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJb\nzg4ij02Q130yGLMLLGq/jj8UEYkgDncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2\nJsglrgVKtOdjLPOMFlN+XPsRGgjBRmKfIrjxwo1p3Po6WAbfAgMBAAGjgbwwgbkwDwYDVR0T\nAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQtCRZvgHyUtVF9lo53BEwZAYDVR0jBF0wW4AU\nGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlt\neW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzjAQ/JSP8wDgYDVR0PAQH/BAQDAgEGMBEG\nCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQUFAAOCAQEAhQMeknH2Qq/ho2Ge6/PAD/Kl\n1NqV5ta+aDY9fm4fTIrv0Q8hbV6lUmPOEvjvKtpv6zf+EwLHyzs+ImvaYS5/1HI93TDhHkxA\nGYwP15zRgzB7mFncfca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1kluPBS1xp81HlDQwY9q\ncEQCYsuuHWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY1gkIl2PlwS6w\nt0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/QwWyH8EZE0\nvkHve52Xdf+XlcCWWC/qu0bXu+TZLg==\n-----END CERTIFICATE-----\n", + "AC Raíz Certicámara S.A.": "-----BEGIN CERTIFICATE-----\nMIIGZjCCBE6gAwIBAgIPB35Sk3vgFeNX8GmMy+wMMA0GCSqGSIb3DQEBBQUAMHsxCzAJBgNV\nBAYTAkNPMUcwRQYDVQQKDD5Tb2NpZWRhZCBDYW1lcmFsIGRlIENlcnRpZmljYWNpw7NuIERp\nZ2l0YWwgLSBDZXJ0aWPDoW1hcmEgUy5BLjEjMCEGA1UEAwwaQUMgUmHDrXogQ2VydGljw6Ft\nYXJhIFMuQS4wHhcNMDYxMTI3MjA0NjI5WhcNMzAwNDAyMjE0MjAyWjB7MQswCQYDVQQGEwJD\nTzFHMEUGA1UECgw+U29jaWVkYWQgQ2FtZXJhbCBkZSBDZXJ0aWZpY2FjacOzbiBEaWdpdGFs\nIC0gQ2VydGljw6FtYXJhIFMuQS4xIzAhBgNVBAMMGkFDIFJhw616IENlcnRpY8OhbWFyYSBT\nLkEuMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAq2uJo1PMSCMI+8PPUZYILrgI\nem08kBeGqentLhM0R7LQcNzJPNCNyu5LF6vQhbCnIwTLqKL85XXbQMpiiY9QngE9JlsYhBzL\nfDe3fezTf3MZsGqy2IiKLUV0qPezuMDU2s0iiXRNWhU5cxh0T7XrmafBHoi0wpOQY5fzp6cS\nsgkiBzPZkc0OnB8OIMfuuzONj8LSWKdf/WU34ojC2I+GdV75LaeHM/J4Ny+LvB2GNzmxlPLY\nvEqcgxhaBvzz1NS6jBUJJfD5to0EfhcSM2tXSExP2yYe68yQ54v5aHxwD6Mq0Do43zeX4lve\ngGHTgNiRg0JaTASJaBE8rF9ogEHMYELODVoqDA+bMMCm8Ibbq0nXl21Ii/kDwFJnmxL3wvIu\nmGVC2daa49AZMQyth9VXAnow6IYm+48jilSH5L887uvDdUhfHjlvgWJsxS3EF1QZtzeNnDeR\nyPYL1epjb4OsOMLzP96a++EjYfDIJss2yKHzMI+ko6Kh3VOz3vCaMh+DkXkwwakfU5tTohVT\nP92dsxA7SH2JD/ztA/X7JWR1DhcZDY8AFmd5ekD8LVkH2ZD6mq093ICK5lw1omdMEWux+IBk\nAC1vImHFrEsm5VoQgpukg3s0956JkSCXjrdCx2bD0Omk1vUgjcTDlaxECp1bczwmPS9KvqfJ\npxAe+59QafMCAwEAAaOB5jCB4zAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAd\nBgNVHQ4EFgQU0QnQ6dfOeXRU+Tows/RtLAMDG2gwgaAGA1UdIASBmDCBlTCBkgYEVR0gADCB\niTArBggrBgEFBQcCARYfaHR0cDovL3d3dy5jZXJ0aWNhbWFyYS5jb20vZHBjLzBaBggrBgEF\nBQcCAjBOGkxMaW1pdGFjaW9uZXMgZGUgZ2FyYW507WFzIGRlIGVzdGUgY2VydGlmaWNhZG8g\nc2UgcHVlZGVuIGVuY29udHJhciBlbiBsYSBEUEMuMA0GCSqGSIb3DQEBBQUAA4ICAQBclLW4\nRZFNjmEfAygPU3zmpFmps4p6xbD/CHwso3EcIRNnoZUSQDWDg4902zNc8El2CoFS3UnUmjIz\n75uny3XlesuXEpBcunvFm9+7OSPI/5jOCk0iAUgHforA1SBClETvv3eiiWdIG0ADBaGJ7M9i\n4z0ldma/Jre7Ir5v/zlXdLp6yQGVwZVR6Kss+LGGIOk/yzVb0hfpKv6DExdA7ohiZVvVO2Dp\nezy4ydV/NgIlqmjCMRW3MGXrfx1IebHPOeJCgBbT9ZMj/EyXyVo3bHwi2ErN0o42gzmRkBDI\n8ck1fj+404HGIGQatlDCIaR43NAvO2STdPCWkPHv+wlaNECW8DYSwaN0jJN+Qd53i+yG2dIP\nPy3RzECiiWZIHiCznCNZc6lEc7wkeZBWN7PGKX6jD/EpOe9+XCgycDWs2rjIdWb8m0w5R44b\nb5tNAlQiM+9hup4phO9OSzNHdpdqy35f/RWmnkJDW2ZaiogN9xa5P1FlK2Zqi9E4UqLWRhH6\n/JocdJ6PlwsCT2TG9WjTSy3/pDceiz+/RL5hRqGEPQgnTIEgd4kI6mdAXmwIUV80WoyWaM3X\n94nCHNMyAK9Sy9NgWyo6R35rMDOhYil/SrnhLecUIw4OGEfhefwVVdCx/CVxY3UzHCMrr1zZ\n7Ud3YA47Dx7SwNxkBYn8eNZcLCZDqQ==\n-----END CERTIFICATE-----\n", + "TC TrustCenter Class 2 CA II": "-----BEGIN CERTIFICATE-----\nMIIEqjCCA5KgAwIBAgIOLmoAAQACH9dSISwRXDswDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UE\nBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNVBAsTGVRDIFRydXN0\nQ2VudGVyIENsYXNzIDIgQ0ExJTAjBgNVBAMTHFRDIFRydXN0Q2VudGVyIENsYXNzIDIgQ0Eg\nSUkwHhcNMDYwMTEyMTQzODQzWhcNMjUxMjMxMjI1OTU5WjB2MQswCQYDVQQGEwJERTEcMBoG\nA1UEChMTVEMgVHJ1c3RDZW50ZXIgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xh\nc3MgMiBDQTElMCMGA1UEAxMcVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQSBJSTCCASIwDQYJ\nKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKuAh5uO8MN8h9foJIIRszzdQ2Lu+MNF2ujhoF/R\nKrLqk2jftMjWQ+nEdVl//OEd+DFwIxuInie5e/060smp6RQvkL4DUsFJzfb95AhmC1eKokKg\nuNV/aVyQMrKXDcpK3EY+AlWJU+MaWss2xgdW94zPEfRMuzBwBJWl9jmM/XOBCH2JXjIeIqki\nRUuwZi4wzJ9l/fzLganx4Duvo4bRierERXlQXa7pIXSSTYtZgo+U4+lK8edJsBTj9WLL1XK9\nH7nSn6DNqPoByNkN39r8R52zyFTfSUrxIan+GE7uSNQZu+995OKdy1u2bv/jzVrndIIFuoAl\nOMvkaZ6vQaoahPUCAwEAAaOCATQwggEwMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD\nAgEGMB0GA1UdDgQWBBTjq1RMgKHbVkO3kUrL84J6E1wIqzCB7QYDVR0fBIHlMIHiMIHfoIHc\noIHZhjVodHRwOi8vd3d3LnRydXN0Y2VudGVyLmRlL2NybC92Mi90Y19jbGFzc18yX2NhX0lJ\nLmNybIaBn2xkYXA6Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBUcnVzdENlbnRlciUy\nMENsYXNzJTIwMiUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21iSCxPVT1yb290\nY2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdD9i\nYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEAjNfffu4bgBCzg/XbEeprS6iSGNn3Bzn1LL4GdXpo\nUxUc6krtXvwjshOg0wn/9vYua0Fxec3ibf2uWWuFHbhOIprtZjluS5TmVfwLG4t3wVMTZonZ\nKNaL80VKY7f9ewthXbhtvsPcW3nS7Yblok2+XnR8au0WOB9/WIFaGusyiC2y8zl3gK9etmF1\nKdsjTYjKUCjLhdLTEKJZbtOTVAB6okaVhgWcqRmY5TFyDADiZ9lA4CQze28suVyrZZ0srHbq\nNZn1l7kPJOzHdiEoZa5X6AeIdUpWoNIFOqTmjZKILPPy4cHGYdtBxceb9w4aUUXCYWvcZCcX\njFq32nQozZfkvQ==\n-----END CERTIFICATE-----\n", + "TC TrustCenter Class 3 CA II": "-----BEGIN CERTIFICATE-----\nMIIEqjCCA5KgAwIBAgIOSkcAAQAC5aBd1j8AUb8wDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UE\nBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNVBAsTGVRDIFRydXN0\nQ2VudGVyIENsYXNzIDMgQ0ExJTAjBgNVBAMTHFRDIFRydXN0Q2VudGVyIENsYXNzIDMgQ0Eg\nSUkwHhcNMDYwMTEyMTQ0MTU3WhcNMjUxMjMxMjI1OTU5WjB2MQswCQYDVQQGEwJERTEcMBoG\nA1UEChMTVEMgVHJ1c3RDZW50ZXIgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xh\nc3MgMyBDQTElMCMGA1UEAxMcVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQSBJSTCCASIwDQYJ\nKoZIhvcNAQEBBQADggEPADCCAQoCggEBALTgu1G7OVyLBMVMeRwjhjEQY0NVJz/GRcekPewJ\nDRoeIMJWHt4bNwcwIi9v8Qbxq63WyKthoy9DxLCyLfzDlml7forkzMA5EpBCYMnMNWju2l+Q\nVl/NHE1bWEnrDgFPZPosPIlY2C8u4rBo6SI7dYnWRBpl8huXJh0obazovVkdKyT21oQDZogk\nAHhg8fir/gKya/si+zXmFtGt9i4S5Po1auUZuV3bOx4a+9P/FRQI2AlqukWdFHlgfa9Aigdz\ns5OW03Q0jTo3Kd5c7PXuLjHCINy+8U9/I1LZW+Jk2ZyqBwi1Rb3R0DHBq1SfqdLDYmAD8bs5\nSpJKPQq5ncWg/jcCAwEAAaOCATQwggEwMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD\nAgEGMB0GA1UdDgQWBBTUovyfs8PYA9NXXAek0CSnwPIA1DCB7QYDVR0fBIHlMIHiMIHfoIHc\noIHZhjVodHRwOi8vd3d3LnRydXN0Y2VudGVyLmRlL2NybC92Mi90Y19jbGFzc18zX2NhX0lJ\nLmNybIaBn2xkYXA6Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBUcnVzdENlbnRlciUy\nMENsYXNzJTIwMyUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21iSCxPVT1yb290\nY2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdD9i\nYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEANmDkcPcGIEPZIxpC8vijsrlNirTzwppVMXzEO2ea\ntN9NDoqTSheLG43KieHPOh6sHfGcMrSOWXaiQYUlN6AT0PV8TtXqluJucsG7Kv5sbviRmEb8\nyRtXW+rIGjs/sFGYPAfaLFkB2otE6OF0/ado3VS6g0bsyEa1+K+XwDsJHI/OcpY9M1ZwvJbL\n2NV9IJqDnxrcOfHFcqMRA/07QlIp2+gB95tejNaNhk4Z+rwcvsUhpYeeeC422wlxo3I0+Gzj\nBgnyXlal092Y+tTmBvTwtiBjS+opvaqCZh77gaqnN60TGOaSw4HBM7uIHqHn4rS9MWwOUT1v\n+5ZWgOI2F9Hc5A==\n-----END CERTIFICATE-----\n", + "TC TrustCenter Universal CA I": "-----BEGIN CERTIFICATE-----\nMIID3TCCAsWgAwIBAgIOHaIAAQAC7LdggHiNtgYwDQYJKoZIhvcNAQEFBQAweTELMAkGA1UE\nBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNVBAsTG1RDIFRydXN0\nQ2VudGVyIFVuaXZlcnNhbCBDQTEmMCQGA1UEAxMdVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2Fs\nIENBIEkwHhcNMDYwMzIyMTU1NDI4WhcNMjUxMjMxMjI1OTU5WjB5MQswCQYDVQQGEwJERTEc\nMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIgR21iSDEkMCIGA1UECxMbVEMgVHJ1c3RDZW50ZXIg\nVW5pdmVyc2FsIENBMSYwJAYDVQQDEx1UQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0EgSTCC\nASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKR3I5ZEr5D0MacQ9CaHnPM42Q9e3s9B\n6DGtxnSRJJZ4Hgmgm5qVSkr1YnwCqMqs+1oEdjneX/H5s7/zA1hV0qq34wQi0fiU2iIIAI3T\nfCZdzHd55yx4Oagmcw6iXSVphU9VDprvxrlE4Vc93x9UIuVvZaozhDrzznq+VZeujRIPFDPi\nUHDDSYcTvFHe15gSWu86gzOSBnWLknwSaHtwag+1m7Z3W0hZneTvWq3zwZ7U10VOylY0Ibw+\nF1tvdwxIAUMpsN0/lm7mlaoMwCC2/T42J5zjXM9OgdwZu5GQfezmlwQek8wiSdeXhrYTCjxD\nI3d+8NzmzSQfO4ObNDqDNOMCAwEAAaNjMGEwHwYDVR0jBBgwFoAUkqR1LKSevoFE63n8isWV\npesQdXMwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFJKkdSyk\nnr6BROt5/IrFlaXrEHVzMA0GCSqGSIb3DQEBBQUAA4IBAQAo0uCG1eb4e/CX3CJrO5UUVg8R\nMKWaTzqwOuAGy2X17caXJ/4l8lfmXpWMPmRgFVp/Lw0BxbFg/UU1z/CyvwbZ71q+s2IhtNer\nNXxTPqYn8aEt2hojnczd7Dwtnic0XQ/CNnm8yUpiLe1r2X1BQ3y2qsrtYbE3ghUJGooWMNjs\nydZHcnhLEEYUjl8Or+zHL6sQ17bxbuyGssLoDZJz3KL0Dzq/YSMQiZxIQG5wALPTujdEWBF6\nAmqI8Dc08BnprNRlc/ZpjGSUOnmFKbAWKwyCPwacx/0QK54PLLae4xW/2TYcuiUaUj0a7CIM\nHOCkoj3w6DnPgcB77V0fb8XQC9eY\n-----END CERTIFICATE-----\n", + "Deutsche Telekom Root CA 2": "-----BEGIN CERTIFICATE-----\nMIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEcMBoGA1UE\nChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRl\ncjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENBIDIwHhcNOTkwNzA5MTIxMTAw\nWhcNMTkwNzA5MjM1OTAwWjBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMTRGV1dHNjaGUgVGVs\nZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1\ndHNjaGUgVGVsZWtvbSBSb290IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB\nAQCrC6M14IspFLEUha88EOQ5bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1c\nOs7TuKhCQN/Po7qCWWqSG6wcmtoIKyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1Mjwr\nrFDa1sPeg5TKqAyZMg4ISFZbavva4VhYAUlfckE8FQYBjl2tqriTtM2e66foai1SNNs671x1\nUdrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aKSe5TBY8ZTNXeWHmb0mocQqvF1afPaA+W5OFh\nmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTVjlsB9WoHtxa2bkp/AgMBAAGjQjBAMB0G\nA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAPBgNVHRMECDAGAQH/AgEFMA4GA1UdDwEB\n/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAlGRZrTlk5ynrE/5aw4sTV8gEJPB0d8Bg42f7\n6Ymmg7+Wgnxu1MM9756AbrsptJh6sTtU6zkXR34ajgv8HzFZMQSyzhfzLMdiNlXiItiJVbSY\nSKpk+tYcNthEeFpaIzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8rZ7/gFnkm0W09juw\nzTkZmDLl6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4Gdyd1Lx+4ivn+\nxbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mUCm26OWMo\nhpLzGITY+9HPBVZkVw==\n-----END CERTIFICATE-----\n", + "ComSign Secured CA": "-----BEGIN CERTIFICATE-----\nMIIDqzCCApOgAwIBAgIRAMcoRwmzuGxFjB36JPU2TukwDQYJKoZIhvcNAQEFBQAwPDEbMBkG\nA1UEAxMSQ29tU2lnbiBTZWN1cmVkIENBMRAwDgYDVQQKEwdDb21TaWduMQswCQYDVQQGEwJJ\nTDAeFw0wNDAzMjQxMTM3MjBaFw0yOTAzMTYxNTA0NTZaMDwxGzAZBgNVBAMTEkNvbVNpZ24g\nU2VjdXJlZCBDQTEQMA4GA1UEChMHQ29tU2lnbjELMAkGA1UEBhMCSUwwggEiMA0GCSqGSIb3\nDQEBAQUAA4IBDwAwggEKAoIBAQDGtWhfHZQVw6QIVS3joFd67+l0Kru5fFdJGhFeTymHDEjW\naueP1H5XJLkGieQcPOqs49ohgHMhCu95mGwfCP+hUH3ymBvJVG8+pSjsIQQPRbsHPaHA+iqY\nHU4Gk/v1iDurX8sWv+bznkqH7Rnqwp9D5PGBpX8QTz7RSmKtUxvLg/8HZaWSLWapW7ha9B20\nIZFKF3ueMv5WJDmyVIRD9YTC2LxBkMyd1mja6YJQqTtoz7VdApRgFrFD2UNd3V2Hbuq7s8lr\n9gOUCXDeFhF6K+h2j0kQmHe5Y1yLM5d19guMsqtb3nQgJT/j8xH5h2iGNXHDHYwt6+UarA9z\n1YJZQIDTAgMBAAGjgacwgaQwDAYDVR0TBAUwAwEB/zBEBgNVHR8EPTA7MDmgN6A1hjNodHRw\nOi8vZmVkaXIuY29tc2lnbi5jby5pbC9jcmwvQ29tU2lnblNlY3VyZWRDQS5jcmwwDgYDVR0P\nAQH/BAQDAgGGMB8GA1UdIwQYMBaAFMFL7XC29z58ADsAj8c+DkWfHl3sMB0GA1UdDgQWBBTB\nS+1wtvc+fAA7AI/HPg5Fnx5d7DANBgkqhkiG9w0BAQUFAAOCAQEAFs/ukhNQq3sUnjO2QiBq\n1BW9Cav8cujvR3qQrFHBZE7piL1DRYHjZiM/EoZNGeQFsOY3wo3aBijJD4mkU6l1P7CW+6tM\nM1X5eCZGbxs2mPtCdsGCuY7e+0X5YxtiOzkGynd6qDwJz2w2PQ8KRUtpFhpFfTMDZflScZAm\nlaxMDPWLkz/MdXSFmLr/YnpNH4n+rr2UAJm/EaXc4HnFFgt9AmEd6oX5AhVP51qJThRv4zdL\nhfXBPGHg/QVBspJ/wx2g0K5SZGBrGMYmnNj1ZOQ2GmKfig8+/21OGVZOIJFsnzQzOjRXUDpv\ngV4GxvU+fE6OK85lBi5d0ipTdF7Tbieejw==\n-----END CERTIFICATE-----\n", + "Cybertrust Global Root": "-----BEGIN CERTIFICATE-----\nMIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYGA1UEChMP\nQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBSb290MB4XDTA2\nMTIxNTA4MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UEChMPQ3liZXJ0cnVzdCwgSW5j\nMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOC\nAQ8AMIIBCgKCAQEA+Mi8vRRQZhP/8NN57CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO2\n1O1fWLE3TdVJDm71aofW0ozSJ8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2O\nlTEQXO2iLb3VOm2yHLtgwEZLAfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeW\nP032a7iPt3sMpTjr3kfb1V05/Iin89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNz\nFtApD0mpSPCzqrdsxacwOUBdrsTiXSZT8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAYXSUnpQID\nAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBS2\nCHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vd3d3Mi5wdWJs\naWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3JsMB8GA1UdIwQYMBaAFLYIew16zKwgTIZW\nMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUAA4IBAQBW7wojoFROlZfJ+InaRcHUowAl9B8Tq7ej\nhVhpwjCt2BWKLePJzYFa+HMjWqd8BfP9IjsO0QbE2zZMcwSO5bAi5MXzLqXZI+O4Tkogp24C\nJJ8iYGd7ix1yCcUxXOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2hO0j9n0Hq0V+09+z\nv+mKts2oomcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+TX3EJIrduPuoc\nA06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jWWL1WMRJO\nEcgh4LMRkWXbtKaIOM5V\n-----END CERTIFICATE-----\n", + "ePKI Root Certification Authority": "-----BEGIN CERTIFICATE-----\nMIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBeMQswCQYD\nVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xKjAoBgNVBAsM\nIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNDEyMjAwMjMxMjdaFw0z\nNDEyMjAwMjMxMjdaMF4xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29t\nIENvLiwgTHRkLjEqMCgGA1UECwwhZVBLSSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U\n82N0ywEhajfqhFAHSyZbCUNsIZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrB\np0xtInAhijHyl3SJCRImHJ7K2RKilTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3X\nDZoTM1PRYfl61dd4s5oz9wCGzh1NlDivqOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1TBnsZfZr\nxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX12ruOzjjK9SXDrkb5wdJfzcq+Xd4z1TtW0ad\no4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0OWQqraffAsgRFelQArr5T9rXn4fg8ozHS\nqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uUWH1+ETOxQvdibBjWzwloPn9s9h6PYq2l\nY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLSnT0IFaUQAS2zMnaolQ2zepr7BxB4EW/hj8e6DyUa\ndCrlHJhBmd8hh+iVBmoKs2pHdmX2Os+PYhcZewoozRrSgx4hxyy/vv9haLdnG7t4TY3OZ+Xk\nwY63I2binZB1NJipNiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXiZo1jDiVN1Rmy5nk3\npyKdVDECAwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/QkqiMAwGA1UdEwQF\nMAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLHClZ87lt4\nDJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGBuvl2ICO1J2B01GqZ\nNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6YlPwZpVnPDimZI+ymBV3QGypzq\nKOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkPJXtoUHRVnAxZfVo9QZQlUgjgRywVMRnV\nvwdVxrsStZf0X4OFunHB2WyBEXYKCrC/gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltab\nrNMdjmEPNXubrjlpC2JgQCA2j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc\n7b3jajWvY9+rGNm65ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8\nGrBQAuUBo2M3IUxExJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS\n/jQ6fbjpKdx2qcgw+BRxgMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2zGp1iro2C\n6pSe3VkQw63d4k3jMdXH7OjysP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTEW9c3rkIO3aQab3yI\nVMUWbuF6aC74Or8NpDyJO3inTmODBCEIZ43ygknQW/2xzQ+DhNQ+IIX3Sj0rnP0qCglN6oH4\nEZw=\n-----END CERTIFICATE-----\n", + "TÜBÄ°TAK UEKAE Kök Sertifika Hizmet Sağlayıcısı - Sürüm 3": "-----BEGIN CERTIFICATE-----\nMIIFFzCCA/+gAwIBAgIBETANBgkqhkiG9w0BAQUFADCCASsxCzAJBgNVBAYTAlRSMRgwFgYD\nVQQHDA9HZWJ6ZSAtIEtvY2FlbGkxRzBFBgNVBAoMPlTDvHJraXllIEJpbGltc2VsIHZlIFRl\na25vbG9qaWsgQXJhxZ90xLFybWEgS3VydW11IC0gVMOcQsSwVEFLMUgwRgYDVQQLDD9VbHVz\nYWwgRWxla3Ryb25payB2ZSBLcmlwdG9sb2ppIEFyYcWfdMSxcm1hIEVuc3RpdMO8c8O8IC0g\nVUVLQUUxIzAhBgNVBAsMGkthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppMUowSAYDVQQDDEFU\nw5xCxLBUQUsgVUVLQUUgS8O2ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSAt\nIFPDvHLDvG0gMzAeFw0wNzA4MjQxMTM3MDdaFw0xNzA4MjExMTM3MDdaMIIBKzELMAkGA1UE\nBhMCVFIxGDAWBgNVBAcMD0dlYnplIC0gS29jYWVsaTFHMEUGA1UECgw+VMO8cmtpeWUgQmls\naW1zZWwgdmUgVGVrbm9sb2ppayBBcmHFn3TEsXJtYSBLdXJ1bXUgLSBUw5xCxLBUQUsxSDBG\nBgNVBAsMP1VsdXNhbCBFbGVrdHJvbmlrIHZlIEtyaXB0b2xvamkgQXJhxZ90xLFybWEgRW5z\ndGl0w7xzw7wgLSBVRUtBRTEjMCEGA1UECwwaS2FtdSBTZXJ0aWZpa2FzeW9uIE1lcmtlemkx\nSjBIBgNVBAMMQVTDnELEsFRBSyBVRUtBRSBLw7ZrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xh\necSxY8Sxc8SxIC0gU8O8csO8bSAzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA\nim1L/xCIOsP2fpTo6iBkcK4hgb46ezzb8R1Sf1n68yJMlaCQvEhOEav7t7WNeoMojCZG2E6V\nQIdhn8WebYGHV2yKO7Rm6sxA/OOqbLLLAdsyv9Lrhc+hDVXDWzhXcLh1xnnRFDDtG1hba+81\n8qEhTsXOfJlfbLm4IpNQp81McGq+agV/E5wrHur+R84EpW+sky58K5+eeROR6Oqeyjh1jmKw\nlZMq5d/pXpduIF9fhHpEORlAHLpVK/swsoHvhOPc7Jg4OQOFCKlUAwUp8MmPi+oLhmUZEdPp\nCSPeaJMDyTYcIW7OjGbxmTDY17PDHfiBLqi9ggtm/oLL4eAagsNAgQIDAQABo0IwQDAdBgNV\nHQ4EFgQUvYiHyY/2pAoLquvF/pEjnatKijIwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF\nMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAB18+kmPNOm3JpIWmgV050vQbTlswyb2zrgxvMTf\nvCr4N5EY3ATIZJkrGG2AA1nJrvhY0D7twyOfaTyGOBye79oneNGEN3GKPEs5z35FBtYt2IpN\neBLWrcLTy9LQQfMmNkqblWwM7uXRQydmwYj3erMgbOqwaSvHIOgMA8RBBZniP+Rr+KCGgceE\nxh/VS4ESshYhLBOhgLJeDEoTniDYYkCrkOpkSi+sDQESeUWoL4cZaMjihccwsnX5OD+ywJO0\na+IDRM5noN+J1q2MdqMTw5RhK2vZbMEHCiIHhWyFJEapvj+LeISCfiQMnf2BN+MlqO02TpUs\nyZyQ2uypQjyttgI=\n-----END CERTIFICATE-----\n", + "Buypass Class 2 CA 1": "-----BEGIN CERTIFICATE-----\nMIIDUzCCAjugAwIBAgIBATANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEdMBsGA1UE\nCgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3MgQ2xhc3MgMiBDQSAx\nMB4XDTA2MTAxMzEwMjUwOVoXDTE2MTAxMzEwMjUwOVowSzELMAkGA1UEBhMCTk8xHTAbBgNV\nBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MR0wGwYDVQQDDBRCdXlwYXNzIENsYXNzIDIgQ0Eg\nMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAIs8B0XY9t/mx8q6jUPFR42wWsE4\n25KEHK8T1A9vNkYgxC7McXA0ojTTNy7Y3Tp3L8DrKehc0rWpkTSHIln+zNvnma+WwajHQN2l\nFYxuyHyXA8vmIPLXl18xoS830r7uvqmtqEyeIWZDO6i88wmjONVZJMHCR3axiFyCO7srpgTX\njAePzdVBHfCuuCkslFJgNJQ72uA40Z0zPhX0kzLFANq1KWYOOngPIVJfAuWSeyXTkh4vFZ2B\n5J2O6O+JzhRMVB0cgRJNcKi+EAUXfh/RuFdV7c27UsKwHnjCTTZoy1YmwVLBvXb3WNVyfh9E\ndrsAiR0WnVE1703CVu9r4Iw7DekCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E\nFgQUP42aWYv8e3uco684sDntkHGA1sgwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUA\nA4IBAQAVGn4TirnoB6NLJzKyQJHyIdFkhb5jatLPgcIV1Xp+DCmsNx4cfHZSldq1fyOhKXdl\nyTKdqC5Wq2B2zha0jX94wNWZUYN/Xtm+DKhQ7SLHrQVMdvvt7h5HZPb3J31cKA9FxVxiXqaa\nkZG3Uxcu3K1gnZZkOb1naLKuBctN518fV4bVIJwo+28TOPX2EZL2fZleHwzoq0QkKXJAPTZS\nr4xYkHPB7GEseaHsh7U/2k3ZIQAw3pDaDtMaSKk+hQsUi4y8QZ5q9w5wwDX3OaJdZtB7WZ+o\nRxKaJyOkLY4ng5IgodcVf/EuGO70SH8vf/GhGLWhC5SgYiAynB321O+/TIho\n-----END CERTIFICATE-----\n", + "Buypass Class 3 CA 1": "-----BEGIN CERTIFICATE-----\nMIIDUzCCAjugAwIBAgIBAjANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEdMBsGA1UE\nCgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3MgQ2xhc3MgMyBDQSAx\nMB4XDTA1MDUwOTE0MTMwM1oXDTE1MDUwOTE0MTMwM1owSzELMAkGA1UEBhMCTk8xHTAbBgNV\nBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MR0wGwYDVQQDDBRCdXlwYXNzIENsYXNzIDMgQ0Eg\nMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKSO13TZKWTeXx+HgJHqTjnmGcZE\nC4DVC69TB4sSveZn8AKxifZgisRbsELRwCGoy+Gb72RRtqfPFfV0gGgEkKBYouZ0plNTVUhj\nP5JW3SROjvi6K//zNIqeKNc0n6wv1g/xpC+9UrJJhW05NfBEMJNGJPO251P7vGGvqaMU+8IX\nF4Rs4HyI+MkcVyzwPX6UvCWThOiaAJpFBUJXgPROztmuOfbIUxAMZTpHe2DC1vqRycZxbL2R\nhzyRhkmr8w+gbCZ2Xhysm3HljbybIR6c1jh+JIAVMYKWsUnTYjdbiAwKYjT+p0h+mbEwi5A3\nlRyoH6UsjfRVyNvdWQrCrXig9IsCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E\nFgQUOBTmyPCppAP0Tj4io1vy1uCtQHQwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUA\nA4IBAQABZ6OMySU9E2NdFm/soT4JXJEVKirZgCFPBdy7pYmrEzMqnji3jG8CcmPHc3ceCQa6\nOyh7pEfJYWsICCD8igWKH7y6xsL+z27sEzNxZy5p+qksP2bAEllNC1QCkoS72xLvg3BweMhT\n+t/Gxv/ciC8HwEmdMldg0/L2mSlf56oBzKwzqBwKu5HEA6BvtjT5htOzdlSY9EqBs1OdTUDs\n5XcTRa9bqh/YL0yCe/4qxFi7T/ye/QNlGioOw6UgFpRreaaiErS7GqQjel/wroQk5PMr+4ok\noyeYZdowdXb8GZHo2+ubPzK/QJcHJrrM85SFSnonk8+QQtS4Wxam58tAA915\n-----END CERTIFICATE-----\n", + "EBG Elektronik Sertifika Hizmet Sağlayıcısı": "-----BEGIN CERTIFICATE-----\nMIIF5zCCA8+gAwIBAgIITK9zQhyOdAIwDQYJKoZIhvcNAQEFBQAwgYAxODA2BgNVBAMML0VC\nRyBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMTcwNQYDVQQK\nDC5FQkcgQmlsacWfaW0gVGVrbm9sb2ppbGVyaSB2ZSBIaXptZXRsZXJpIEEuxZ4uMQswCQYD\nVQQGEwJUUjAeFw0wNjA4MTcwMDIxMDlaFw0xNjA4MTQwMDMxMDlaMIGAMTgwNgYDVQQDDC9F\nQkcgRWxla3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTE3MDUGA1UE\nCgwuRUJHIEJpbGnFn2ltIFRla25vbG9qaWxlcmkgdmUgSGl6bWV0bGVyaSBBLsWeLjELMAkG\nA1UEBhMCVFIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDuoIRh0DpqZhAy2DE4\nf6en5f2h4fuXd7hxlugTlkaDT7byX3JWbhNgpQGR4lvFzVcfd2NR/y8927k/qqk153nQ9dAk\ntiHq6yOU/im/+4mRDGSaBUorzAzu8T2bgmmkTPiab+ci2hC6X5L8GCcKqKpE+i4stPtGmggD\ng3KriORqcsnlZR9uKg+ds+g75AxuetpX/dfreYteIAbTdgtsApWjluTLdlHRKJ2hGvxEok3M\nenaoDT2/F08iiFD9rrbskFBKW5+VQarKD7JK/oCZTqNGFav4c0JqwmZ2sQomFd2TkuzbqV9U\nIlKRcF0T6kjsbgNs2d1s/OsNA/+mgxKb8amTD8UmTDGyY5lhcucqZJnSuOl14nypqZoaqsNW\n2xCaPINStnuWt6yHd6i58mcLlEOzrz5z+kI2sSXFCjEmN1ZnuqMLfdb3ic1nobc6HmZP9qBV\nFCVMLDMNpkGMvQQxahByCp0OLna9XvNRiYuoP1Vzv9s6xiQFlpJIqkuNKgPlV5EQ9GooFW5H\nd4RcUXSfGenmHmMWOeMRFeNYGkS9y8RsZteEBt8w9DeiQyJ50hBs37vmExH8nYQKE3vwO9D8\nowrXieqWfo1IhR5kX9tUoqzVegJ5a9KK8GfaZXINFHDk6Y54jzJ0fFfy1tb0Nokb+Clsi7n2\nl9GkLqq+CxnCRelwXQIDAJ3Zo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB\nBjAdBgNVHQ4EFgQU587GT/wWZ5b6SqMHwQSny2re2kcwHwYDVR0jBBgwFoAU587GT/wWZ5b6\nSqMHwQSny2re2kcwDQYJKoZIhvcNAQEFBQADggIBAJuYml2+8ygjdsZs93/mQJ7ANtyVDR2t\nFcU22NU57/IeIl6zgrRdu0waypIN30ckHrMk2pGI6YNw3ZPX6bqz3xZaPt7gyPvT/Wwp+BVG\noGgmzJNSroIBk5DKd8pNSe/iWtkqvTDOTLKBtjDOWU/aWR1qeqRFsIImgYZ29fUQALjuswno\nT4cCB64kXPBfrAowzIpAoHMEwfuJJPaaHFy3PApnNgUIMbOv2AFoKuB4j3TeuFGkjGwgPaL7\ns9QJ/XvCgKqTbCmYIai7FvOpEl90tYeY8pUm3zTvilORiF0alKM/fCL414i6poyWqD1SNGKf\nAB5UVUJnxk1Gj7sURT0KlhaOEKGXmdXTMIXM3rRyt7yKPBgpaP3ccQfuJDlq+u2lrDgv+R4Q\nDgZxGhBM/nV+/x5XOULK1+EVoVZVWRvRo68R2E7DpSvvkL/A7IITW43WciyTTo9qKd+FPNMN\n4KIYEsxVL0e3p5sC/kH2iExt2qkBR4NkJ2IQgtYSe14DHzSpyZH+r11thie3I6p1GMog57AP\n14kOpmciY/SDQSsGS7tY1dHXt7kQY9iJSrSq3RZj9W6+YKH47ejWkE8axsWgKdOnIaj1Wjz3\nx0miIZpKlVIglnKaZsv30oZDfCK+lvm9AahH3eU7QPl1K5srRmSGjR70j/sHd9DqSaIcjVIU\npgqT\n-----END CERTIFICATE-----\n", + "certSIGN ROOT CA": "-----BEGIN CERTIFICATE-----\nMIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYTAlJPMREw\nDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTAeFw0wNjA3MDQx\nNzIwMDRaFw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lH\nTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC\nAQoCggEBALczuX7IJUqOtdu0KBuqV5Do0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oq\nrl0Hj0rDKH/v+yv6efHHrfAQUySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsA\nfsT8AzNXDe3i+s5dRdY4zTW2ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUo\nSe1b16kQOA7+j0xbm0bqQfWwCHTD0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwv\nJoIQ4uNllAoEwF73XVv4EOLQunpL+943AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08CAwEAAaNC\nMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAcYwHQYDVR0OBBYEFOCMm9slSbPx\nfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IBAQA+0hyJLjX8+HXd5n9liPRyTMks1zJO\n890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecYMnQ8SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6\nIJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ44gx+FkagQnIl6Z0x2DEW8xXjrJ1/RsCCdtZb3KT\nafcxQdaIOL+Hsr0Wefmq5L6IJd1hJyMctTEHBDa0GpC9oHRxUIltvBTjD4au8as+x6AJzKNI\n0eDbZOeStc+vckNwi/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7NzTogVZ96edhBiIL5V\naZVDADlN9u6wWk5JRFRYX0KD\n-----END CERTIFICATE-----\n", + "CNNIC ROOT": "-----BEGIN CERTIFICATE-----\nMIIDVTCCAj2gAwIBAgIESTMAATANBgkqhkiG9w0BAQUFADAyMQswCQYDVQQGEwJDTjEOMAwG\nA1UEChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwHhcNMDcwNDE2MDcwOTE0WhcNMjcw\nNDE2MDcwOTE0WjAyMQswCQYDVQQGEwJDTjEOMAwGA1UEChMFQ05OSUMxEzARBgNVBAMTCkNO\nTklDIFJPT1QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDTNfc/c3et6FtzF8LR\nb+1VvG7q6KR5smzDo+/hn7E7SIX1mlwhIhAsxYLO2uOabjfhhyzcuQxauohV3/2q2x8x6gHx\n3zkBwRP9SFIhxFXf2tizVHa6dLG3fdfA6PZZxU3Iva0fFNrfWEQlMhkqx35+jq44sDB7R3IJ\nMfAw28Mbdim7aXZOV/kbZKKTVrdvmW7bCgScEeOAH8tjlBAKqeFkgjH5jCftppkA9nCTGPih\nNIaj3XrCGHn2emU1z5DrvTOTn1OrczvmmzQgLx3vqR1jGqCA2wMv+SYahtKNu6m+UjqHZ0gN\nv7Sg2Ca+I19zN38m5pIEo3/PIKe38zrKy5nLAgMBAAGjczBxMBEGCWCGSAGG+EIBAQQEAwIA\nBzAfBgNVHSMEGDAWgBRl8jGtKvf33VKWCscCwQ7vptU7ETAPBgNVHRMBAf8EBTADAQH/MAsG\nA1UdDwQEAwIB/jAdBgNVHQ4EFgQUZfIxrSr3991SlgrHAsEO76bVOxEwDQYJKoZIhvcNAQEF\nBQADggEBAEs17szkrr/Dbq2flTtLP1se31cpolnKOOK5Gv+e5m4y3R6u6jW39ZORTtpC4cMX\nYFDy0VwmuYK36m3knITnA3kXr5g9lNvHugDnuL8BV8F3RTIMO/G0HAiw/VGgod2aHRM2mm23\nxzy54cXZF/qD1T0VoDy7HgviyJA/qIYM/PmLXoXLT1tLYhFHxUV8BS9BsZ4QaRuZluBVeftO\nhpm4lNqGOGqTo+fLbuXf6iFViZx9fX+Y9QCJ7uOEwFyWtcVG6kbghVW2G8kS1sHNzYDzAgE8\nyGnLRUhj2JTQ7IUOO04RZfSCjKY9ri4ilAnIXOo8gV0WKgOXFlUJ24pBgp5mmxE=\n-----END CERTIFICATE-----\n", + "ApplicationCA - Japanese Government": "-----BEGIN CERTIFICATE-----\nMIIDoDCCAoigAwIBAgIBMTANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJKUDEcMBoGA1UE\nChMTSmFwYW5lc2UgR292ZXJubWVudDEWMBQGA1UECxMNQXBwbGljYXRpb25DQTAeFw0wNzEy\nMTIxNTAwMDBaFw0xNzEyMTIxNTAwMDBaMEMxCzAJBgNVBAYTAkpQMRwwGgYDVQQKExNKYXBh\nbmVzZSBHb3Zlcm5tZW50MRYwFAYDVQQLEw1BcHBsaWNhdGlvbkNBMIIBIjANBgkqhkiG9w0B\nAQEFAAOCAQ8AMIIBCgKCAQEAp23gdE6Hj6UG3mii24aZS2QNcfAKBZuOquHMLtJqO8F6tJdh\njYq+xpqcBrSGUeQ3DnR4fl+Kf5Sk10cI/VBaVuRorChzoHvpfxiSQE8tnfWuREhzNgaeZCw7\nNCPbXCbkcXmP1G55IrmTwcrNwVbtiGrXoDkhBFcsovW8R0FPXjQilbUfKW1eSvNNcr5BViCH\n/OlQR9cwFO5cjFW6WY2H/CPek9AEjP3vbb3QesmlOmpyM8ZKDQUXKi17safY1vC+9D/qDiht\nQWEjdnjDuGWk81quzMKq2edY3rZ+nYVunyoKb58DKTCXKB28t89UKU5RMfkntigm/qJj5kEW\n8DOYRwIDAQABo4GeMIGbMB0GA1UdDgQWBBRUWssmP3HMlEYNllPqa0jQk/5CdTAOBgNVHQ8B\nAf8EBAMCAQYwWQYDVR0RBFIwUKROMEwxCzAJBgNVBAYTAkpQMRgwFgYDVQQKDA/ml6XmnKzl\nm73mlL/lupwxIzAhBgNVBAsMGuOCouODl+ODquOCseODvOOCt+ODp+ODs0NBMA8GA1UdEwEB\n/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADlqRHZ3ODrso2dGD/mLBqj7apAxzn7s2tGJ\nfHrrLgy9mTLnsCTWw//1sogJhyzjVOGjprIIC8CFqMjSnHH2HZ9g/DgzE+Ge3Atf2hZQKXsv\ncJEPmbo0NI2VdMV+eKlmXb3KIXdCEKxmJj3ekav9FfBv7WxfEPjzFvYDio+nEhEMy/0/ecGc\n/WLuo89UDNErXxc+4z6/wCs+CZv+iKZ+tJIX/COUgb1up8WMwusRRdv4QcmWdupwX3kSa+Sj\nB1oF7ydJzyGfikwJcGapJsErEU4z0g781mzSDjJkaP+tBXhfAx2o45CsJOAPQKdLrosot4LK\nGAfmt1t06SAZf7IbiVQ=\n-----END CERTIFICATE-----\n", + "GeoTrust Primary Certification Authority - G3": "-----BEGIN CERTIFICATE-----\nMIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCBmDELMAkG\nA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA4IEdl\nb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1\nc3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMB4XDTA4MDQwMjAwMDAw\nMFoXDTM3MTIwMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJ\nbmMuMTkwNwYDVQQLEzAoYykgMjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQg\ndXNlIG9ubHkxNjA0BgNVBAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRo\nb3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz\n+uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5jK/BGvESyiaHAKAxJcCGVn2TAppMSAmUmhsalifD6\n14SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdEc5IiaacDiGydY8hS2pgn5whMcD60yRLBxWeD\nXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3CIShwiP/WJmxsYAQlTlV+fe+/lEjetx3d\ncI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exALDmKudlW/X3e+PkkBUz2YJQN2JFodtNuJ\n6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZChuOl1UcCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB\n/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMR5yo6hTgMdHNxr2zFblD4/MH8tMA0GCSqG\nSIb3DQEBCwUAA4IBAQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9cr5HqQ6XErhK8WTT\nOd8lNNTBzU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbEAp7aDHdlDkQN\nkv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGDAWh9jUGh\nlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUHSJsMC8tJP33st/3L\njWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2Gspki4cErx5z481+oghLrGREt\n-----END CERTIFICATE-----\n", + "thawte Primary Root CA - G2": "-----BEGIN CERTIFICATE-----\nMIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDELMAkGA1UE\nBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMpIDIwMDcgdGhhd3Rl\nLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmlt\nYXJ5IFJvb3QgQ0EgLSBHMjAeFw0wNzExMDUwMDAwMDBaFw0zODAxMTgyMzU5NTlaMIGEMQsw\nCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0\naGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3Rl\nIFByaW1hcnkgUm9vdCBDQSAtIEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFS\neIf+iha/BebfowJPDQfGAFG6DAJSLSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6\npapu+7qzcMBniKI11KOasf2twu8x+qi58/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8EBTADAQH/\nMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUmtgAMADna3+FGO6Lts6KDPgR4bswCgYIKoZI\nzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUNG4k8VIZ3KMqh9HneteY4sPBlcIx/AlTC\nv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41oxXZ3Krr0TKUQNJ1uo52icEvdYPy5yAlej\nj6EULg==\n-----END CERTIFICATE-----\n", + "thawte Primary Root CA - G3": "-----BEGIN CERTIFICATE-----\nMIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCBrjELMAkG\nA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlv\nbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDggdGhhd3RlLCBJbmMuIC0g\nRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3Qg\nQ0EgLSBHMzAeFw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJV\nUzEVMBMGA1UEChMMdGhhd3RlLCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZp\nY2VzIERpdmlzaW9uMTgwNgYDVQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0\naG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEcz\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsr8nLPvb2FvdeHsbnndmgcs+vHyu\n86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2AtP0LMqmsywCPLLEHd5N/8YZzic7IilRFDGF/E\nth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC+BsUa0Lfb1+6a4KinVvnSr0eAXLbS3To\nO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS99irY7CFJXJv2eul/VTV+lmuNk5Mny5K7\n6qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2SzhkGcuYMXDhpxwTWvGzOW/b3aJzcJRVIiKHpqfiY\nnODz1TEoYRFsZ5aNOZnLwkUkOQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB\n/wQEAwIBBjAdBgNVHQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJKoZIhvcNAQELBQAD\nggEBABpA2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweKA3rD6z8KLFIW\noCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1but8jLZ8HJ\nnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7cKUGRIjxpp7sC8rZc\nJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fMm7v/OeZWYdMKp8RcTGB7BXcm\ner/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZuMdRAGmI0Nj81Aa6sY6A=\n-----END CERTIFICATE-----\n", + "GeoTrust Primary Certification Authority - G2": "-----BEGIN CERTIFICATE-----\nMIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDELMAkGA1UE\nBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA3IEdlb1Ry\ndXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3Qg\nUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoX\nDTM4MDExODIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMu\nMTkwNwYDVQQLEzAoYykgMjAwNyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl\nIG9ubHkxNjA0BgNVBAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp\ndHkgLSBHMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcL\nSo17VDs6bl8VAsBQps8lL33KSLjHUGMcKiEIfJo22Av+0SbFWDEwKCXzXV2juLaltJLtbCyf\n691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC\nAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+EVXVMAoGCCqGSM49BAMDA2cAMGQCMGSW\nWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGTqQ7mndwxHLKgpxgceeHHNgIwOlavmnRs\n9vuD4DPTCF+hnMJbn0bWtsuRBmOiBuczrD6ogRLQy7rQkgu2npaqBA+K\n-----END CERTIFICATE-----\n", + "VeriSign Universal Root Certification Authority": "-----BEGIN CERTIFICATE-----\nMIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCBvTELMAkG\nA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBU\ncnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJpU2lnbiwgSW5jLiAtIEZvciBh\ndXRob3JpemVkIHVzZSBvbmx5MTgwNgYDVQQDEy9WZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBD\nZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTla\nMIG9MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl\ncmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMu\nIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNh\nbCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\nMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj1mCOkdeQmIN65lgZOIzF9uVkhbSicfvtvbna\nzU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGPMiJhgsWHH26MfF8WIFFE0XBPV+rjHOPM\nee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+HLL729fdC4uW/h2KJXwBL38Xd5HVEMkE6\nHnFuacsLdUYI0crSK5XQz/u5QGtkjFdN/BMReYTtXlT2NJ8IAfMQJQYXStrxHXpma5hgZqTZ\n79IugvHw7wnqRMkVauIDbjPTrJ9VAMf2CGqUuV/c4DPxhGD5WycRtPwW8rtWaoAljQIDAQAB\no4GyMIGvMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0GCCsGAQUFBwEMBGEw\nX6FdoFswWTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2Oa8PPgGrUSBgs\nexkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1UdDgQWBBS2\nd/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4sAPmLGd75JR3Y8xu\nTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+seQxIcaBlVZaDrHC1LGmWazx\nY8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahf\nYtTxP/jgdFcrGJ2BtMQo2pSXpXDrrB2+BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tew\nXDpPaj+PwGZsY6rp2aQW9IHRlRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WI\ng0vvBZIGcfK4mJO37M2CYfE45k+XmCpajQ==\n-----END CERTIFICATE-----\n", + "VeriSign Class 3 Public Primary Certification Authority - G4": "-----BEGIN CERTIFICATE-----\nMIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjELMAkGA1UE\nBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz\ndCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRo\nb3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmlt\nYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgw\nMTE4MjM1OTU5WjCByjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8w\nHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJp\nU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2ln\nbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQw\ndjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8Utpkmw4tXNherJI9/gHmGUo9FANL+mAnINmD\niWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGzrl0Bp3vefLK+ymVhAIau2o970ImtTR1Z\nmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYI\nKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQUj+XTGoas\njY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVyaXNpZ24uY29tL3ZzbG9nby5naWYw\nHQYDVR0OBBYEFLMWkf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMDA2gAMGUCMGYhDBgm\nYFo4e1ZC4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIxAJw9SDkjOVga\nFRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA==\n-----END CERTIFICATE-----\n", + "NetLock Arany (Class Gold) Főtanúsítvány": "-----BEGIN CERTIFICATE-----\nMIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJIVTER\nMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3MDUGA1UECwwuVGFu\nw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzKTE1MDMGA1UEAwws\nTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWRdGFuw7pzw610dsOhbnkwHhcNMDgxMjEx\nMTUwODIxWhcNMjgxMjA2MTUwODIxWjCBpzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFw\nZXN0MRUwEwYDVQQKDAxOZXRMb2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lh\nZMOzayAoQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkg\nKENsYXNzIEdvbGQpIEbFkXRhbsO6c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\nMIIBCgKCAQEAxCRec75LbRTDofTjl5Bu0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrTlF8afFtt\nvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw/HpYzY6b7cNGbIRwXdrzAZAj/E4wqX7hJ2Pn\n7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAkH3B5r9s5VA1lddkVQZQBr17s9o3x/61k\n/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRGILdwfzzeSNuWU7c5d+Qa4scWhHaXWy+7\nGRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2BJtr+UBdADTHLpl1neWIA6pN+APSQnbAGwIDAKiL\no0UwQzASBgNVHRMBAf8ECDAGAQH/AgEEMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUzPpn\nk/C2uNClwB7zU/2MU9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwWqZw8UQCgwBEIBaeZ\n5m8BiFRhbvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTtaYtOUZcTh5m2C\n+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzCbLBQWV2Q\nWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2FuLjbvrW5KfnaNwUA\nSZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2XjG4Kvte9nHfRCaexOYNkbQu\ndZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E=\n-----END CERTIFICATE-----\n", + "Staat der Nederlanden Root CA - G2": "-----BEGIN CERTIFICATE-----\nMIIFyjCCA7KgAwIBAgIEAJiWjDANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJOTDEeMBwG\nA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFhdCBkZXIgTmVkZXJs\nYW5kZW4gUm9vdCBDQSAtIEcyMB4XDTA4MDMyNjExMTgxN1oXDTIwMDMyNTExMDMxMFowWjEL\nMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjErMCkGA1UEAwwi\nU3RhYXQgZGVyIE5lZGVybGFuZGVuIFJvb3QgQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQAD\nggIPADCCAgoCggIBAMVZ5291qj5LnLW4rJ4L5PnZyqtdj7U5EILXr1HgO+EASGrP2uEGQxGZ\nqhQlEq0i6ABtQ8SpuOUfiUtnvWFI7/3S4GCI5bkYYCjDdyutsDeqN95kWSpGV+RLufg3fNU2\n54DBtvPUZ5uW6M7XxgpT0GtJlvOjCwV3SPcl5XCsMBQgJeN/dVrlSPhOewMHBPqCYYdu8DvE\npMfQ9XQ+pV0aCPKbJdL2rAQmPlU6Yiile7Iwr/g3wtG61jj99O9JMDeZJiFIhQGp5Rbn3JBV\n3w/oOM2ZNyFPXfUib2rFEhZgF1XyZWampzCROME4HYYEhLoaJXhena/MUGDWE4dS7WMfbWV9\nwhUYdMrhfmQpjHLYFhN9C0lK8SgbIHRrxT3dsKpICT0ugpTNGmXZK4iambwYfp/ufWZ8Pr2U\nuIHOzZgweMFvZ9C+X+Bo7d7iscksWXiSqt8rYGPy5V6548r6f1CGPqI0GAwJaCgRHOThuVw+\nR7oyPxjMW4T182t0xHJ04eOLoEq9jWYv6q012iDTiIJh8BIitrzQ1aTsr1SIJSQ8p22xcik/\nPlemf1WvbibG/ufMQFxRRIEKeN5KzlW/HdXZt1bv8Hb/C3m1r737qWmRRpdogBQ2HbN/uymY\nNqUg+oJgYjOk7Na6B6duxc8UpufWkjTYgfX8HV2qXB72o007uPc5AgMBAAGjgZcwgZQwDwYD\nVR0TAQH/BAUwAwEB/zBSBgNVHSAESzBJMEcGBFUdIAAwPzA9BggrBgEFBQcCARYxaHR0cDov\nL3d3dy5wa2lvdmVyaGVpZC5ubC9wb2xpY2llcy9yb290LXBvbGljeS1HMjAOBgNVHQ8BAf8E\nBAMCAQYwHQYDVR0OBBYEFJFoMocVHYnitfGsNig0jQt8YojrMA0GCSqGSIb3DQEBCwUAA4IC\nAQCoQUpnKpKBglBu4dfYszk78wIVCVBR7y29JHuIhjv5tLySCZa59sCrI2AGeYwRTlHSeYAz\n+51IvuxBQ4EffkdAHOV6CMqqi3WtFMTC6GY8ggen5ieCWxjmD27ZUD6KQhgpxrRW/FYQoAUX\nvQwjf/ST7ZwaUb7dRUG/kSS0H4zpX897IZmflZ85OkYcbPnNe5yQzSipx6lVu6xiNGI1E0sU\nOlWDuYaNkqbG9AclVMwWVxJKgnjIFNkXgiYtXSAfea7+1HAWFpWD2DU5/1JddRwWxRNVz0fM\ndWVSSt7wsKfkCpYL+63C4iWEst3kvX5ZbJvw8NjnyvLplzh+ib7M+zkXYT9y2zqR2GUBGR2t\nUKRXCnxLvJxxcypFURmFzI79R6d0lR2o0a9OF7FpJsKqeFdbxU2n5Z4FF5TKsl+gSRiNNOkm\nbEgeqmiSBeGCc1qb3AdbCG19ndeNIdn8FCCqwkXfP+cAslHkwvgFuXkajDTznlvkN1trSt8s\nV4pAWja63XVECDdCcAz+3F4hoKOKwJCcaNpQ5kUQR3i2TtJlycM33+FCY7BXN0Ute4qcvwXq\nZVUz9zkQxSgqIXobisQk+T8VyJoVIPVVYpbtbZNQvOSqeK3Zywplh6ZmwcSBo3c6WB4L7oOL\nnR7SUqTMHW+wmG2UMbX4cQrcufx9MmDm66+KAQ==\n-----END CERTIFICATE-----\n", + "CA Disig": "-----BEGIN CERTIFICATE-----\nMIIEDzCCAvegAwIBAgIBATANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQGEwJTSzETMBEGA1UE\nBxMKQnJhdGlzbGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcw\nHhcNMDYwMzIyMDEzOTM0WhcNMTYwMzIyMDEzOTM0WjBKMQswCQYDVQQGEwJTSzETMBEGA1UE\nBxMKQnJhdGlzbGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcw\nggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCS9jHBfYj9mQGp2HvycXXxMcbzdWb6\nUShGhJd4NLxs/LxFWYgmGErENx+hSkS943EE9UQX4j/8SFhvXJ56CbpRNyIjZkMhsDxkovhq\nFQ4/61HhVKndBpnXmjxUizkDPw/Fzsbrg3ICqB9x8y34dQjbYkzo+s7552oftms1grrijxaS\nfQUMbEYDXcDtab86wYqg6I7ZuUUohwjstMoVvoLdtUSLLa2GDGhibYVW8qwUYzrG0ZmsNHhW\nS8+2rT+MitcE5eN4TPWGqvWP+j1scaMtymfraHtuM6kMgiioTGohQBUgDCZbg8KpFhXAJIJd\nKxatymP2dACw30PEEGBWZ2NFAgMBAAGjgf8wgfwwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E\nFgQUjbJJaJ1yCCW5wCf1UJNWSEZx+Y8wDgYDVR0PAQH/BAQDAgEGMDYGA1UdEQQvMC2BE2Nh\nb3BlcmF0b3JAZGlzaWcuc2uGFmh0dHA6Ly93d3cuZGlzaWcuc2svY2EwZgYDVR0fBF8wXTAt\noCugKYYnaHR0cDovL3d3dy5kaXNpZy5zay9jYS9jcmwvY2FfZGlzaWcuY3JsMCygKqAohiZo\ndHRwOi8vY2EuZGlzaWcuc2svY2EvY3JsL2NhX2Rpc2lnLmNybDAaBgNVHSAEEzARMA8GDSuB\nHpGT5goAAAABAQEwDQYJKoZIhvcNAQEFBQADggEBAF00dGFMrzvY/59tWDYcPQuBDRIrRhCA\n/ec8J9B6yKm2fnQwM6M6int0wHl5QpNt/7EpFIKrIYwvF/k/Ji/1WcbvgAa3mkkp7M5+cTxq\nEEHA9tOasnxakZzArFvITV734VP/Q3f8nktnbNfzg9Gg4H8l37iYC5oyOGwwoPP/CBUz91BK\nez6jPiCp3C9WgArtQVCwyfTssuMmRAAOb54GvCKWU3BlxFAKRmukLyeBEicTXxChds6Kezfq\nwzlhA5WYOudsiCUI/HloDYd9Yvi0X/vF2Ey9WLw/Q1vUHgFNPGO+I++MzVpQuGhU+QqZMxEA\n4Z7CRneC9VkGjCFMhwnN5ag=\n-----END CERTIFICATE-----\n", + "Juur-SK": "-----BEGIN CERTIFICATE-----\nMIIE5jCCA86gAwIBAgIEO45L/DANBgkqhkiG9w0BAQUFADBdMRgwFgYJKoZIhvcNAQkBFglw\na2lAc2suZWUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKExlBUyBTZXJ0aWZpdHNlZXJpbWlza2Vz\na3VzMRAwDgYDVQQDEwdKdXVyLVNLMB4XDTAxMDgzMDE0MjMwMVoXDTE2MDgyNjE0MjMwMVow\nXTEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVlMQswCQYDVQQGEwJFRTEiMCAGA1UEChMZQVMg\nU2VydGlmaXRzZWVyaW1pc2tlc2t1czEQMA4GA1UEAxMHSnV1ci1TSzCCASIwDQYJKoZIhvcN\nAQEBBQADggEPADCCAQoCggEBAIFxNj4zB9bjMI0TfncyRsvPGbJgMUaXhvSYRqTCZUXP00B8\n41oiqBB4M8yIsdOBSvZiF3tfTQou0M+LI+5PAk676w7KvRhj6IAcjeEcjT3g/1tf6mTll+g/\nmX8MCgkzABpTpyHhOEvWgxutr2TC+Rx6jGZITWYfGAriPrsfB2WThbkasLnE+w0R9vXW+RvH\nLCu3GFH+4Hv2qEivbDtPL+/40UceJlfwUR0zlv/vWT3aTdEVNMfqPxZIe5EcgEMPPbgFPtGz\nlc3Yyg/CQ2fbt5PgIoIuvvVoKIO5wTtpeyDaTpxt4brNj3pssAki14sL2xzVWiZbDcDq5WDQ\nn/413z8CAwEAAaOCAawwggGoMA8GA1UdEwEB/wQFMAMBAf8wggEWBgNVHSAEggENMIIBCTCC\nAQUGCisGAQQBzh8BAQEwgfYwgdAGCCsGAQUFBwICMIHDHoHAAFMAZQBlACAAcwBlAHIAdABp\nAGYAaQBrAGEAYQB0ACAAbwBuACAAdgDkAGwAagBhAHMAdABhAHQAdQBkACAAQQBTAC0AaQBz\nACAAUwBlAHIAdABpAGYAaQB0AHMAZQBlAHIAaQBtAGkAcwBrAGUAcwBrAHUAcwAgAGEAbABh\nAG0ALQBTAEsAIABzAGUAcgB0AGkAZgBpAGsAYQBhAHQAaQBkAGUAIABrAGkAbgBuAGkAdABh\nAG0AaQBzAGUAawBzMCEGCCsGAQUFBwIBFhVodHRwOi8vd3d3LnNrLmVlL2Nwcy8wKwYDVR0f\nBCQwIjAgoB6gHIYaaHR0cDovL3d3dy5zay5lZS9qdXVyL2NybC8wHQYDVR0OBBYEFASqekej\n5ImvGs8KQKcYP2/v6X2+MB8GA1UdIwQYMBaAFASqekej5ImvGs8KQKcYP2/v6X2+MA4GA1Ud\nDwEB/wQEAwIB5jANBgkqhkiG9w0BAQUFAAOCAQEAe8EYlFOiCfP+JmeaUOTDBS8rNXiRTHyo\nERF5TElZrMj3hWVcRrs7EKACr81Ptcw2Kuxd/u+gkcm2k298gFTsxwhwDY77guwqYHhpNjbR\nxZyLabVAyJRld/JXIWY7zoVAtjNjGr95HvxcHdMdkxuLDF2FvZkwMhgJkVLpfKG6/2SSmuz+\nNe6ML678IIbsSt4beDI3poHSna9aEhbKmVv8b20OxaAehsmR0FyYgl9jDIpaq9iVpszLita/\nZEuOyoqysOkhMp6qqIWYNIE5ITuoOlIyPfZrN4YGWhWY3PARZv40ILcD9EEQfTmEeZZyY7aW\nAuVrua0ZTbvGRNs2yyqcjg==\n-----END CERTIFICATE-----\n", + "Hongkong Post Root CA 1": "-----BEGIN CERTIFICATE-----\nMIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsxFjAUBgNV\nBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMB4X\nDTAzMDUxNTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoT\nDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMIIBIjAN\nBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArP84tulmAknjorThkPlAj3n54r15/gK97iSS\nHSL22oVyaf7XPwnU3ZG1ApzQjVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8g\nPW2iNr4joLFutbEnPzlTCeqrauh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7j\nEAaPIpjhZY4bXSNmO7ilMlHIhqqhqZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9\nnnV0ttgCXjqQesBCNnLsak3c78QA3xMYV18meMjWCnl3v/evt3a5pQuEF10Q6m/hq5URX208\no1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNVHRMBAf8ECDAGAQH/AgEDMA4GA1UdDwEB/wQE\nAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7ih9legYsCmEEIjEy82tvuJxuC52pF7BaL\nT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI37piol7Yutmcn1KZJ/RyTZXaeQi/cImya\nT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clBoiMBdDhViw+5LmeiIAQ32pwL0xch4I+XeTRvhEgC\nIDMb5jREn5Fw9IBehEPCKdJsEhTkYY2sEJCehFC78JZvRZ+K88psT/oROhUVRsPNH4NbLUES\n7VBnQRM9IauUiqpOfMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilTc4afU9hDDl3WY4Jx\nHYB0yvbiAmvZWg==\n-----END CERTIFICATE-----\n", + "SecureSign RootCA11": "-----BEGIN CERTIFICATE-----\nMIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDErMCkGA1UE\nChMiSmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoGA1UEAxMTU2VjdXJl\nU2lnbiBSb290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0MDgwNDU2NDdaMFgxCzAJBgNV\nBAYTAkpQMSswKQYDVQQKEyJKYXBhbiBDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzLCBJbmMuMRww\nGgYDVQQDExNTZWN1cmVTaWduIFJvb3RDQTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\nCgKCAQEA/XeqpRyQBTvLTJszi1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1y\nfIw/XwFndBWW4wI8h9uuywGOwvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyK\nyiyhFTOVMdrAG/LuYpmGYz+/3ZMqg6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9\nUK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rPO7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni8McDWc/V\n1uinMrPmmECGxc0nEovMe863ETxiYAcjPitAbpSACW22s293bzUIUPsCh8U+iQIDAQABo0Iw\nQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZXt94wDgYDVR0PAQH/BAQDAgEGMA8GA1Ud\nEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAKChOBZmLqdWHyGcBvod7bkixTgm2E5P\n7KN/ed5GIaGHd48HCJqypMWvDzKYC3xmKbabfSVSSUOrTC4rbnpwrxYO4wJs+0LmGJ1F2FXI\n6Dvd5+H0LgscNFxsWEr7jIhQX5Ucv+2rIrVls4W6ng+4reV6G4pQOh29Dbx7VFALuUKvVaAY\nga1lme++5Jy/xIWrQbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01y8hSyn+B/tlr0/cR\n7SXf+Of5pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061lgeLKBObjBmN\nQSdJQO7e5iNEOdyhIta6A/I=\n-----END CERTIFICATE-----\n", + "ACEDICOM Root": "-----BEGIN CERTIFICATE-----\nMIIFtTCCA52gAwIBAgIIYY3HhjsBggUwDQYJKoZIhvcNAQEFBQAwRDEWMBQGA1UEAwwNQUNF\nRElDT00gUm9vdDEMMAoGA1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00xCzAJBgNVBAYTAkVT\nMB4XDTA4MDQxODE2MjQyMloXDTI4MDQxMzE2MjQyMlowRDEWMBQGA1UEAwwNQUNFRElDT00g\nUm9vdDEMMAoGA1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00xCzAJBgNVBAYTAkVTMIICIjAN\nBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA/5KV4WgGdrQsyFhIyv2AVClVYyT/kGWbEHV7\nw2rbYgIB8hiGtXxaOLHkWLn709gtn70yN78sFW2+tfQh0hOR2QetAQXW8713zl9CgQr5auOD\nAKgrLlUTY4HKRxx7XBZXehuDYAQ6PmXDzQHe3qTWDLqO3tkE7hdWIpuPY/1NFgu3e3eM+SW1\n0W2ZEi5PGrjm6gSSrj0RuVFCPYewMYWveVqc/udOXpJPQ/yrOq2lEiZmueIM15jO1FillUAK\nt0SdE3QrwqXrIhWYENiLxQSfHY9g5QYbm8+5eaA9oiM/Qj9r+hwDezCNzmzAv+YbX79nuIQZ\n1RXve8uQNjFiybwCq0Zfm/4aaJQ0PZCOrfbkHQl/Sog4P75n/TSW9R28MHTLOO7VbKvU/PQA\ntwBbhTIWdjPp2KOZnQUAqhbm84F9b32qhm2tFXTTxKJxqvQUfecyuB+81fFOvW8XAjnXDpVC\nOscAPukmYxHqC9FK/xidstd7LzrZlvvoHpKuE1XI2Sf23EgbsCTBheN3nZqk8wwRHQ3ItBTu\ntYJXCb8gWH8vIiPYcMt5bMlL8qkqyPyHK9caUPgn6C9D4zq92Fdx/c6mUlv53U3t5fZvie27\nk5x2IXXwkkwp9y+cAS7+UEaeZAwUswdbxcJzbPEHXEUkFDWug/FqTYl6+rPYLWbwNof1K1MC\nAwEAAaOBqjCBpzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKaz4SsrSbbXc6GqlPUB\n53NlTKxQMA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUprPhKytJttdzoaqU9QHnc2VMrFAw\nRAYDVR0gBD0wOzA5BgRVHSAAMDEwLwYIKwYBBQUHAgEWI2h0dHA6Ly9hY2VkaWNvbS5lZGlj\nb21ncm91cC5jb20vZG9jMA0GCSqGSIb3DQEBBQUAA4ICAQDOLAtSUWImfQwng4/F9tqgaHtP\nkl7qpHMyEVNEskTLnewPeUKzEKbHDZ3Ltvo/Onzqv4hTGzz3gvoFNTPhNahXwOf9jU8/kzJP\neGYDdwdY6ZXIfj7QeQCM8htRM5u8lOk6e25SLTKeI6RF+7YuE7CLGLHdztUdp0J/Vb77W7tH\n1PwkzQSulgUV1qzOMPPKC8W64iLgpq0i5ALudBF/TP94HTXa5gI06xgSYXcGCRZj6hitoocf\n8seACQl1ThCojz2GuHURwCRiipZ7SkXp7FnFvmuD5uHorLUwHv4FB4D54SMNUI8FmP8sX+g7\ntq3PgbUhh8oIKiMnMCArz+2UW6yyetLHKKGKC5tNSixthT8Jcjxn4tncB7rrZXtaAWPWkFtP\nF2Y9fwsZo5NjEFIqnxQWWOLcpfShFosOkYuByptZ+thrkQdlVV9SH686+5DdaaVbnG0OLLb6\nzqylfDJKZ0DcMDQj3dcEI2bw/FWAp/tmGYI1Z2JwOV5vx+qQQEQIHriy1tvuWacNGHk0vFQY\nXlPKNFHtRQrmjseCNj6nOGOpMCwXEGCSn1WHElkQwg9naRHMTh5+Spqtr0CodaxWkHS4oJyl\neW/c6RrIaQXpuvoDs3zk4E7Czp3otkYNbn5XOmeUwssfnHdKZ05phkOTOPu220+DkdRgfks+\nKzgHVZhepA==\n-----END CERTIFICATE-----\n", + "Microsec e-Szigno Root CA 2009": "-----BEGIN CERTIFICATE-----\nMIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYDVQQGEwJI\nVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMM\nHk1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0Bl\nLXN6aWduby5odTAeFw0wOTA2MTYxMTMwMThaFw0yOTEyMzAxMTMwMThaMIGCMQswCQYDVQQG\nEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNV\nBAMMHk1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5m\nb0BlLXN6aWduby5odTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG\n2KfgQvvPkd6mJviZpWNwrZuuyjNAfW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tc\ncbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG0IMZfcChEhyVbUr02MelTTMuhTlAdX4UfIASmFDH\nQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKApxn1ntxVUwOXewdI/5n7N4okxFnMUBBjjqqp\nGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm1HxdrtbCxkzlBQHZ7Vf8wSN5/PrIJIOV\n87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1+rUCAwEAAaOBgDB+MA8GA1UdEwEB/wQF\nMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAf\nBgNVHSMEGDAWgBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAbBgNVHREEFDASgRBpbmZvQGUtc3pp\nZ25vLmh1MA0GCSqGSIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0olZMEyL/azXm4Q5Dw\npL7v8u8hmLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfXI/OMn74dseGk\nddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775tyERzAMB\nVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c2Pm2G2JwCz02yULy\nMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5tHMN1Rq41Bab2XD0h7lbwyYIi\nLXpUq3DDfSJlgnCW\n-----END CERTIFICATE-----\n", + "E-Guven Kok Elektronik Sertifika Hizmet Saglayicisi": "-----BEGIN CERTIFICATE-----\nMIIDtjCCAp6gAwIBAgIQRJmNPMADJ72cdpW56tustTANBgkqhkiG9w0BAQUFADB1MQswCQYD\nVQQGEwJUUjEoMCYGA1UEChMfRWxla3Ryb25payBCaWxnaSBHdXZlbmxpZ2kgQS5TLjE8MDoG\nA1UEAxMzZS1HdXZlbiBLb2sgRWxla3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhZ2xheWlj\naXNpMB4XDTA3MDEwNDExMzI0OFoXDTE3MDEwNDExMzI0OFowdTELMAkGA1UEBhMCVFIxKDAm\nBgNVBAoTH0VsZWt0cm9uaWsgQmlsZ2kgR3V2ZW5saWdpIEEuUy4xPDA6BgNVBAMTM2UtR3V2\nZW4gS29rIEVsZWt0cm9uaWsgU2VydGlmaWthIEhpem1ldCBTYWdsYXlpY2lzaTCCASIwDQYJ\nKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMMSIJ6wXgBljU5Gu4Bc6SwGl9XzcslwuedLZYDB\nS75+PNdUMZTe1RK6UxYC6lhj71vY8+0qGqpxSKPcEC1fX+tcS5yWCEIlKBHMilpiAVDV6wlT\nL/jDj/6z/P2douNffb7tC+Bg62nsM+3YjfsSSYMAyYuXjDtzKjKzEve5TfL0TW3H5tYmNwjy\n2f1rXKPlSFxYvEK+A1qBuhw1DADT9SN+cTAIJjjcJRFHLfO6IxClv7wC90Nex/6wN1CZew+T\nzuZDLMN+DfIcQ2Zgy2ExR4ejT669VmxMvLz4Bcpk9Ok0oSy1c+HCPujIyTQlCFzz7abHlJ+t\niEMl1+E5YP6sOVkCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w\nHQYDVR0OBBYEFJ/uRLOU1fqRTy7ZVZoEVtstxNulMA0GCSqGSIb3DQEBBQUAA4IBAQB/X7lT\nW2M9dTLn+sR0GstG30ZpHFLPqk/CaOv/gKlR6D1id4k9CnU58W5dF4dvaAXBlGzZXd/aslnL\npRCKysw5zZ/rTt5S/wzw9JKp8mxTq5vSR6AfdPebmvEvFZ96ZDAYBzwqD2fK/A+JYZ1lpTzl\nvBNbCNvj/+27BrtqBrF6T2XGgv0enIu1De5Iu7i9qgi0+6N8y5/NkHZchpZ4Vwpm+Vganf2X\nKWDeEaaQHBkc7gGWIjQ0LpH5t8Qn0Xvmv/uARFoW5evg1Ao4vOSR49XrXMGs3xtqfJ7lddK2\nl4fbzIcrQzqECK+rPNv3PGYxhrCdU3nt+CPeQuMtgvEP5fqX\n-----END CERTIFICATE-----\n", + "GlobalSign Root CA - R3": "-----BEGIN CERTIFICATE-----\nMIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMX\nR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMT\nCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQL\nExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UE\nAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5Bngi\nFvXAg7aEyiie/QV2EcWtiHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0M\nK66X17YUhhB5uzsTgHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL\n0gRgykmmKPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd\nQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613\nt2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQD\nAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0G\nCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7lgAJQayzE4aGKAczymvmdLm6AC2u\npArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdW\nPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0\n095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJr\nlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH\nWD9f\n-----END CERTIFICATE-----\n", + "TC TrustCenter Universal CA III": "-----BEGIN CERTIFICATE-----\nMIID4TCCAsmgAwIBAgIOYyUAAQACFI0zFQLkbPQwDQYJKoZIhvcNAQEFBQAwezELMAkGA1UE\nBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNVBAsTG1RDIFRydXN0\nQ2VudGVyIFVuaXZlcnNhbCBDQTEoMCYGA1UEAxMfVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2Fs\nIENBIElJSTAeFw0wOTA5MDkwODE1MjdaFw0yOTEyMzEyMzU5NTlaMHsxCzAJBgNVBAYTAkRF\nMRwwGgYDVQQKExNUQyBUcnVzdENlbnRlciBHbWJIMSQwIgYDVQQLExtUQyBUcnVzdENlbnRl\nciBVbml2ZXJzYWwgQ0ExKDAmBgNVBAMTH1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQSBJ\nSUkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDC2pxisLlxErALyBpXsq6DFJmz\nNEubkKLF5+cvAqBNLaT6hdqbJYUtQCggbergvbFIgyIpRJ9Og+41URNzdNW88jBmlFPAQDYv\nDIRlzg9uwliT6CwLOunBjvvya8o84pxOjuT5fdMnnxvVZ3iHLX8LR7PH6MlIfK8vzArZQe+f\n/prhsq75U7Xl6UafYOPfjdN/+5Z+s7Vy+EutCHnNaYlAJ/Uqwa1D7KRTyGG299J5KmcYdkht\nWyUB0SbFt1dpIxVbYYqt8Bst2a9c8SaQaanVDED1M4BDj5yjdipFtK+/fz6HP3bFzSreIMUW\nWMv5G/UPyw0RUmS40nZid4PxWJ//AgMBAAGjYzBhMB8GA1UdIwQYMBaAFFbn4VslQ4Dg9ozh\ncbyO5YAvxEjiMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRW\n5+FbJUOA4PaM4XG8juWAL8RI4jANBgkqhkiG9w0BAQUFAAOCAQEAg8ev6n9NCjw5sWi+e22J\nLumzCecYV42FmhfzdkJQEw/HkG8zrcVJYCtsSVgZ1OK+t7+rSbyUyKu+KGwWaODIl0YgoGhn\nYIg5IFHYaAERzqf2EQf27OysGh+yZm5WZ2B6dF7AbZc2rrUNXWZzwCUyRdhKBgePxLcHsU0G\nDeGl6/R1yrqc0L2z0zIkTO5+4nYES0lT2PLpVDP85XEfPRRclkvxOvIAu2y0+pZVCIgJwcyR\nGSmwIC3/yzikQOEXvnlhgP8HA4ZMTnsGnxGGjYnuJ8Tb4rwZjgvDwxPHLQNjO9Po5KIqwoII\nlBZU8O8fJ5AluA0OKBtHd0e9HKgl8ZS0Zg==\n-----END CERTIFICATE-----\n", + "Autoridad de Certificacion Firmaprofesional CIF A62634068": "-----BEGIN CERTIFICATE-----\nMIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UEBhMCRVMx\nQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwg\nQ0lGIEE2MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEyMzEwODM4MTVaMFExCzAJBgNV\nBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zl\nc2lvbmFsIENJRiBBNjI2MzQwNjgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDK\nlmuO6vj78aI14H9M2uDDUtd9thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOS\nL/UR5GLXMnE42QQMcas9UX4PB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9\nqFD0sefGL9ItWY16Ck6WaVICqjaY7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15i\nNA9wBj4gGFrO93IbJWyTdBSTo3OxDqqHECNZXyAFGUftaI6SEspd/NYrspI8IM/hX68gvqB2\nf3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyIplD9amML9ZMWGxmPsu2bm8mQ9QEM3xk9Dz44\nI8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctXMbScyJCyZ/QYFpM6/EfY0XiWMR+6Kwxf\nXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirjaEbsXLZmdEyRG98Xi2J+Of8ePdG1asuhy\n9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/TKI8xWVvTyQKmtFLKbpf7Q8UIJm+K9Lv9nyiqDdVF\n8xM6HdjAeI9BZzwelGSuewvF6NkBiDkal4ZkQdU7hwxu+g/GvUgUvzlN1J5Bto+WHWOWk9mV\nBngxaJ43BjuAiUVhOSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1UdEwEB/wQIMAYBAf8C\nAQEwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNHDhpkLzCBpgYD\nVR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZpcm1hcHJv\nZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBvACAAZABlACAAbABh\nACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBlAGwAbwBuAGEAIAAwADgAMAAx\nADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF661LJLWhAqvdpYhKsg9VSytXjDvlMd3+\nxDLx51tkljYyGOylMnfX40S2wBEqgLk9am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5x\nhOW1//qkR71kMrv2JYSiJ0L1ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5\neTSSPi5E6PaPT481PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5Fl\nClrD2VQS3a/DTg4fJl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5k\nSeTy36LssUzAKh3ntLFlosS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF3dvd6qJ2\ngHN99ZwExEWN57kci57q13XRcrHedUTnQn3iV2t93Jm8PYMo6oCTjcVMZcFwgbg4/EMxsvYD\nNEeyrPsiBsse3RdHHF9mudMaotoRsaS8I8nkvof/uZS2+F0gStRf571oe2XyFR7SOqkt6dhr\nJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTDKCOM/iczQ0CgFzzr6juwcqajuUpLXhZI9LK8yIyS\nxZ2frHI2vDSANGupi5LAuBft7HZT9SQBjLMi6Et8Vcad+qMUu2WFbm5PEn4KPJ2V\n-----END CERTIFICATE-----\n", + "Izenpe.com": "-----BEGIN CERTIFICATE-----\nMIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4MQswCQYD\nVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wHhcN\nMDcxMjEzMTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYDVQQGEwJFUzEUMBIGA1UECgwL\nSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4IC\nDwAwggIKAoICAQDJ03rKDx6sp4boFmVqscIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5Tz\ncqQsRNiekpsUOqHnJJAKClaOxdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpz\nbm3benhB6QiIEn6HLmYRY2xU+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJ\nGjMxCrFXuaOKmMPsOzTFlUFpfnXCPCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQD\nyCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxTOTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+JrUV86f8\nhBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbKF7jJeodWLBoBHmy+E60QrLUk9TiRodZL2vG7\n0t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK0GqfvEyNBjNaooXlkDWgYlwWTvDjovoD\nGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8Lhij+0rnq49qlw0dpEuDb8PYZi+17cNcC\n1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIBQFqNeb+Lz0vPqhbBleStTIo+F5HUsWLlguWABKQD\nfo2/2n+iD5dPDNMN+9fR5XJ+HMh3/1uaD7euBUbl8agW7EekFwIDAQABo4H2MIHzMIGwBgNV\nHREEgagwgaWBD2luZm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+SVpFTlBFIFMuQS4g\nLSBDSUYgQTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBGNjIgUzgxQzBB\nBgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAxMCBWaXRv\ncmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE\nFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUAA4ICAQB4pgwWSp9MiDrAyw6l\nFn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWblaQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9\nfbgakEyrkgPH7UIBzg/YsfqikuFgba56awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJO\nubv5vr8qhT/AQKM6WfxZSzwoJNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m\n5hzkQiCeR7Csg1lwLDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Py\ne6kfLqCTVyvehQP5aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGk\nLhObNA5me0mrZJfQRsN5nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJbUjWumDqt\nujWTI6cfSN01RpiyEGjkpTHCClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/QnMFlEPVjjxOAToZ\npR9GTnfQXeWBIiGH/pR9hNiTrdZoQ0iy2+tzJOeRf1SktoA+naM8THLCV8Sg1Mw4J87VBp6i\nSNnpn86CcDaTmjvfliHjWbcM2pE38P1ZWrOZyGlsQyYBNWNgVYkDOnXYukrZVP/u3oDYLdE4\n1V4tC5h9Pmzb/CaIxw==\n-----END CERTIFICATE-----\n", + "Chambers of Commerce Root - 2008": "-----BEGIN CERTIFICATE-----\nMIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYDVQQGEwJF\nVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZp\ncm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1l\ncmZpcm1hIFMuQS4xKTAnBgNVBAMTIENoYW1iZXJzIG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4\nMB4XDTA4MDgwMTEyMjk1MFoXDTM4MDczMTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYD\nVQQHEzpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29t\nL2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEg\nUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0G\nCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW928sNRHI+\nJrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKAXuFixrYp4YFs8r/lfTJqVKAyGVn+H4vXPWCG\nhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorjh40G072QDuKZoRuGDtqaCrsLYVAGUvGe\nf3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR5gN/ikilTWh1uem8nk4ZcfUyS5xtYBkL\n+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfLZEFHcpOrUMPrCXZkNNI5t3YRCQ12RcSprj1qr7V9\nZS+UWBDsXHyvfuK2GNnQm05aSd+pZgvMPMZ4fKecHePOjlO+Bd5gD2vlGts/4+EhySnB8esH\nnFIbAURRPHsl18TlUlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331lubKgdaX8ZSD6e2w\nsWsSaR6s+12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ0wlf2eOKNcx5\nWk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhjya6BXBg1\n4JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAxhduub+84Mxh2EQID\nAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNVHQ4EFgQU+SSsD7K1+HnA+mCI\nG8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1+HnA+mCIG8TZTQKeFxmhgbSkgbEwga4x\nCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQg\nd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNV\nBAoTEkFDIENhbWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2Ug\nUm9vdCAtIDIwMDiCCQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRV\nHSAAMCowKAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZI\nhvcNAQEFBQADggIBAJASryI1wqM58C7e6bXpeHxIvj99RZJe6dqxGfwWPJ+0W2aeaufDuV2I\n6A+tzyMP3iU6XsxPpcG1Lawk0lgH3qLPaYRgM+gQDROpI9CF5Y57pp49chNyM/WqfcZjHwj0\n/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbURWpGqOt1glanq6B8aBMz9p0w8G8nOSQjKpD9kCk1\n8pPfNKXG9/jvjA9iSnyu0/VU+I22mlaHFoI6M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rc\nf+g769HsJtg1pDDFOqxXnrN2pSB7+R5KBWIBpih1YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+K\nMjNbMMeJL0eYD6MDxvbxrN8y8NmBGuScvfaAFPDRLLmF9dijscilIeUcE5fuDr3fKanvNFNb\n0+RqE4QGtjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcKzBIKinmwPQN/aUv0NCB9szTq\njktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvGnrDQWzilm1DefhiYtUU7\n9nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRgOGcEMeyP84LG3rlV\n8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZd0jQ\n-----END CERTIFICATE-----\n", + "Global Chambersign Root - 2008": "-----BEGIN CERTIFICATE-----\nMIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYDVQQGEwJF\nVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZp\ncm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1l\ncmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODAe\nFw0wODA4MDExMjMxNDBaFw0zODA3MzExMjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UE\nBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9h\nZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu\nQS4xJzAlBgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZI\nhvcNAQEBBQADggIPADCCAgoCggIBAMDfVtPkOpt2RbQT2//BthmLN0EYlVJH6xedKYiONWwG\nMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXfXjaOcNFccUMd2drvXNL7G706tcuto8xEpw2u\nIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0ZJJ0YPP2zxhPYLIj0Mc7zmFLmY/CDNBA\nspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4ddPB/gBVsIdU6CeQNR1MM62X/JcumIS/\nLMmjv9GYERTtY/jKmIhYF5ntRQOXfjyGHoiMvvKRhI9lNNgATH23MRdaKXoKGCQwoze1eqkB\nfSbW+Q6OWfH9GzO1KTsXO0G2Id3UwD2ln58fQ1DJu7xsepeY7s2MH/ucUa6LcL0nn3HAa6x9\nkGbo1106DbDVwo3VyJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfeOx2YItaswTXbo6Al\n/3K1dh3ebeksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSFHTynyQbehP9r\n6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9JhwZG7SMA0\nj0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsogzCtLkykPAgMBAAGj\nggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQWBBS5CcqcHtvTbDprru1U8VuT\nBjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDprru1U8VuTBjUuXqGBsqSBrzCBrDELMAkG\nA1UEBhMCRVUxQzBBBgNVBAcTOk1hZHJpZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cu\nY2FtZXJmaXJtYS5jb20vYWRkcmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMS\nQUMgQ2FtZXJmaXJtYSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAt\nIDIwMDiCCQDJzdPp1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCow\nKAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEF\nBQADggIBAICIf3DekijZBZRG/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZUohwEurdPfWbU1Rv\n4WCiqAm57OtZfMY18dwY6fFn5a+6ReAJ3spED8IXDneRRXozX1+WLGiLwUePmJs9wOzL9dWC\nkoQ10b42OFZyMVtHLaoXpGNR6woBrX/sdZ7LoR/xfxKxueRkf2fWIyr0uDldmOghp+G9PUIa\ndJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVza2Mg9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJ\njUhjxsYjV5KTXjXBjfkK9yydYhz2rXzdpjEetrHHfoUm+qRqtdpjMNHvkzeyZi99Bffnt0uY\nlDXA2TopwZ2yUDMdSqlapskD7+3056huirRXhOukP9DuqqqHW2Pok+JrqNS4cnhrG+055F3L\nm6qH1U9OAP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETrP3iZ8ntxPjzxmKfFGBI/5rso\nM0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVqc5iJWzouE4gev8CSlDQb\n4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z09gwzxMNTxXJhLyn\nSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B\n-----END CERTIFICATE-----\n", + "Go Daddy Root Certificate Authority - G2": "-----BEGIN CERTIFICATE-----\nMIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMxEDAOBgNV\nBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHkuY29t\nLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAt\nIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgYMxCzAJBgNVBAYTAlVTMRAw\nDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5\nLmNvbSwgSW5jLjExMC8GA1UEAxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3Jp\ndHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3\ngElY6SKDE6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH\n/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7RnwyDfMAZiLI\njWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVhGkSBjCypQ5Yj36w6\ngZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGRtDtwKj9useiciAF9n9T521Nt\nYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO\nBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3\nDQEBCwUAA4IBAQCZ21151fmXWWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC\n2gV7+AJ1uP2lsdeu9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95\nkTXWXwTrgIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo\n2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPOLPAvTK33\nsefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI4uJEvlz36hz1\n-----END CERTIFICATE-----\n", + "Starfield Root Certificate Authority - G2": "-----BEGIN CERTIFICATE-----\nMIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMxEDAOBgNV\nBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBU\nZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVsZCBSb290IENlcnRpZmljYXRl\nIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJ\nBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYD\nVQQKExxTdGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQg\nUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEP\nADCCAQoCggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg\nnLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1HOZ/5FSu\nS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/NHwtjuzqd+/x5AJhh\ndM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dNdloedl40wOiWVpmKs/B/pM29\n3DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0HZbUJtQIBFnQmA4O5t78w+wfkPECAwEA\nAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n\n2TB/xH1oo2Kooc6rB1snMA0GCSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWU\nXuEok21iXQnCoKjUsHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox\n9g61DLu34jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg\n8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/KpL/QlwVK\nvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1mMpYjn0q7pBZc2T5\nNnReJaH1ZgUufzkVqSr7UIuOhWn0\n-----END CERTIFICATE-----\n", + "Starfield Services Root Certificate Authority - G2": "-----BEGIN CERTIFICATE-----\nMIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNV\nBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBU\nZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENl\ncnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1\nOVowgZgxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNk\nYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJT\ndGFyZmllbGQgU2VydmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw\nDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p\nOsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm28xpWriu2\ndBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1KTs9DkTvnVtYAcMtS\n7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufehRhJfGZOozptqbXuNC66DQO4\nM99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk6mFBrMnUVN+HL8cisibMn1lUaJ/8viov\nxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC\nAQYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBL\nNqaEd2ndOxmfZyMIbw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynV\nv/heyNXBve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z\nqwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkdiEDPfUYd\n/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn0q23KXB56jzaYyWf\n/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCNsSi6\n-----END CERTIFICATE-----\n", + "AffirmTrust Commercial": "-----BEGIN CERTIFICATE-----\nMIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCVVMx\nFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFs\nMB4XDTEwMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDELMAkGA1UEBhMCVVMxFDASBgNV\nBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMIIBIjAN\nBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTW\nzsO3qyxPxkEylFf6EqdbDuKPHx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U\n6Mje+SJIZMblq8Yrba0F8PrVC8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNA\nFxHUdPALMeIrJmqbTFeurCA+ukV6BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1\nyHp52UKqK39c/s4mT6NmgTWvRLpUHhwwMmWd5jyTXlBOeuM61G7MGvv50jeuJCqrVwMiKA1J\ndX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNVHQ4EFgQUnZPGU4teyq8/nx4P5ZmVvCT2lI8w\nDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggEBAFis\n9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYGXUPGhi4+c7ImfU+TqbbEKpqrIZcUsd6M\n06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNjvbz4YYCanrHOQnDiqX0GJX0nof5v7LMeJNrjS1Ua\nADs1tDvZ110w/YETifLCBivtZ8SOyUOyXGsViQK8YvxO8rUzqrJv0wqiUOP2O+guRMLbZjip\nM1ZI8W0bM40NjD9gN53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0khsUlHRUe072o0EclN\nmsxZt9YCnlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8=\n-----END CERTIFICATE-----\n", + "AffirmTrust Networking": "-----BEGIN CERTIFICATE-----\nMIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UEBhMCVVMx\nFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5n\nMB4XDTEwMDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDELMAkGA1UEBhMCVVMxFDASBgNV\nBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMIIBIjAN\nBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWRE\nZY9nZOIG41w3SfYvm4SEHi3yYJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ\n/Ls6rnla1fTWcbuakCNrmreIdIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXL\nviRmVSRLQESxG9fhwoXA3hA/Pe24/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp\n6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gbh+0t+nvujArjqWaJGctB+d1ENmHP4ndGyH329JKB\nNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNVHQ4EFgQUBx/S55zawm6iQLSwelAQUHTEyL0w\nDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBAIlX\nshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfOtDIuUFUaNU52Q3Eg75N3ThVwLofDwR1t\n3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzuQY0x2+c06lkh1QF612S4ZDnNye2v7UsDSKegmQGA\n3GWjNq5lWUhPgkvIZfFXHeVZLgo/bNjR9eUJtGxUAArgFU2HdW23WJZa3W3SAKD0m0i+wzek\nujbgfIeFlxoVot4uolu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9/ZFvgrG+CJPbFEfx\nojfHRZ48x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s=\n-----END CERTIFICATE-----\n", + "AffirmTrust Premium": "-----BEGIN CERTIFICATE-----\nMIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UEBhMCVVMx\nFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMB4X\nDTEwMDEyOTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkGA1UEBhMCVVMxFDASBgNVBAoM\nC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMIICIjANBgkqhkiG\n9w0BAQEFAAOCAg8AMIICCgKCAgEAxBLfqV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64t\nb+eT2TZwamjPjlGjhVtnBKAQJG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/\n0qRY7iZNyaqoe5rZ+jjeRFcV5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/\nK+k8rNrSs8PhaJyJ+HoAVt70VZVs+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5\nHMQxK9VfvFMSF5yZVylmd2EhMQcuJUmdGPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d770O/Nbua\n2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5Rp9EixAqnOEhss/n/fauGV+O61oV4d7pD6kh/\n9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NIS+LI+H+SqHZGnEJlPqQewQcDWkYtuJfz\nt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S5u046uwBHjxIVkkJx0w3AJ6IDsBz4W9m\n6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4IaC1nEWTJ3s7xgaVY5/bQGeyzWZDbZvUjthB9+pSKP\nKrhC9IK31FOQeE4tGv2Bb0TXOwF0lkLgAOIua+rF7nKsu7/+6qqo+Nz2snmKtmcCAwEAAaNC\nMEAwHQYDVR0OBBYEFJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB/wQFMAMBAf8wDgYD\nVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByvMiPIs0laUZx2\nKI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMgNt58D2kT\niKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B8OWycvpEgjNC6C1Y\n91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQMKSOyARiqcTtNd56l+0OOF6S\nL5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc0jlzCFfemQa0W50QBuHCAKi4HEoCChTQ\nwUHK+4w1IX2COPKpVJEZNZOUbWo6xbLQu4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFo\noC8k4gmVBtWVyuEklut89pMFu+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5Yw\nH2AG7hsj/oFgIxpHYoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/\nqzWaVYa8GKa1qF60g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaO\nRtGdFNrHF+QFlozEJLUbzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6eKeC2uAlo\nGRwYQw==\n-----END CERTIFICATE-----\n", + "AffirmTrust Premium ECC": "-----BEGIN CERTIFICATE-----\nMIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMCVVMxFDAS\nBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQcmVtaXVtIEVDQzAe\nFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJBgNVBAYTAlVTMRQwEgYDVQQK\nDAtBZmZpcm1UcnVzdDEgMB4GA1UEAwwXQWZmaXJtVHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcq\nhkjOPQIBBgUrgQQAIgNiAAQNMF4bFZ0D0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQU\nX+iOGasvLkjmrBhDeKzQN8O9ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR\n4ptlKymjQjBAMB0GA1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTAD\nAQH/MA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs\naobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6Iflc9nF9C\na/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ==\n-----END CERTIFICATE-----\n", + "Certum Trusted Network CA": "-----BEGIN CERTIFICATE-----\nMIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBMMSIwIAYD\nVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlm\naWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBUcnVzdGVkIE5ldHdvcmsgQ0Ew\nHhcNMDgxMDIyMTIwNzM3WhcNMjkxMjMxMTIwNzM3WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UE\nChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmlj\nYXRpb24gQXV0aG9yaXR5MSIwIAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIB\nIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/\n91sts1rHUV+rpDKmYYe2bg+G0jACl/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LM\nTXPb865Px1bVWqeWifrzq2jUI4ZZJ88JJ7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVUBBvXQzmt\nVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4fOQtf/WsX+sWn7Et0brMkUJ3TCXJkDhv2/DM\n+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0cvW0QM8xAcPs3hEtF10fuFDRXhmnad4H\nMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQI\nds3LB/8k9sXN7buQvOKEN0Z19zAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEB\nAKaorSLOAT2mo/9i0Eidi15ysHhE49wcrwn9I0j6vSrEuVUEtRCjjSfeC4Jj0O7eDDd5QVsi\nsrCaQVymcODU0HfLI9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1mS1FhIrlQgnXdAIv\n94nYmem8J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5ajZt3hrvJBW8qY\nVoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI03YnnZot\nBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw=\n-----END CERTIFICATE-----\n", + "Certinomis - Autorité Racine": "-----BEGIN CERTIFICATE-----\nMIIFnDCCA4SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJGUjETMBEGA1UE\nChMKQ2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxJjAkBgNVBAMMHUNlcnRp\nbm9taXMgLSBBdXRvcml0w6kgUmFjaW5lMB4XDTA4MDkxNzA4Mjg1OVoXDTI4MDkxNzA4Mjg1\nOVowYzELMAkGA1UEBhMCRlIxEzARBgNVBAoTCkNlcnRpbm9taXMxFzAVBgNVBAsTDjAwMDIg\nNDMzOTk4OTAzMSYwJAYDVQQDDB1DZXJ0aW5vbWlzIC0gQXV0b3JpdMOpIFJhY2luZTCCAiIw\nDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJ2Fn4bT46/HsmtuM+Cet0I0VZ35gb5j2CN2\nDpdUzZlMGvE5x4jYF1AMnmHawE5V3udauHpOd4cN5bjr+p5eex7Ezyh0x5P1FMYiKAT5kcOr\nJ3NqDi5N8y4oH3DfVS9O7cdxbwlyLu3VMpfQ8Vh30WC8Tl7bmoT2R2FFK/ZQpn9qcSdIhDWe\nrP5pqZ56XjUl+rSnSTV3lqc2W+HN3yNw2F1MpQiD8aYkOBOo7C+ooWfHpi2GR+6K/OybDnT0\nK0kCe5B1jPyZOQE51kqJ5Z52qz6WKDgmi92NjMD2AR5vpTESOH2VwnHu7XSu5DaiQ3XV8QCb\n4uTXzEIDS3h65X27uK4uIJPT5GHfceF2Z5c/tt9qc1pkIuVC28+BA5PY9OMQ4HL2AHCs8MF6\nDwV/zzRpRbWT5BnbUhYjBYkOjUjkJW+zeL9i9Qf6lSTClrLooyPCXQP8w9PlfMl1I9f09bze\n5N/NgL+RiH2nE7Q5uiy6vdFrzPOlKO1Enn1So2+WLhl+HPNbxxaOu2B9d2ZHVIIAEWBsMsGo\nOBvrbpgT1u449fCfDu/+MYHB0iSVL1N6aaLwD4ZFjliCK0wi1F6g530mJ0jfJUaNSih8hp75\nmxpZuWW/Bd22Ql095gBIgl4g9xGC3srYn+Y3RyYe63j3YcNBZFgCQfna4NH4+ej9Uji29Ynf\nAgMBAAGjWzBZMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBQN\njLZh2kS40RR9w759XkjwzspqsDAXBgNVHSAEEDAOMAwGCiqBegFWAgIAAQEwDQYJKoZIhvcN\nAQEFBQADggIBACQ+YAZ+He86PtvqrxyaLAEL9MW12Ukx9F1BjYkMTv9sov3/4gbIOZ/xWqnd\nIlgVqIrTseYyCYIDbNc/CMf4uboAbbnW/FIyXaR/pDGUu7ZMOH8oMDX/nyNTt7buFHAAQCva\nR6s0fl6nVjBhK4tDrP22iCj1a7Y+YEq6QpA0Z43q619FVDsXrIvkxmUP7tCMXWY5zjKn2BCX\nwH40nJ+U8/aGH88bc62UeYdocMMzpXDn2NU4lG9jeeu/Cg4I58UvD0KgKxRA/yHgBcUn4YQR\nE7rWhh1BCxMjidPJC+iKunqjo3M3NYB9Ergzd0A4wPpeMNLytqOx1qKVl4GbUu1pTP+A5FPb\nVFsDbVRfsbjvJL1vnxHDx2TCDyhihWZeGnuyt++uNckZM6i4J9szVb9o4XVIRFb7zdNIu0eJ\nOqxp9YDG5ERQL1TEqkPFMTFYvZbF6nVsmnWxTfj3l/+WFvKXTej28xH5On2KOG4Ey+HTRRWq\npdEdnV1j6CTmNhTih60bWfVEm/vXd3wfAXBioSAaosUaKPQhA+4u2cGA6rnZgtZbdsLLO7XS\nAPCjDuGtbkD326C00EauFddEwk01+dIL8hf2rGbVJLJP0RyZwG71fet0BLj5TXcJ17TPBzAJ\n8bgAVtkXFhYKK4bfjwEZGuW7gmP/vgt2Fl43N+bYdJeimUV5\n-----END CERTIFICATE-----\n", + "Root CA Generalitat Valenciana": "-----BEGIN CERTIFICATE-----\nMIIGizCCBXOgAwIBAgIEO0XlaDANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJFUzEfMB0G\nA1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJR1ZBMScwJQYDVQQD\nEx5Sb290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwHhcNMDEwNzA2MTYyMjQ3WhcNMjEw\nNzAxMTUyMjQ3WjBoMQswCQYDVQQGEwJFUzEfMB0GA1UEChMWR2VuZXJhbGl0YXQgVmFsZW5j\naWFuYTEPMA0GA1UECxMGUEtJR1ZBMScwJQYDVQQDEx5Sb290IENBIEdlbmVyYWxpdGF0IFZh\nbGVuY2lhbmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGKqtXETcvIorKA3Qd\nyu0togu8M1JAJke+WmmmO3I2F0zo37i7L3bhQEZ0ZQKQUgi0/6iMweDHiVYQOTPvaLRfX9pt\nI6GJXiKjSgbwJ/BXufjpTjJ3Cj9BZPPrZe52/lSqfR0grvPXdMIKX/UIKFIIzFVd0g/bmoGl\nu6GzwZTNVOAydTGRGmKy3nXiz0+J2ZGQD0EbtFpKd71ng+CT516nDOeB0/RSrFOyA8dEJvt5\n5cs0YFAQexvba9dHq198aMpunUEDEO5rmXteJajCq+TA81yc477OMUxkHl6AovWDfgzWyoxV\njr7gvkkHD6MkQXpYHYTqWBLI4bft75PelAgxAgMBAAGjggM7MIIDNzAyBggrBgEFBQcBAQQm\nMCQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9vY3NwLnBraS5ndmEuZXMwEgYDVR0TAQH/BAgwBgEB\n/wIBAjCCAjQGA1UdIASCAiswggInMIICIwYKKwYBBAG/VQIBADCCAhMwggHoBggrBgEFBQcC\nAjCCAdoeggHWAEEAdQB0AG8AcgBpAGQAYQBkACAAZABlACAAQwBlAHIAdABpAGYAaQBjAGEA\nYwBpAPMAbgAgAFIAYQDtAHoAIABkAGUAIABsAGEAIABHAGUAbgBlAHIAYQBsAGkAdABhAHQA\nIABWAGEAbABlAG4AYwBpAGEAbgBhAC4ADQAKAEwAYQAgAEQAZQBjAGwAYQByAGEAYwBpAPMA\nbgAgAGQAZQAgAFAAcgDhAGMAdABpAGMAYQBzACAAZABlACAAQwBlAHIAdABpAGYAaQBjAGEA\nYwBpAPMAbgAgAHEAdQBlACAAcgBpAGcAZQAgAGUAbAAgAGYAdQBuAGMAaQBvAG4AYQBtAGkA\nZQBuAHQAbwAgAGQAZQAgAGwAYQAgAHAAcgBlAHMAZQBuAHQAZQAgAEEAdQB0AG8AcgBpAGQA\nYQBkACAAZABlACAAQwBlAHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAHMAZQAgAGUAbgBjAHUA\nZQBuAHQAcgBhACAAZQBuACAAbABhACAAZABpAHIAZQBjAGMAaQDzAG4AIAB3AGUAYgAgAGgA\ndAB0AHAAOgAvAC8AdwB3AHcALgBwAGsAaQAuAGcAdgBhAC4AZQBzAC8AYwBwAHMwJQYIKwYB\nBQUHAgEWGWh0dHA6Ly93d3cucGtpLmd2YS5lcy9jcHMwHQYDVR0OBBYEFHs100DSHHgZZu90\nECjcPk+yeAT8MIGVBgNVHSMEgY0wgYqAFHs100DSHHgZZu90ECjcPk+yeAT8oWykajBoMQsw\nCQYDVQQGEwJFUzEfMB0GA1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMG\nUEtJR1ZBMScwJQYDVQQDEx5Sb290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmGCBDtF5Wgw\nDQYJKoZIhvcNAQEFBQADggEBACRhTvW1yEICKrNcda3FbcrnlD+laJWIwVTAEGmiEi8YPyVQ\nqHxK6sYJ2fR1xkDar1CdPaUWu20xxsdzCkj+IHLtb8zog2EWRpABlUt9jppSCS/2bxzkoXHP\njCpaF3ODR00PNvsETUlR4hTJZGH71BTg9J63NI8KJr2XXPR5OkowGcytT6CYirQxlyric21+\neLj4iIlPsSKRZEv1UN4D2+XFducTZnV+ZfsBn5OHiJ35Rld8TWCvmHMTI6QgkYH60GFmuH3R\nr9ZvHmw96RH9qfmCIoaZM3Fa6hlXPZHNqcCjbgcTpsnt+GijnsNacgmHKNHEc8RzGF9QdRYx\nn7fofMM=\n-----END CERTIFICATE-----\n", + "A-Trust-nQual-03": "-----BEGIN CERTIFICATE-----\nMIIDzzCCAregAwIBAgIDAWweMA0GCSqGSIb3DQEBBQUAMIGNMQswCQYDVQQGEwJBVDFIMEYG\nA1UECgw/QS1UcnVzdCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBpbSBlbGVrdHIuIERh\ndGVudmVya2VociBHbWJIMRkwFwYDVQQLDBBBLVRydXN0LW5RdWFsLTAzMRkwFwYDVQQDDBBB\nLVRydXN0LW5RdWFsLTAzMB4XDTA1MDgxNzIyMDAwMFoXDTE1MDgxNzIyMDAwMFowgY0xCzAJ\nBgNVBAYTAkFUMUgwRgYDVQQKDD9BLVRydXN0IEdlcy4gZi4gU2ljaGVyaGVpdHNzeXN0ZW1l\nIGltIGVsZWt0ci4gRGF0ZW52ZXJrZWhyIEdtYkgxGTAXBgNVBAsMEEEtVHJ1c3QtblF1YWwt\nMDMxGTAXBgNVBAMMEEEtVHJ1c3QtblF1YWwtMDMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw\nggEKAoIBAQCtPWFuA/OQO8BBC4SAzewqo51ru27CQoT3URThoKgtUaNR8t4j8DRE/5TrzAUj\nlUC5B3ilJfYKvUWG6Nm9wASOhURh73+nyfrBJcyFLGM/BWBzSQXgYHiVEEvc+RFZznF/QJuK\nqiTfC0Li21a8StKlDJu3Qz7dg9MmEALP6iPESU7l0+m0iKsMrmKS1GWH2WrX9IWf5DMiJaXl\nyDO6w8dB3F/GaswADm0yqLaHNgBid5seHzTLkDx4iHQF63n1k3Flyp3HaxgtPVxO59X4PzF9\nj4fsCiIvI+n+u33J4PTs63zEsMMtYrWacdaxaujs2e3Vcuy+VwHOBVWf3tFgiBCzAgMBAAGj\nNjA0MA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0OBAoECERqlWdVeRFPMA4GA1UdDwEB/wQEAwIB\nBjANBgkqhkiG9w0BAQUFAAOCAQEAVdRU0VlIXLOThaq/Yy/kgM40ozRiPvbY7meIMQQDbwvU\nB/tOdQ/TLtPAF8fGKOwGDREkDg6lXb+MshOWcdzUzg4NCmgybLlBMRmrsQd7TZjTXLDR8KdC\noLXEjq/+8T/0709GAHbrAvv5ndJAlseIOrifEXnzgGWovR/TeIGgUUw3tKZdJXDRZslo+S4R\nFGjxVJgIrCaSD96JntT6s3kr0qN51OyLrIdTaEJMUVF0HhsnLuP1Hyl0Te2v9+GSmYHovjrH\nF1D2t8b8m7CKa9aIA5GPBnc6hQLdmNVDeD/GMBWsm2vLV7eJUYs66MmEDNuxUCAKGkq6ahq9\n7BvIxYSazQ==\n-----END CERTIFICATE-----\n", + "TWCA Root Certification Authority": "-----BEGIN CERTIFICATE-----\nMIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzESMBAGA1UE\nCgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2Vy\ndGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMzWhcNMzAxMjMxMTU1OTU5WjBf\nMQswCQYDVQQGEwJUVzESMBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSow\nKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3\nDQEBAQUAA4IBDwAwggEKAoIBAQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bi\nhSX0NXIP+FPQQeFEAcK0HMMxQhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQ\nsIBct+HHK3XLfJ+utdGdIzdjp9xCoi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeX\nRfwZVzsrb+RH9JlF/h3x+JejiB03HFyP4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/zrX2SYgJb\nKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1ry+UPizgN7gr8/g+YnzAx3WxSZfmLgb4i4RxY\nA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud\nDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkqhkiG9w0BAQUFAAOCAQEAPNV3PdrfibqH\nDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeCMErJk/9q56YAf4lCmtYR5VPOL8zy2gXE/uJQxDqG\nfczafhAJO5I1KlOy/usrBdlsXebQ79NqZp4VKIV66IIArB6nCWlWQtNoURi+VJq/REG6Sb4g\numlc7rh3zc5sH62Dlhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVYT0bf+215WfKEIlKu\nD8z7fDvnaspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocnyYh0igzyXxfkZ\nYiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw==\n-----END CERTIFICATE-----\n", + "Security Communication RootCA2": "-----BEGIN CERTIFICATE-----\nMIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDElMCMGA1UE\nChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMeU2VjdXJpdHkgQ29t\nbXVuaWNhdGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoXDTI5MDUyOTA1MDAzOVowXTEL\nMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xJzAl\nBgNVBAsTHlNlY3VyaXR5IENvbW11bmljYXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEB\nBQADggEPADCCAQoCggEBANAVOVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz3\n35c9S672XewhtUGrzbl+dp+++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonC\nv/Q4EpVMVAX3NuRFg3sUZdbcDE3R3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQ\nhNBqyjoGADdH5H5XTz+L62e4iKrFvlNVspHEfbmwhRkGeC7bYRr6hfVKkaHnFtWOojnflLhw\nHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1KEOtOghY6rCcMU/Gt1SSwawNQwS08Ft1ENCca\ndfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8QIH4D5csOPEK7DzPMA4GA1UdDwEB/wQE\nAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBMOqNErLlFsceTfsgL\nCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpFcoJxDjrSzG+ntKEju/Ykn8sX/oymzsLS28yN/HH8\nAynBbF0zX2S2ZTuJbxh2ePXcokgfGT+Ok+vx+hfuzU7jBBJV1uXk3fs+BXziHV7Gp7yXT2g6\n9ekuCkO2r1dcYmh8t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6qtnRGEmyR7jTV7JqR\n50S+kDFy1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29mvVXIwAHIRc/\nSjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03\n-----END CERTIFICATE-----\n", + "EC-ACC": "-----BEGIN CERTIFICATE-----\nMIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB8zELMAkG\nA1UEBhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2VydGlmaWNhY2lvIChO\nSUYgUS0wODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1YmxpY3MgZGUgQ2VydGlmaWNh\nY2lvMTUwMwYDVQQLEyxWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAo\nYykwMzE1MDMGA1UECxMsSmVyYXJxdWlhIEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRh\nbGFuZXMxDzANBgNVBAMTBkVDLUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTla\nMIHzMQswCQYDVQQGEwJFUzE7MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZp\nY2FjaW8gKE5JRiBRLTA4MDExNzYtSSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBD\nZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZlZ2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQubmV0L3Zl\ncmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJhcnF1aWEgRW50aXRhdHMgZGUgQ2VydGlmaWNh\nY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUNDMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\nMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R85iKw5K4/0CQBXCHYMkAqbWUZRkiFRfC\nQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm4CgPukLjbo73FCeTae6RDqNfDrHrZqJyTxIThmV6\nPttPB/SnCWDaOkKZx7J/sxaVHMf5NLWUhdWZXqBIoH7nF2W4onW4HvPlQn2v7fOKSGRdghST\n2MDk/7NQcvJ29rNdQlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0aE9jD2z3Il3rucO2n\n5nzbcc8tlGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw0JDnJwIDAQAB\no4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8EBTADAQH/\nMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4opvpXY0wfwYDVR0g\nBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBodHRwczovL3d3dy5jYXRjZXJ0\nLm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0\nLm5ldC92ZXJhcnJlbCAwDQYJKoZIhvcNAQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/\nsXE7zDkJlF7W2u++AVtd0x7Y/X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPp\nqojlNcAZQmNaAl6kSBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7Awa\nboMMPOhyRp/7SNVel+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOS\nAgu+TGbrIP65y7WZf+a2E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xlnJ2lYJU6\nUn/10asIbvPuW/mIPX64b24D5EI=\n-----END CERTIFICATE-----\n", + "Hellenic Academic and Research Institutions RootCA 2011": "-----BEGIN CERTIFICATE-----\nMIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1IxRDBCBgNV\nBAoTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4g\nQXV0aG9yaXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5z\ndGl0dXRpb25zIFJvb3RDQSAyMDExMB4XDTExMTIwNjEzNDk1MloXDTMxMTIwMTEzNDk1Mlow\ngZUxCzAJBgNVBAYTAkdSMUQwQgYDVQQKEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFy\nY2ggSW5zdGl0dXRpb25zIENlcnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNh\nZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZI\nhvcNAQEBBQADggEPADCCAQoCggEBAKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPz\ndYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJfel3r+0a\ne50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa71HFK9+WXesyHgLacEnsbgzImjeN9/E2YEsm\nLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u8yBRQlqD75O6aRXxYp2fmTmCobd0LovU\nxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSPFEDH3N6sQWRstBmbAmNtJGSPRLIl6s5d\ndAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBBjAdBgNV\nHQ4EFgQUppFC/RNhSiOeCKQp5dgTBCPuQSUwRwYDVR0eBEAwPqA8MAWCAy5ncjAFggMuZXUw\nBoIELmVkdTAGggQub3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQub3JnMA0GCSqGSIb3\nDQEBBQUAA4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVtXdMiKahsog2p\n6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8TqBTnbI6\nnOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7dIsXRSZMFpGD/md9\nzU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8AcysNnq/onN694/BtZqhFLKPM58N\n7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXIl7WdmplNsDz4SgCbZN2fOUvRJ9e4\n-----END CERTIFICATE-----\n", + "Actalis Authentication Root CA": "-----BEGIN CERTIFICATE-----\nMIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UEBhMCSVQx\nDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1ODUyMDk2NzEn\nMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENBMB4XDTExMDkyMjExMjIw\nMloXDTMwMDkyMjExMjIwMlowazELMAkGA1UEBhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYD\nVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRo\nZW50aWNhdGlvbiBSb290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bE\npSmkLO/lGMWwUKNvUTufClrJwkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW\n1V8IbInX4ay8IMKx4INRimlNAJZaby/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9\nKK3giq0itFZljoZUj5NDKd45RnijMCO6zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/gCczWw63\nigxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1fYVEiVRvjRuPjPdA1YprbrxTIW6HMiRvhMCb8\noJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2oxgkg4YQ51Q+qDp2JE+BIcXjDwL4k5RH\nILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2Fbe8lEfKXGkJh90qX6IuxEAf6ZYGyojnP\n9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxeKF+w6D9Fz8+vm2/7hNN3WpVvrJSEnu68wEqPSpP4\nRCHiMUVhUE4Q2OM1fEwZtN4Fv6MGn8i1zeQf1xcGDXqVdFUNaBr8EBtiZJ1t4JWgw5QHVw0U\n5r0F+7if5t+L4sbnfpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5jF66CyCU3nuDuP/j\nVo23Eek7jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLYiDrIn3hm7Ynz\nezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbtifN7OHCU\nyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQALe3KHwGCmSUyIWOYd\niPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70jsNjLiNmsGe+b7bAEzlgqqI0\nJZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDzWochcYBNy+A4mz+7+uAwTc+G02UQGRjR\nlwKxK3JCaKygvU5a2hi/a5iB0P2avl4VSM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2ryk\nOLpn7VU+Xlff1ANATIGk0k9jpwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2T\nlf05fbsq4/aC4yyXX04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst\n842/6+OkfcvHlXHo2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7R\nK4X9p2jIugErsWx0Hbhzlefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btUZCzJJ7VL\nkn5l/9Mt4blOvH+kQSGQQXemOR/qnuOf0GZvBeyqdn6/axag67XH/JJULysRJyU3eExRarDz\nzFhdFPFqSBX/wge2sY0PjlxQRrM9vwGYT7JZVEc+NHt4bVaTLnPqZih4zR0Uv6CPLy64Lo7y\nFIrM6bV8+2ydDKXhlg==\n-----END CERTIFICATE-----\n", + "Trustis FPS Root CA": "-----BEGIN CERTIFICATE-----\nMIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBFMQswCQYD\nVQQGEwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQLExNUcnVzdGlzIEZQ\nUyBSb290IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTExMzY1NFowRTELMAkGA1UEBhMC\nR0IxGDAWBgNVBAoTD1RydXN0aXMgTGltaXRlZDEcMBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9v\ndCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2\nmfRC6qc+gIMPpqdZh8mQRUN+AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkc\nhU59j9WvezX2fihHiTHcDnlkH5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE\n2gfmHhjjvSkCqPoc4Vu5g6hBSLwacY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA\n0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zto3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlBOrTh4/L6\n8MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEAAaNTMFEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV\nHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAdBgNVHQ4EFgQUuvpxJXmLV0ElIYYLceuy\nZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01GX2cGE+esCu8jowU/yyg2kdbw++BLa8F\n6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmWzaD+vkAMXBJV+JOCyinpXj9WV4s4NvdFGkwozZ5B\nuO1WTISkQMi4sKUraXAEasP41BIy+Q7DsdwyhEQsb8tGD+pmQQ9P8Vilpg0ND2HepZ5dfWWh\nPBfnqFVO76DH7cZEf1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHVl/9D7S3B2l0pKoU/\nrGXuhg8FjZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYliB6XzCGcKQEN\nZetX2fNXlrtIzYE=\n-----END CERTIFICATE-----\n", + "StartCom Certification Authority G2": "-----BEGIN CERTIFICATE-----\nMIIFYzCCA0ugAwIBAgIBOzANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJJTDEWMBQGA1UE\nChMNU3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRo\nb3JpdHkgRzIwHhcNMTAwMTAxMDEwMDAxWhcNMzkxMjMxMjM1OTAxWjBTMQswCQYDVQQGEwJJ\nTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlmaWNh\ndGlvbiBBdXRob3JpdHkgRzIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2iTZb\nB7cgNr2Cu+EWIAOVeq8Oo1XJJZlKxdBWQYeQTSFgpBSHO839sj60ZwNq7eEPS8CRhXBF4EKe\n3ikj1AENoBB5uNsDvfOpL9HG4A/LnooUCri99lZi8cVytjIl2bLzvWXFDSxu1ZJvGIsAQRSC\nb0AgJnooD/Uefyf3lLE3PbfHkffiAez9lInhzG7TNtYKGXmu1zSCZf98Qru23QumNK9LYP5/\nQ0kGi4xDuFby2X8hQxfqp0iVAXV16iulQ5XqFYSdCI0mblWbq9zSOdIxHWDirMxWRST1HFSr\n7obdljKF+ExP6JV2tgXdNiNnvP8V4so75qbsO+wmETRIjfaAKxojAuuKHDp2KntWFhxyKrOq\n42ClAJ8Em+JvHhRYW6Vsi1g8w7pOOlz34ZYrPu8HvKTlXcxNnw3h3Kq74W4a7I/htkxNeXJd\nFzULHdfBR9qWJODQcqhaX2YtENwvKhOuJv4KHBnM0D4LnMgJLvlblnpHnOl68wVQdJVznjAJ\n85eCXuaPOQgeWeU1FEIT/wCc976qUM/iUUjXuG+v+E5+M5iSFGI6dWPPe/regjupuznixL0s\nAA7IF6wT700ljtizkC+p2il9Ha90OrInwMEePnWjFqmveiJdnxMaz6eg6+OGCtP95paV1yPI\nN93EfKo2rJgaErHgTuixO/XWb/Ew1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud\nDwEB/wQEAwIBBjAdBgNVHQ4EFgQUS8W0QGutHLOlHGVuRjaJhwUMDrYwDQYJKoZIhvcNAQEL\nBQADggIBAHNXPyzVlTJ+N9uWkusZXn5T50HsEbZH77Xe7XRcxfGOSeD8bpkTzZ+K2s06Ctg6\nWgk/XzTQLwPSZh0avZyQN8gMjgdalEVGKua+etqhqaRpEpKwfTbURIfXUfEpY9Z1zRbkJ4kd\n+MIySP3bmdCPX1R0zKxnNBFi2QwKN4fRoxdIjtIXHfbX/dtl6/2o1PXWT6RbdejF0mCy2wl+\nJYt7ulKSnj7oxXehPOBKc2thz4bcQ///If4jXSRK9dNtD2IEBVeC2m6kMyV5Sy5UGYvMLD0w\n6dEG/+gyRr61M3Z3qAFdlsHB1b6uJcDJHgoJIIihDsnzb02CVAAgp9KP5DlUFy6NHrgbuxu9\nmk47EDTcnIhT76IxW1hPkWLIwpqazRVdOKnWvvgTtZ8SafJQYqz7Fzf07rh1Z2AQ+4NQ+US1\ndZxAF7L+/XldblhYXzD8AK6vM8EOTmy6p6ahfzLbOOCxchcKK5HsamMm7YnUeMx0HgX4a/6M\nanY5Ka5lIxKVCCIcl85bBu4M4ru8H0ST9tg4RQUh7eStqxK2A6RCLi3ECToDZ2mEmuFZkIoo\nhdVddLHRDiBYmxOlsGOm7XtH/UVVMKTumtTm4ofvmMkyghEpIrwACjFeLQ/Ajulrso8uBtjR\nkcfGEvRM/TAXw8HaOFvjqermobp573PYtlNXLfbQ4ddI\n-----END CERTIFICATE-----\n", + "Buypass Class 2 Root CA": "-----BEGIN CERTIFICATE-----\nMIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UE\nCgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMiBSb290\nIENBMB4XDTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1owTjELMAkGA1UEBhMCTk8xHTAb\nBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDIg\nUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1\naeTuMgHbo4Yf5FkNuud1g1Lr6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXl\nzwx87vFKu3MwZfPVL4O2fuPn9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FV\nM5I+GC911K2GScuVr1QGbNgGE41b/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHx\nMlAQTn/0hpPshNOOvEu/XAFOBz3cFIqUCqTqc/sLUegTBxj6DvEr0VQVfTzh97QZQmdiXnfg\nolXsttlpF9U6r0TtSsWe5HonfOV116rLJeffawrbD02TTqigzXsu8lkBarcNuAeBfos4Gzjm\nCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgIzRFo1clrUs3ERo/ctfPYV3Me6ZQ5BL/T\n3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLiFRhnBkp/1Wy1TbMz4GHrXb7pmA8y1x1L\nPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRSP/TizPJhk9H9Z2vXUq6/aKtAQ6BXNVN48FP4YUIH\nZMbXb5tMOA1jrGKvNouicwoN9SG9dKpN6nIDSdvHXx1iY8f93ZHsM+71bbRuMGjeyNYmsHVe\ne7QHIJihdjK4TWxPAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMmAd+Bi\nkoL1RpzzuvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAU18h\n9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462sA20ucS6v\nxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3tOluwlN5E40EIosHs\nHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo+fsicdl9sz1Gv7SEr5AcD48S\naq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlq\nYLYdDnkM/crqJIByw5c/8nerQyIKx+u2DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6\nOBE1/yWDLfJ6v9r9jv6ly0UsH8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6w\npJ9qzo6ysmD0oyLQI+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYK\nbeaP4NK75t98biGCwWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h\n3PFaTWwyI0PurKju7koSCTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPzY11aWOIv\n4x3kqdbQCtCev9eBCfHJxyYNrJgWVqA=\n-----END CERTIFICATE-----\n", + "Buypass Class 3 Root CA": "-----BEGIN CERTIFICATE-----\nMIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UE\nCgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMyBSb290\nIENBMB4XDTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFowTjELMAkGA1UEBhMCTk8xHTAb\nBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDMg\nUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEG\nMnqb8RB2uACatVI2zSRHsJ8YZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fk\noF0LXOBXByow9c3EN3coTRiR5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOo\nTyrvYLs9tznDDgFHmV0ST9tD+leh7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX\n0DJq1l1sDPGzbjniazEuOQAnFN44wOwZZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c/3ATAOux\n9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH2xc519woe2v1n/MuwU8XKhDzzMro6/1rqy6a\nny2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV/afmiSTYzIw0bOIjL9kSGiG5VZFvC5F5\nGQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvSO1UQRwUVZ2J+GGOmRj8JDlQyXr8NYnon\n74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D34xFMFbG02SrZvPAXpacw8Tvw3xrizp5f7NJzz3i\niZ+gMEuFuZyUJHmPfWupRWgPK9Dx2hzLabjKSWJtyNBjYt1gD1iqj6G8BaVmos8bdrKEZLFM\nOVLAMLrwjEsCsLa3AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFEe4zf/l\nb+74suwvTg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAACAj\nQTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdVcSQy9sgL\n8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXSIGrs/CIBKM+GuIAe\nqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2HJLw5QY33KbmkJs4j1xrG0aG\nQ0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsaO5S3HWCntZznKWlXWpuTekMwGwPXYshA\npqr8ZORK15FTAaggiG6cX0S5y2CBNOxv033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjEN\nSoYc6+I2KSb12tjE8nVhz36udmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr1\n8okmAWiDSKIz6MkEkbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2X\ncEQNtg413OEMXbugUZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvD\nu79leNKGef9JOxqDDPDeeOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq4/g7u9xN\n12TyUb7mqqta6THuBrxzvxNiCp/HuZc=\n-----END CERTIFICATE-----\n", + "T-TeleSec GlobalRoot Class 3": "-----BEGIN CERTIFICATE-----\nMIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNV\nBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lz\ndGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNz\nIDMwHhcNMDgxMDAxMTAyOTU2WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzAp\nBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQt\nU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENs\nYXNzIDMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3Z\nJNW4t/zN8ELg63iIVl6bmlQdTQyK9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/\nRLyTPWGrTs0NvvAgJ1gORH8EGoel15YUNpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4hqX2iys5\n2qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZFiP0Zf3WHHx+xGwpzJFu5ZeAsVMhg02YXP+HM\nVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W0eDrXltMEnAMbEQgqxHY9Bn20pxSN+f6\ntsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD\nVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1A/d2O2GCahKqGFPrAyGUv/7OyjANBgkqhkiG9w0B\nAQsFAAOCAQEAVj3vlNW92nOyWL6ukK2YJ5f+AbGwUgC4TeQbIXQbfsDuXmkqJa9c1h3a0nnJ\n85cp4IaH3gRZD/FZ1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzTucpH9sry9uetuUg/\nvBa3wW306gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7hP0HHRwA11fXT\n91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuImle9eiPZaG\nzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4pTpPDpFQUWw==\n-----END CERTIFICATE-----\n", + "EE Certification Centre Root CA": "-----BEGIN CERTIFICATE-----\nMIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1MQswCQYD\nVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEoMCYGA1UEAwwf\nRUUgQ2VydGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYGCSqGSIb3DQEJARYJcGtpQHNr\nLmVlMCIYDzIwMTAxMDMwMTAxMDMwWhgPMjAzMDEyMTcyMzU5NTlaMHUxCzAJBgNVBAYTAkVF\nMSIwIAYDVQQKDBlBUyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0\naWZpY2F0aW9uIENlbnRyZSBSb290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEi\nMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIIMDs4MVLqwd4lfNE7vsLDP90jmG7sWLq\nI9iroWUyeuuOF0+W2Ap7kaJjbMeMTC55v6kF/GlclY1i+blw7cNRfdCT5mzrMEvhvH2/UpvO\nbntl8jixwKIy72KyaOBhU8E2lf/slLo2rpwcpzIP5Xy0xm90/XsY6KxX7QYgSzIwWFv9zajm\nofxwvI6Sc9uXp3whrj3B9UiHbCe9nyV0gVWw93X2PaRka9ZP585ArQ/dMtO8ihJTmMmJ+xAd\nTX7Nfh9WDSFwhfYggx/2uh8Ej+p3iDXE/+pOoYtNP2MbRMNE1CV2yreN1x5KZmTNXMWcg+HC\nCIia7E6j8T4cLNlsHaFLAgMBAAGjgYowgYcwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E\nBAMCAQYwHQYDVR0OBBYEFBLyWj7qVhy/zQas8fElyalL1BSZMEUGA1UdJQQ+MDwGCCsGAQUF\nBwMCBggrBgEFBQcDAQYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYIKwYBBQUHAwkw\nDQYJKoZIhvcNAQEFBQADggEBAHv25MANqhlHt01Xo/6tu7Fq1Q+e2+RjxY6hUFaTlrg4wCQi\nZrxTFGGVv9DHKpY5P30osxBAIWrEr7BSdxjhlthWXePdNl4dp1BUoMUq5KqMlIpPnTX/dqQG\nE5Gion0ARD9V04I8GtVbvFZMIi5GQ4okQC3zErg7cBqklrkar4dBGmoYDQZPxz5uuSlNDUmJ\nEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIWiAYLtqZLICjU3j2L\nrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/vGVCJYMzpJJUPwssd8m92kMfM\ndcGWxZ0=\n-----END CERTIFICATE-----\n" +} +},{}],15:[function(require,module,exports){ (function (Buffer){ 'use strict'; -var _ = require('lodash'); -var $ = require('./util/preconditions'); -var Base58Check = require('./encoding/base58check'); -var Networks = require('./networks'); -var Hash = require('./crypto/hash'); -var JSUtil = require('./util/js'); +var RootCerts = exports; -/** - * Instantiate an address from an address String or Buffer, a public key or script hash Buffer, - * or an instance of {@link PublicKey} or {@link Script}. - * - * This is an immutable class, and if the first parameter provided to this constructor is an - * `Address` instance, the same argument will be returned. - * - * An address has two key properties: `network` and `type`. The type is either - * `Address.PayToPublicKeyHash` (value is the `'pubkeyhash'` string) - * or `Address.PayToScriptHash` (the string `'scripthash'`). The network is an instance of {@link Network}. - * You can quickly check whether an address is of a given kind by using the methods - * `isPayToPublicKeyHash` and `isPayToScriptHash` - * - * @example - * ```javascript - * // validate that an input field is valid - * var error = Address.getValidationError(input, 'testnet'); - * if (!error) { - * var address = Address(input, 'testnet'); - * } else { - * // invalid network or checksum (typo?) - * var message = error.messsage; - * } - * - * // get an address from a public key - * var address = Address(publicKey, 'testnet').toString(); - * ``` - * - * @param {*} data - The encoded data in various formats - * @param {Network|String|number=} network - The network: 'livenet' or 'testnet' - * @param {string=} type - The type of address: 'script' or 'pubkey' - * @returns {Address} A new valid and frozen instance of an Address - * @constructor - */ -function Address(data, network, type) { - /* jshint maxcomplexity: 12 */ - /* jshint maxstatements: 20 */ +var certs = require('./rootcerts.json'); - if (!(this instanceof Address)) { - return new Address(data, network, type); - } +// Use hash table for efficiency: +var trusted = Object.keys(certs).reduce(function(trusted, key) { + var pem = certs[key]; + pem = pem.replace(/-----BEGIN CERTIFICATE-----/g, ''); + pem = pem.replace(/-----END CERTIFICATE-----/g, ''); + pem = pem.replace(/\s+/g, ''); + trusted[pem] = key; + return trusted; +}, {}); - if (_.isArray(data) && _.isNumber(network)) { - return Address.createMultisig(data, network, type); +RootCerts.getTrusted = function(pem) { + pem = RootCerts.parsePEM(pem)[0].pem; + if (!Object.prototype.hasOwnProperty.call(trusted, pem)) { + return; } + return trusted[pem]; +}; - if (data instanceof Address) { - // Immutable instance - return data; +RootCerts.getCert = function(name) { + name = name.replace(/^s+|s+$/g, ''); + if (!Object.prototype.hasOwnProperty.call(certs, name)) { + return; } + return certs[name]; +}; - $.checkArgument(data, 'First argument is required, please include address data.', 'guide/address.html'); +RootCerts.parsePEM = function(pem) { + pem = pem + ''; + var concatted = pem.trim().split(/-----BEGIN [^\-\r\n]+-----/); + if (concatted.length > 2) { + return concatted.reduce(function(out, pem) { + if (!pem) { + return out; + } + pem = RootCerts.parsePEM(pem)[0].pem; + if (pem) { + out.push(pem); + } + return out; + }, []); + } + var type = /-----BEGIN ([^\-\r\n]+)-----/.exec(pem)[1]; + pem = pem.replace(/-----BEGIN [^\-\r\n]+-----/, ''); + pem = pem.replace(/-----END [^\-\r\n]+-----/, ''); + var parts = pem.trim().split(/(?:\r?\n){2,}/); + var headers = {}; + if (parts.length > 1) { + headers = parts[0].trim().split(/[\r\n]/).reduce(function(out, line) { + var parts = line.split(/:[ \t]+/); + var key = parts[0].trim().toLowerCase(); + var value = (parts.slice(1).join('') || '').trim(); + out[key] = value; + return out; + }, {}); + pem = parts.slice(1).join(''); + } + pem = pem.replace(/\s+/g, ''); + var der = pem ? new Buffer(pem, 'base64') : null; + return [{ + type: type, + headers: headers, + pem: pem, + der: der, + body: der || new Buffer([0]) + }]; +}; - if (network && !Networks.get(network)) { - throw new TypeError('Second argument must be "livenet" or "testnet".'); - } +RootCerts.certs = certs; +RootCerts.trusted = trusted; - if (type && (type !== Address.PayToPublicKeyHash && type !== Address.PayToScriptHash)) { - throw new TypeError('Third argument must be "pubkeyhash" or "scripthash".'); - } +}).call(this,require("buffer").Buffer) +},{"./rootcerts.json":14,"buffer":209}],16:[function(require,module,exports){ +var asn1 = exports; - var info = this._classifyArguments(data, network, type); +asn1.bignum = require('bn.js'); - // set defaults if not set - info.network = info.network || Networks.get(network) || Networks.defaultNetwork; - info.type = info.type || type || Address.PayToPublicKeyHash; +asn1.define = require('./asn1/api').define; +asn1.base = require('./asn1/base'); +asn1.constants = require('./asn1/constants'); +asn1.decoders = require('./asn1/decoders'); +asn1.encoders = require('./asn1/encoders'); - JSUtil.defineImmutable(this, { - hashBuffer: info.hashBuffer, - network: info.network, - type: info.type - }); +},{"./asn1/api":17,"./asn1/base":19,"./asn1/constants":23,"./asn1/decoders":25,"./asn1/encoders":27,"bn.js":28}],17:[function(require,module,exports){ +var asn1 = require('../asn1'); +var util = require('util'); +var vm = require('vm'); - return this; -} +var api = exports; -/** - * Internal function used to split different kinds of arguments of the constructor - * @param {*} data - The encoded data in various formats - * @param {Network|String|number=} network - The network: 'livenet' or 'testnet' - * @param {string=} type - The type of address: 'script' or 'pubkey' - * @returns {Object} An "info" object with "type", "network", and "hashBuffer" - */ -Address.prototype._classifyArguments = function(data, network, type) { - var PublicKey = require('./publickey'); - var Script = require('./script'); - /* jshint maxcomplexity: 10 */ - // transform and validate input data - if ((data instanceof Buffer || data instanceof Uint8Array) && data.length === 20) { - return Address._transformHash(data); - } else if ((data instanceof Buffer || data instanceof Uint8Array) && data.length === 21) { - return Address._transformBuffer(data, network, type); - } else if (data instanceof PublicKey) { - return Address._transformPublicKey(data); - } else if (data instanceof Script) { - return Address._transformScript(data, network); - } else if (typeof(data) === 'string') { - return Address._transformString(data, network, type); - } else if (_.isObject(data)) { - return Address._transformObject(data); - } else { - throw new TypeError('First argument is an unrecognized data format.'); - } +api.define = function define(name, body) { + return new Entity(name, body); }; -/** @static */ -Address.PayToPublicKeyHash = 'pubkeyhash'; -/** @static */ -Address.PayToScriptHash = 'scripthash'; +function Entity(name, body) { + this.name = name; + this.body = body; -/** - * @param {Buffer} hash - An instance of a hash Buffer - * @returns {Object} An object with keys: hashBuffer - * @private - */ -Address._transformHash = function(hash){ - var info = {}; - if (!(hash instanceof Buffer) && !(hash instanceof Uint8Array)) { - throw new TypeError('Address supplied is not a buffer.'); - } - if (hash.length !== 20) { - throw new TypeError('Address hashbuffers must be exactly 20 bytes.'); - } - info.hashBuffer = hash; - return info; + this.decoders = {}; + this.encoders = {}; }; -/** - * Deserializes an address serialized through `Address#toObject()` - * @param {Object} data - * @param {string} data.hash - the hash that this address encodes - * @param {string} data.type - either 'pubkeyhash' or 'scripthash' - * @param {Network=} data.network - the name of the network associated - * @return {Address} - */ -Address._transformObject = function(data) { - $.checkArgument(data.hash || data.hashBuffer, 'Must provide a `hash` or `hashBuffer` property'); - $.checkArgument(data.type, 'Must provide a `type` property'); - return { - hashBuffer: data.hash ? new Buffer(data.hash, 'hex') : data.hashBuffer, - network: Networks.get(data.network) || Networks.defaultNetwork, - type: data.type +Entity.prototype._createNamed = function createNamed(base) { + var named = vm.runInThisContext('(function ' + this.name + '(entity) {\n' + + ' this._initNamed(entity);\n' + + '})'); + util.inherits(named, base); + named.prototype._initNamed = function initnamed(entity) { + base.call(this, entity); }; -}; -/** - * Internal function to discover the network and type based on the first data byte - * - * @param {Buffer} buffer - An instance of a hex encoded address Buffer - * @returns {Object} An object with keys: network and type - * @private - */ -Address._classifyFromVersion = function(buffer){ - var version = {}; - version.network = Networks.get(buffer[0]); - switch (buffer[0]) { // the version byte - case Networks.livenet.pubkeyhash: - version.type = Address.PayToPublicKeyHash; - break; + return new named(this); +}; - case Networks.livenet.scripthash: - version.type = Address.PayToScriptHash; - break; +Entity.prototype._getDecoder = function _getDecoder(enc) { + // Lazily create decoder + if (!this.decoders.hasOwnProperty(enc)) + this.decoders[enc] = this._createNamed(asn1.decoders[enc]); + return this.decoders[enc]; +}; - case Networks.testnet.pubkeyhash: - version.type = Address.PayToPublicKeyHash; - break; +Entity.prototype.decode = function decode(data, enc, options) { + return this._getDecoder(enc).decode(data, options); +}; - case Networks.testnet.scripthash: - version.type = Address.PayToScriptHash; - break; - } - return version; +Entity.prototype._getEncoder = function _getEncoder(enc) { + // Lazily create encoder + if (!this.encoders.hasOwnProperty(enc)) + this.encoders[enc] = this._createNamed(asn1.encoders[enc]); + return this.encoders[enc]; }; -/** - * Internal function to transform a bitcoin address buffer - * - * @param {Buffer} buffer - An instance of a hex encoded address Buffer - * @param {string=} network - The network: 'livenet' or 'testnet' - * @param {string=} type - The type: 'pubkeyhash' or 'scripthash' - * @returns {Object} An object with keys: hashBuffer, network and type - * @private - */ -Address._transformBuffer = function(buffer, network, type){ - /* jshint maxcomplexity: 9 */ - var info = {}; - if (!(buffer instanceof Buffer) && !(buffer instanceof Uint8Array)) { - throw new TypeError('Address supplied is not a buffer.'); - } - if (buffer.length !== 1 + 20) { - throw new TypeError('Address buffers must be exactly 21 bytes.'); - } +Entity.prototype.encode = function encode(data, enc, /* internal */ reporter) { + return this._getEncoder(enc).encode(data, reporter); +}; - network = Networks.get(network); - var bufferVersion = Address._classifyFromVersion(buffer); +},{"../asn1":16,"util":377,"vm":378}],18:[function(require,module,exports){ +var assert = require('assert'); +var util = require('util'); +var Reporter = require('../base').Reporter; +var Buffer = require('buffer').Buffer; - if (!bufferVersion.network || (network && network !== bufferVersion.network)) { - throw new TypeError('Address has mismatched network type.'); +function DecoderBuffer(base, options) { + Reporter.call(this, options); + if (!Buffer.isBuffer(base)) { + this.error('Input not Buffer'); + return; } - if (!bufferVersion.type || ( type && type !== bufferVersion.type )) { - throw new TypeError('Address has mismatched type.'); - } + this.base = base; + this.offset = 0; + this.length = base.length; +} +util.inherits(DecoderBuffer, Reporter); +exports.DecoderBuffer = DecoderBuffer; - info.hashBuffer = buffer.slice(1); - info.network = bufferVersion.network; - info.type = bufferVersion.type; - return info; +DecoderBuffer.prototype.save = function save() { + return { offset: this.offset }; }; -/** - * Internal function to transform a {@link PublicKey} - * - * @param {PublicKey} pubkey - An instance of PublicKey - * @returns {Object} An object with keys: hashBuffer, type - * @private - */ -Address._transformPublicKey = function(pubkey){ - var PublicKey = require('./publickey'); - var info = {}; - if (!(pubkey instanceof PublicKey)) { - throw new TypeError('Address must be an instance of PublicKey.'); - } - info.hashBuffer = Hash.sha256ripemd160(pubkey.toBuffer()); - info.type = Address.PayToPublicKeyHash; - return info; -}; +DecoderBuffer.prototype.restore = function restore(save) { + // Return skipped data + var res = new DecoderBuffer(this.base); + res.offset = save.offset; + res.length = this.offset; -/** - * Internal function to transform a {@link Script} into a `info` object. - * - * @param {Script} script - An instance of Script - * @returns {Object} An object with keys: hashBuffer, type - * @private - */ -Address._transformScript = function(script, network){ - var Script = require('./script'); - var info = {}; - if (!(script instanceof Script)) { - throw new TypeError('Address must be an instance of Script.'); - } - if (script.isScriptHashOut()) { - info.hashBuffer = script.getData(); - info.type = Address.PayToScriptHash; - } else if (script.isPublicKeyHashOut()) { - info.hashBuffer = script.getData(); - info.type = Address.PayToPublicKeyHash; - } else { - info.hashBuffer = Hash.sha256ripemd160(script.toBuffer()); - info.type = Address.PayToScriptHash; - } - info.network = Networks.get(network) || Networks.defaultNetwork; - return info; -}; + this.offset = save.offset; -/** - * Creates a P2SH address from a set of public keys and a threshold. - * - * The addresses will be sorted lexicographically, as that is the trend in bitcoin. - * To create an address from unsorted public keys, use the {@link Script#buildMultisigOut} - * interface. - * - * @param {Array} publicKeys - a set of public keys to create an address - * @param {number} threshold - the number of signatures needed to release the funds - * @param {String|Network} network - either a Network instance, 'livenet', or 'testnet' - * @return {Address} - */ -Address.createMultisig = function(publicKeys, threshold, network) { - var Script = require('./script'); - network = network || publicKeys[0].network; - return new Address(Script.buildMultisigOut(publicKeys, threshold), network || Networks.defaultNetwork); + return res; }; -/** - * Internal function to transform a bitcoin address string - * - * @param {string} data - * @param {String|Network=} network - either a Network instance, 'livenet', or 'testnet' - * @param {string=} type - The type: 'pubkeyhash' or 'scripthash' - * @returns {Object} An object with keys: hashBuffer, network and type - * @private - */ -Address._transformString = function(data, network, type){ - if( typeof(data) !== 'string' ) { - throw new TypeError('Address supplied is not a string.'); - } - var addressBuffer = Base58Check.decode(data); - var info = Address._transformBuffer(addressBuffer, network, type); - return info; +DecoderBuffer.prototype.isEmpty = function isEmpty() { + return this.offset === this.length; }; -/** - * Instantiate an address from a PublicKey instance - * - * @param {PublicKey} data - * @param {String|Network} network - either a Network instance, 'livenet', or 'testnet' - * @returns {Address} A new valid and frozen instance of an Address - */ -Address.fromPublicKey = function(data, network){ - var info = Address._transformPublicKey(data); - network = network || Networks.defaultNetwork; - return new Address(info.hashBuffer, network, info.type); -}; +DecoderBuffer.prototype.readUInt8 = function readUInt8(fail) { + if (this.offset + 1 <= this.length) + return this.base.readUInt8(this.offset++, true); + else + return this.error(fail || 'DecoderBuffer overrun'); +} -/** - * Instantiate an address from a ripemd160 public key hash - * - * @param {Buffer} hash - An instance of buffer of the hash - * @param {String|Network} network - either a Network instance, 'livenet', or 'testnet' - * @returns {Address} A new valid and frozen instance of an Address - */ -Address.fromPublicKeyHash = function(hash, network) { - var info = Address._transformHash(hash); - return new Address(info.hashBuffer, network, Address.PayToPublicKeyHash); -}; +DecoderBuffer.prototype.skip = function skip(bytes, fail) { + if (!(this.offset + bytes <= this.length)) + return this.error(fail || 'DecoderBuffer overrun'); -/** - * Instantiate an address from a ripemd160 script hash - * - * @param {Buffer} hash - An instance of buffer of the hash - * @param {String|Network} network - either a Network instance, 'livenet', or 'testnet' - * @returns {Address} A new valid and frozen instance of an Address - */ -Address.fromScriptHash = function(hash, network) { - var info = Address._transformHash(hash); - return new Address(info.hashBuffer, network, Address.PayToScriptHash); -}; + var res = new DecoderBuffer(this.base); -/** - * Instantiate an address from a Script - * - * @param {Script} script - An instance of Script - * @param {String|Network} network - either a Network instance, 'livenet', or 'testnet' - * @returns {Address} A new valid and frozen instance of an Address - */ -Address.fromScript = function(script, network) { - var info = Address._transformScript(script, network); - return new Address(info.hashBuffer, network, info.type); -}; + // Share reporter state + res._reporterState = this._reporterState; -/** - * Instantiate an address from a buffer of the address - * - * @param {Buffer} buffer - An instance of buffer of the address - * @param {String|Network=} network - either a Network instance, 'livenet', or 'testnet' - * @param {string=} type - The type of address: 'script' or 'pubkey' - * @returns {Address} A new valid and frozen instance of an Address - */ -Address.fromBuffer = function(buffer, network, type) { - var info = Address._transformBuffer(buffer, network, type); - return new Address(info.hashBuffer, info.network, info.type); -}; + res.offset = this.offset; + res.length = this.offset + bytes; + this.offset += bytes; + return res; +} -/** - * Instantiate an address from an address string - * - * @param {string} str - An string of the bitcoin address - * @param {String|Network=} network - either a Network instance, 'livenet', or 'testnet' - * @param {string=} type - The type of address: 'script' or 'pubkey' - * @returns {Address} A new valid and frozen instance of an Address - */ -Address.fromString = function(str, network, type) { - var info = Address._transformString(str, network, type); - return new Address(info.hashBuffer, info.network, info.type); -}; +DecoderBuffer.prototype.raw = function raw(save) { + return this.base.slice(save ? save.offset : this.offset, this.length); +} -/** - * Instantiate an address from JSON - * - * @param {string} json - An JSON string or Object with keys: hash, network and type - * @returns {Address} A new valid instance of an Address - */ -Address.fromJSON = function fromJSON(json) { - if (JSUtil.isValidJSON(json)) { - json = JSON.parse(json); +function EncoderBuffer(value, reporter) { + if (Array.isArray(value)) { + this.length = 0; + this.value = value.map(function(item) { + if (!(item instanceof EncoderBuffer)) + item = new EncoderBuffer(item); + this.length += item.length; + return item; + }, this); + } else if (typeof value === 'number') { + if (!(0 <= value && value <= 0xff)) + return reporter.error('non-byte EncoderBuffer value'); + this.value = value; + this.length = 1; + } else if (typeof value === 'string') { + this.value = value; + this.length = Buffer.byteLength(value); + } else if (Buffer.isBuffer(value)) { + this.value = value; + this.length = value.length; + } else { + return reporter.error('Unsupporter type: ' + typeof value); } - $.checkState( - JSUtil.isHexa(json.hash), - 'Unexpected hash property, "' + json.hash + '", expected to be hex.' - ); - var hashBuffer = new Buffer(json.hash, 'hex'); - return new Address(hashBuffer, json.network, json.type); -}; +} +exports.EncoderBuffer = EncoderBuffer; -/** - * Will return a validation error if exists - * - * @example - * ```javascript - * // a network mismatch error - * var error = Address.getValidationError('15vkcKf7gB23wLAnZLmbVuMiiVDc1Nm4a2', 'testnet'); - * ``` - * - * @param {string} data - The encoded data - * @param {String|Network} network - either a Network instance, 'livenet', or 'testnet' - * @param {string} type - The type of address: 'script' or 'pubkey' - * @returns {null|Error} The corresponding error message - */ -Address.getValidationError = function(data, network, type) { - var error; - try { - /* jshint nonew: false */ - new Address(data, network, type); - } catch (e) { - error = e; +EncoderBuffer.prototype.join = function join(out, offset) { + if (!out) + out = new Buffer(this.length); + if (!offset) + offset = 0; + + if (this.length === 0) + return out; + + if (Array.isArray(this.value)) { + this.value.forEach(function(item) { + item.join(out, offset); + offset += item.length; + }); + } else { + if (typeof this.value === 'number') + out[offset] = this.value; + else if (typeof this.value === 'string') + out.write(this.value, offset); + else if (Buffer.isBuffer(this.value)) + this.value.copy(out, offset); + offset += this.length; } - return error; -}; -/** - * Will return a boolean if an address is valid - * - * @example - * ```javascript - * assert(Address.isValid('15vkcKf7gB23wLAnZLmbVuMiiVDc1Nm4a2', 'livenet')); - * ``` - * - * @param {string} data - The encoded data - * @param {String|Network} network - either a Network instance, 'livenet', or 'testnet' - * @param {string} type - The type of address: 'script' or 'pubkey' - * @returns {boolean} The corresponding error message - */ -Address.isValid = function(data, network, type) { - return !Address.getValidationError(data, network, type); + return out; }; -/** - * Returns true if an address is of pay to public key hash type - * @return boolean - */ -Address.prototype.isPayToPublicKeyHash = function() { - return this.type === Address.PayToPublicKeyHash; -}; +},{"../base":19,"assert":194,"buffer":209,"util":377}],19:[function(require,module,exports){ +var base = exports; -/** - * Returns true if an address is of pay to script hash type - * @return boolean - */ -Address.prototype.isPayToScriptHash = function() { - return this.type === Address.PayToScriptHash; -}; +base.Reporter = require('./reporter').Reporter; +base.DecoderBuffer = require('./buffer').DecoderBuffer; +base.EncoderBuffer = require('./buffer').EncoderBuffer; +base.Node = require('./node'); -/** - * Will return a buffer representation of the address - * - * @returns {Buffer} Bitcoin address buffer - */ -Address.prototype.toBuffer = function() { - var version = new Buffer([this.network[this.type]]); - var buf = Buffer.concat([version, this.hashBuffer]); - return buf; -}; +},{"./buffer":18,"./node":20,"./reporter":21}],20:[function(require,module,exports){ +var assert = require('assert'); +var Reporter = require('../base').Reporter; +var EncoderBuffer = require('../base').EncoderBuffer; -/** - * @returns {Object} A plain object with the address information - */ -Address.prototype.toObject = function toObject() { - return { - hash: this.hashBuffer.toString('hex'), - type: this.type, - network: this.network.toString() - }; -}; +// Supported tags +var tags = [ + 'seq', 'seqof', 'set', 'setof', 'octstr', 'bitstr', 'objid', 'bool', + 'gentime', 'utctime', 'null_', 'enum', 'int' +]; -/** - * @returns {string} A JSON representation of a plain object with the address information - */ -Address.prototype.toJSON = function toJSON() { - return JSON.stringify(this.toObject()); -}; +// Public methods list +var methods = [ + 'key', 'obj', 'use', 'optional', 'explicit', 'implicit', 'def', 'choice', + 'any' +].concat(tags); -/** - * Will return a the string representation of the address - * - * @returns {string} Bitcoin address - */ -Address.prototype.toString = function() { - return Base58Check.encode(this.toBuffer()); -}; +// Overrided methods list +var overrided = [ + '_peekTag', '_decodeTag', '_use', + '_decodeStr', '_decodeObjid', '_decodeTime', + '_decodeNull', '_decodeInt', '_decodeBool', '_decodeList', -/** - * Will return a string formatted for the console - * - * @returns {string} Bitcoin address - */ -Address.prototype.inspect = function() { - return ''; -}; + '_encodeComposite', '_encodeStr', '_encodeObjid', '_encodeTime', + '_encodeNull', '_encodeInt', '_encodeBool' +]; -module.exports = Address; +function Node(enc, parent) { + var state = {}; + this._baseState = state; -}).call(this,require("buffer").Buffer) -},{"./crypto/hash":20,"./encoding/base58check":25,"./networks":34,"./publickey":37,"./script":38,"./util/js":54,"./util/preconditions":55,"buffer":104,"lodash":79}],14:[function(require,module,exports){ -(function (Buffer){ -'use strict'; + state.enc = enc; -var _ = require('lodash'); -var BlockHeader = require('./blockheader'); -var BN = require('../crypto/bn'); -var BufferUtil = require('../util/buffer'); -var BufferReader = require('../encoding/bufferreader'); -var BufferWriter = require('../encoding/bufferwriter'); -var Hash = require('../crypto/hash'); -var JSUtil = require('../util/js'); -var Transaction = require('../transaction'); -var $ = require('../util/preconditions'); + state.parent = parent || null; + state.children = null; -/** - * Instantiate a Block from a Buffer, JSON object, or Object with - * the properties of the Block - * - * @param {*} - A Buffer, JSON string, or Object - * @returns {Block} - * @constructor - */ -function Block(arg) { - if (!(this instanceof Block)) { - return new Block(arg); + // State + state.tag = null; + state.args = null; + state.reverseArgs = null; + state.choice = null; + state.optional = false; + state.any = false; + state.obj = false; + state.use = null; + state.useDecoder = null; + state.key = null; + state['default'] = null; + state.explicit = null; + state.implicit = null; + + // Should create new instance on each method + if (!state.parent) { + state.children = []; + this._wrap(); } - _.extend(this, Block._from(arg)); - return this; } +module.exports = Node; -// https://github.com/bitcoin/bitcoin/blob/b5fa132329f0377d787a4a21c1686609c2bfaece/src/primitives/block.h#L14 -Block.MAX_BLOCK_SIZE = 1000000; - -/** - * @param {*} - A Buffer, JSON string or Object - * @returns {Object} - An object representing block data - * @throws {TypeError} - If the argument was not recognized - * @private - */ -Block._from = function _from(arg) { - var info = {}; - if (BufferUtil.isBuffer(arg)) { - info = Block._fromBufferReader(BufferReader(arg)); - } else if (JSUtil.isValidJSON(arg)) { - info = Block._fromJSON(arg); - } else if (_.isObject(arg)) { - info = { - /** - * @name Block#header - * @type {BlockHeader} - */ - header: arg.header, - /** - * @name Block#transactions - * @type {Transaction[]} - */ - transactions: arg.transactions - }; - } else { - throw new TypeError('Unrecognized argument for Block'); - } - return info; -}; +var stateProps = [ + 'enc', 'parent', 'children', 'tag', 'args', 'reverseArgs', 'choice', + 'optional', 'any', 'obj', 'use', 'alteredUse', 'key', 'default', 'explicit', + 'implicit' +]; -/** - * @param {String|Object} - A JSON string or object - * @returns {Object} - An object representing block data - * @private - */ -Block._fromJSON = function _fromJSON(data) { - if (JSUtil.isValidJSON(data)) { - data = JSON.parse(data); - } - var transactions = []; - data.transactions.forEach(function(data) { - transactions.push(Transaction().fromJSON(data)); +Node.prototype.clone = function clone() { + var state = this._baseState; + var cstate = {}; + stateProps.forEach(function(prop) { + cstate[prop] = state[prop]; }); - var info = { - header: BlockHeader.fromJSON(data.header), - transactions: transactions - }; - return info; + var res = new this.constructor(cstate.parent); + res._baseState = cstate; + return res; }; -/** - * @param {String|Object} - A JSON string or object - * @returns {Block} - An instance of block - */ -Block.fromJSON = function fromJSON(json) { - var info = Block._fromJSON(json); - return new Block(info); +Node.prototype._wrap = function wrap() { + var state = this._baseState; + methods.forEach(function(method) { + this[method] = function _wrappedMethod() { + var clone = new this.constructor(this); + state.children.push(clone); + return clone[method].apply(clone, arguments); + }; + }, this); }; -/** - * @param {BufferReader} - Block data - * @returns {Object} - An object representing the block data - * @private - */ -Block._fromBufferReader = function _fromBufferReader(br) { - var info = {}; - $.checkState(!br.finished(), 'No block data received'); - info.header = BlockHeader.fromBufferReader(br); - var transactions = br.readVarintNum(); - info.transactions = []; - for (var i = 0; i < transactions; i++) { - info.transactions.push(Transaction().fromBufferReader(br)); - } - return info; -}; +Node.prototype._init = function init(body) { + var state = this._baseState; -/** - * @param {BufferReader} - A buffer reader of the block - * @returns {Block} - An instance of block - */ -Block.fromBufferReader = function fromBufferReader(br) { - var info = Block._fromBufferReader(br); - return new Block(info); -}; + assert(state.parent === null); + body.call(this); -/** - * @param {Buffer} - A buffer of the block - * @returns {Block} - An instance of block - */ -Block.fromBuffer = function fromBuffer(buf) { - return Block.fromBufferReader(BufferReader(buf)); + // Filter children + state.children = state.children.filter(function(child) { + return child._baseState.parent === this; + }, this); + assert.equal(state.children.length, 1, 'Root node can have only one child'); }; -/** - * @param {string} - str - A hex encoded string of the block - * @returns {Block} - A hex encoded string of the block - */ -Block.fromString = function fromString(str) { - var buf = new Buffer(str, 'hex'); - return Block.fromBuffer(buf); -}; +Node.prototype._useArgs = function useArgs(args) { + var state = this._baseState; -/** - * @param {Binary} - Raw block binary data or buffer - * @returns {Block} - An instance of block - */ -Block.fromRawBlock = function fromRawBlock(data) { - if (!BufferUtil.isBuffer(data)) { - data = new Buffer(data, 'binary'); + // Filter children and args + var children = args.filter(function(arg) { + return arg instanceof this.constructor; + }, this); + args = args.filter(function(arg) { + return !(arg instanceof this.constructor); + }, this); + + if (children.length !== 0) { + assert(state.children === null); + state.children = children; + + // Replace parent to maintain backward link + children.forEach(function(child) { + child._baseState.parent = this; + }, this); + } + if (args.length !== 0) { + assert(state.args === null); + state.args = args; + state.reverseArgs = args.map(function(arg) { + if (typeof arg !== 'object' || arg.constructor !== Object) + return arg; + + var res = {}; + Object.keys(arg).forEach(function(key) { + if (key == (key | 0)) + key |= 0; + var value = arg[key]; + res[value] = key; + }); + return res; + }); } - var br = BufferReader(data); - br.pos = Block.Values.START_OF_BLOCK; - var info = Block._fromBufferReader(br); - return new Block(info); }; -/** - * @returns {Object} - A plain object with the block properties - */ -Block.prototype.toObject = function toObject() { - var transactions = []; - this.transactions.forEach(function(tx) { - transactions.push(tx.toObject()); - }); - return { - header: this.header.toObject(), - transactions: transactions +// +// Overrided methods +// + +overrided.forEach(function(method) { + Node.prototype[method] = function _overrided() { + var state = this._baseState; + throw new Error(method + ' not implemented for encoding: ' + state.enc); }; -}; +}); -/** - * @returns {string} - A JSON string - */ -Block.prototype.toJSON = function toJSON() { - return JSON.stringify(this.toObject()); -}; +// +// Public methods +// -/** - * @returns {Buffer} - A buffer of the block - */ -Block.prototype.toBuffer = function toBuffer() { - return this.toBufferWriter().concat(); -}; +tags.forEach(function(tag) { + Node.prototype[tag] = function _tagMethod() { + var state = this._baseState; + var args = Array.prototype.slice.call(arguments); -/** - * @returns {string} - A hex encoded string of the block - */ -Block.prototype.toString = function toString() { - return this.toBuffer().toString('hex'); -}; + assert(state.tag === null); + state.tag = tag; -/** - * @param {BufferWriter} - An existing instance of BufferWriter - * @returns {BufferWriter} - An instance of BufferWriter representation of the Block - */ -Block.prototype.toBufferWriter = function toBufferWriter(bw) { - if (!bw) { - bw = new BufferWriter(); - } - bw.write(this.header.toBuffer()); - bw.writeVarintNum(this.transactions.length); - for (var i = 0; i < this.transactions.length; i++) { - this.transactions[i].toBufferWriter(bw); - } - return bw; + this._useArgs(args); + + return this; + }; +}); + +Node.prototype.use = function use(item) { + var state = this._baseState; + + assert(state.use === null); + state.use = item; + + return this; }; -/** - * Will iterate through each transaction and return an array of hashes - * @returns {Array} - An array with transaction hashes - */ -Block.prototype.getTransactionHashes = function getTransactionHashes() { - var hashes = []; - if (this.transactions.length === 0) { - return [Block.Values.NULL_HASH]; - } - for (var t = 0; t < this.transactions.length; t++) { - hashes.push(this.transactions[t]._getHash()); - } - return hashes; +Node.prototype.optional = function optional() { + var state = this._baseState; + + state.optional = true; + + return this; }; -/** - * Will build a merkle tree of all the transactions, ultimately arriving at - * a single point, the merkle root. - * @link https://en.bitcoin.it/wiki/Protocol_specification#Merkle_Trees - * @returns {Array} - An array with each level of the tree after the other. - */ -Block.prototype.getMerkleTree = function getMerkleTree() { +Node.prototype.def = function def(val) { + var state = this._baseState; - var tree = this.getTransactionHashes(); + assert(state['default'] === null); + state['default'] = val; + state.optional = true; - var j = 0; - for (var size = this.transactions.length; size > 1; size = Math.floor((size + 1) / 2)) { - for (var i = 0; i < size; i += 2) { - var i2 = Math.min(i + 1, size - 1); - var buf = Buffer.concat([tree[j + i], tree[j + i2]]); - tree.push(Hash.sha256sha256(buf)); - } - j += size; - } + return this; +}; - return tree; +Node.prototype.explicit = function explicit(num) { + var state = this._baseState; + + assert(state.explicit === null && state.implicit === null); + state.explicit = num; + + return this; }; -/** - * Calculates the merkleRoot from the transactions. - * @returns {Buffer} - A buffer of the merkle root hash - */ -Block.prototype.getMerkleRoot = function getMerkleRoot() { - var tree = this.getMerkleTree(); - return tree[tree.length - 1]; +Node.prototype.implicit = function implicit(num) { + var state = this._baseState; + + assert(state.explicit === null && state.implicit === null); + state.implicit = num; + + return this; }; -/** - * Verifies that the transactions in the block match the header merkle root - * @returns {Boolean} - If the merkle roots match - */ -Block.prototype.validMerkleRoot = function validMerkleRoot() { +Node.prototype.obj = function obj() { + var state = this._baseState; + var args = Array.prototype.slice.call(arguments); - var h = new BN(this.header.merkleRoot.toString('hex'), 'hex'); - var c = new BN(this.getMerkleRoot().toString('hex'), 'hex'); + state.obj = true; - if (h.cmp(c) !== 0) { - return false; - } + if (args.length !== 0) + this._useArgs(args); - return true; + return this; }; -/** - * @returns {Buffer} - The little endian hash buffer of the header - */ -Block.prototype._getHash = function() { - return this.header._getHash(); -}; +Node.prototype.key = function key(key) { + var state = this._baseState; -var idProperty = { - configurable: false, - writeable: false, - /** - * @returns {string} - The big endian hash buffer of the header - */ - get: function() { - if (!this._id) { - this._id = this.header.id; - } - return this._id; - }, - set: _.noop -}; -Object.defineProperty(Block.prototype, 'id', idProperty); -Object.defineProperty(Block.prototype, 'hash', idProperty); + assert(state.key === null); + state.key = key; -/** - * @returns {string} - A string formated for the console - */ -Block.prototype.inspect = function inspect() { - return ''; + return this; }; -Block.Values = { - START_OF_BLOCK: 8, // Start of block in raw block data - NULL_HASH: new Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex') -}; +Node.prototype.any = function any() { + var state = this._baseState; -module.exports = Block; + state.any = true; -}).call(this,require("buffer").Buffer) -},{"../crypto/bn":18,"../crypto/hash":20,"../encoding/bufferreader":26,"../encoding/bufferwriter":27,"../transaction":41,"../util/buffer":53,"../util/js":54,"../util/preconditions":55,"./blockheader":15,"buffer":104,"lodash":79}],15:[function(require,module,exports){ -(function (Buffer){ -'use strict'; + return this; +}; -var _ = require('lodash'); -var BN = require('../crypto/bn'); -var BufferUtil = require('../util/buffer'); -var BufferReader = require('../encoding/bufferreader'); -var BufferWriter = require('../encoding/bufferwriter'); -var Hash = require('../crypto/hash'); -var JSUtil = require('../util/js'); +Node.prototype.choice = function choice(obj) { + var state = this._baseState; + + assert(state.choice === null); + state.choice = obj; + this._useArgs(Object.keys(obj).map(function(key) { + return obj[key]; + })); -/** - * Instantiate a BlockHeader from a Buffer, JSON object, or Object with - * the properties of the BlockHeader - * - * @param {*} - A Buffer, JSON string, or Object - * @returns {BlockHeader} - An instance of block header - * @constructor - */ -var BlockHeader = function BlockHeader(arg) { - if (!(this instanceof BlockHeader)) { - return new BlockHeader(arg); - } - _.extend(this, BlockHeader._from(arg)); return this; }; -/** - * @param {*} - A Buffer, JSON string or Object - * @returns {Object} - An object representing block header data - * @throws {TypeError} - If the argument was not recognized - * @private - */ -BlockHeader._from = function _from(arg) { - var info = {}; - if (BufferUtil.isBuffer(arg)) { - info = BlockHeader._fromBufferReader(BufferReader(arg)); - } else if (JSUtil.isValidJSON(arg)) { - info = BlockHeader._fromJSON(arg); - } else if (_.isObject(arg)) { - info = { - version: arg.version, - prevHash: arg.prevHash, - merkleRoot: arg.merkleRoot, - time: arg.time, - bits: arg.bits, - nonce: arg.nonce - }; - } else { - throw new TypeError('Unrecognized argument for BlockHeader'); - } - return info; -}; +// +// Decoding +// -/** - * @param {String|Object} - A JSON string or object - * @returns {Object} - An object representing block header data - * @private - */ -BlockHeader._fromJSON = function _fromJSON(data) { - if (JSUtil.isValidJSON(data)) { - data = JSON.parse(data); - } - var info = { - version: data.version, - prevHash: new Buffer(data.prevHash, 'hex'), - merkleRoot: new Buffer(data.merkleRoot, 'hex'), - time: data.time, - timestamp: data.time, - bits: data.bits, - nonce: data.nonce - }; - return info; -}; +Node.prototype._decode = function decode(input) { + var state = this._baseState; -/** - * @param {String|Object} - A JSON string or object - * @returns {BlockHeader} - An instance of block header - */ -BlockHeader.fromJSON = function fromJSON(json) { - var info = BlockHeader._fromJSON(json); - return new BlockHeader(info); -}; + // Decode root node + if (state.parent === null) + return input.wrapResult(state.children[0]._decode(input)); -/** - * @param {Binary} - Raw block binary data or buffer - * @returns {BlockHeader} - An instance of block header - */ -BlockHeader.fromRawBlock = function fromRawBlock(data) { - if (!BufferUtil.isBuffer(data)) { - data = new Buffer(data, 'binary'); + var result = state['default']; + var present = true; + + var prevKey; + if (state.key !== null) + prevKey = input.enterKey(state.key); + + // Check if tag is there + if (state.optional) { + present = this._peekTag( + input, + state.explicit !== null ? state.explicit : + state.implicit !== null ? state.implicit : + state.tag || 0 + ); + if (input.isError(present)) + return present; } - var br = BufferReader(data); - br.pos = BlockHeader.Constants.START_OF_HEADER; - var info = BlockHeader._fromBufferReader(br); - return new BlockHeader(info); -}; -/** - * @param {Buffer} - A buffer of the block header - * @returns {BlockHeader} - An instance of block header - */ -BlockHeader.fromBuffer = function fromBuffer(buf) { - var info = BlockHeader._fromBufferReader(BufferReader(buf)); - return new BlockHeader(info); -}; + // Push object on stack + var prevObj; + if (state.obj && present) + prevObj = input.enterObject(); -/** - * @param {string} - A hex encoded buffer of the block header - * @returns {BlockHeader} - An instance of block header - */ -BlockHeader.fromString = function fromString(str) { - var buf = new Buffer(str, 'hex'); - return BlockHeader.fromBuffer(buf); -}; + if (present) { + // Unwrap explicit values + if (state.explicit !== null) { + var explicit = this._decodeTag(input, state.explicit); + if (input.isError(explicit)) + return explicit; + input = explicit; + } -/** - * @param {BufferReader} - A BufferReader of the block header - * @returns {Object} - An object representing block header data - * @private - */ -BlockHeader._fromBufferReader = function _fromBufferReader(br) { - var info = {}; - info.version = br.readUInt32LE(); - info.prevHash = br.read(32); - info.merkleRoot = br.read(32); - info.time = br.readUInt32LE(); - info.bits = br.readUInt32LE(); - info.nonce = br.readUInt32LE(); - return info; -}; + // Unwrap implicit and normal values + if (state.use === null && state.choice === null) { + if (state.any) + var save = input.save(); + var body = this._decodeTag( + input, + state.implicit !== null ? state.implicit : state.tag, + state.any + ); + if (input.isError(body)) + return body; -/** - * @param {BufferReader} - A BufferReader of the block header - * @returns {BlockHeader} - An instance of block header - */ -BlockHeader.fromBufferReader = function fromBufferReader(br) { - var info = BlockHeader._fromBufferReader(br); - return new BlockHeader(info); -}; + if (state.any) + result = input.raw(save); + else + input = body; + } -/** - * @returns {Object} - A plain object of the BlockHeader - */ -BlockHeader.prototype.toObject = function toObject() { - return { - version: this.version, - prevHash: this.prevHash.toString('hex'), - merkleRoot: this.merkleRoot.toString('hex'), - time: this.time, - bits: this.bits, - nonce: this.nonce - }; -}; + // Select proper method for tag + if (state.any) + result = result; + else if (state.choice === null) + result = this._decodeGeneric(state.tag, input); + else + result = this._decodeChoice(input); -/** - * @returns {string} - A JSON string - */ -BlockHeader.prototype.toJSON = function toJSON() { - return JSON.stringify(this.toObject()); -}; + if (input.isError(result)) + return result; -/** - * @returns {Buffer} - A Buffer of the BlockHeader - */ -BlockHeader.prototype.toBuffer = function toBuffer() { - return this.toBufferWriter().concat(); -}; + // Decode children + if (!state.any && state.choice === null && state.children !== null) { + var fail = state.children.some(function decodeChildren(child) { + // NOTE: We are ignoring errors here, to let parser continue with other + // parts of encoded data + child._decode(input); + }); + if (fail) + return err; + } + } -/** - * @returns {string} - A hex encoded string of the BlockHeader - */ -BlockHeader.prototype.toString = function toString() { - return this.toBuffer().toString('hex'); + // Pop object + if (state.obj && present) + result = input.leaveObject(prevObj); + + // Set key + if (state.key !== null && (result !== null || present === true)) + input.leaveKey(prevKey, state.key, result); + + return result; }; -/** - * @param {BufferWriter} - An existing instance BufferWriter - * @returns {BufferWriter} - An instance of BufferWriter representation of the BlockHeader - */ -BlockHeader.prototype.toBufferWriter = function toBufferWriter(bw) { - if (!bw) { - bw = new BufferWriter(); - } - bw.writeUInt32LE(this.version); - bw.write(this.prevHash); - bw.write(this.merkleRoot); - bw.writeUInt32LE(this.time); - bw.writeUInt32LE(this.bits); - bw.writeUInt32LE(this.nonce); - return bw; +Node.prototype._decodeGeneric = function decodeGeneric(tag, input) { + var state = this._baseState; + + if (tag === 'seq' || tag === 'set') + return null; + if (tag === 'seqof' || tag === 'setof') + return this._decodeList(input, tag, state.args[0]); + else if (tag === 'octstr' || tag === 'bitstr') + return this._decodeStr(input, tag); + else if (tag === 'objid' && state.args) + return this._decodeObjid(input, state.args[0], state.args[1]); + else if (tag === 'objid') + return this._decodeObjid(input, null, null); + else if (tag === 'gentime' || tag === 'utctime') + return this._decodeTime(input, tag); + else if (tag === 'null_') + return this._decodeNull(input); + else if (tag === 'bool') + return this._decodeBool(input); + else if (tag === 'int' || tag === 'enum') + return this._decodeInt(input, state.args && state.args[0]); + else if (state.use !== null) + return this._getUse(state.use)._decode(input); + else + return input.error('unknown tag: ' + tag); + + return null; }; -/** - * @link https://en.bitcoin.it/wiki/Difficulty - * @returns {BN} - An instance of BN with the decoded difficulty bits - */ -BlockHeader.prototype.getTargetDifficulty = function getTargetDifficulty(info) { - var target = new BN(this.bits & 0xffffff); - var mov = 8 * ((this.bits >>> 24) - 3); - while (mov-- > 0) { - target = target.mul(new BN(2)); +Node.prototype._getUse = function _getUse(entity) { + var state = this._baseState; + if (!state.useDecoder) { + // Create altered use decoder if implicit is set + state.useDecoder = this._use(entity); + assert(state.useDecoder._baseState.parent === null); + state.useDecoder = state.useDecoder._baseState.children[0]; + if (state.implicit !== null) { + state.useDecoder = state.useDecoder.clone(); + state.useDecoder._baseState.implicit = state.implicit; + } } - return target; + return state.useDecoder; }; -/** - * @returns {Buffer} - The little endian hash buffer of the header - */ -BlockHeader.prototype._getHash = function hash() { - var buf = this.toBuffer(); - return Hash.sha256sha256(buf); -}; +Node.prototype._decodeChoice = function decodeChoice(input) { + var state = this._baseState; + var result = null; + var match = false; -var idProperty = { - configurable: false, - writeable: false, - enumerable: true, - /** - * @returns {string} - The big endian hash buffer of the header - */ - get: function() { - if (!this._id) { - this._id = BufferReader(this._getHash()).readReverse().toString('hex'); + Object.keys(state.choice).some(function(key) { + var save = input.save(); + var node = state.choice[key]; + try { + var value = node._decode(input); + if (input.isError(value)) + return false; + + result = { type: key, value: value }; + match = true; + } catch (e) { + input.restore(save); + return false; } - return this._id; - }, - set: _.noop -}; -Object.defineProperty(BlockHeader.prototype, 'id', idProperty); -Object.defineProperty(BlockHeader.prototype, 'hash', idProperty); + return true; + }, this); -/** - * @returns {Boolean} - If timestamp is not too far in the future - */ -BlockHeader.prototype.validTimestamp = function validTimestamp() { - var currentTime = Math.round(new Date().getTime() / 1000); - if (this.time > currentTime + BlockHeader.Constants.MAX_TIME_OFFSET) { - return false; - } - return true; + if (!match) + return input.error('Choice not matched'); + + return result; }; -/** - * @returns {Boolean} - If the proof-of-work hash satisfies the target difficulty - */ -BlockHeader.prototype.validProofOfWork = function validProofOfWork() { - var pow = new BN(this.id, 'hex'); - var target = this.getTargetDifficulty(); +// +// Encoding +// - if (pow.cmp(target) > 0) { - return false; - } - return true; +Node.prototype._createEncoderBuffer = function createEncoderBuffer(data) { + return new EncoderBuffer(data, this.reporter); }; -/** - * @returns {string} - A string formated for the console - */ -BlockHeader.prototype.inspect = function inspect() { - return ''; -}; +Node.prototype._encode = function encode(data, reporter) { + var state = this._baseState; -BlockHeader.Constants = { - START_OF_HEADER: 8, // Start buffer position in raw block data - MAX_TIME_OFFSET: 2 * 60 * 60, // The max a timestamp can be in the future - LARGEST_HASH: new BN('10000000000000000000000000000000000000000000000000000000000000000', 'hex') -}; + // Decode root node + if (state.parent === null) + return state.children[0]._encode(data, reporter || new Reporter()); -module.exports = BlockHeader; + var result = null; + var present = true; -}).call(this,require("buffer").Buffer) -},{"../crypto/bn":18,"../crypto/hash":20,"../encoding/bufferreader":26,"../encoding/bufferwriter":27,"../util/buffer":53,"../util/js":54,"buffer":104,"lodash":79}],16:[function(require,module,exports){ -module.exports = require('./block'); + // Set reporter to share it with a child class + this.reporter = reporter; -module.exports.BlockHeader = require('./blockheader'); -module.exports.MerkleBlock = require('./merkleblock'); + // Check if data is there + if (state.optional && data === undefined) { + if (state['default'] !== null) + data = state['default'] + else + return; + } -},{"./block":14,"./blockheader":15,"./merkleblock":17}],17:[function(require,module,exports){ -(function (Buffer){ -'use strict'; + // For error reporting + var prevKey; -var _ = require('lodash'); -var BlockHeader = require('./blockheader'); -var BufferUtil = require('../util/buffer'); -var BufferReader = require('../encoding/bufferreader'); -var BufferWriter = require('../encoding/bufferwriter'); -var Hash = require('../crypto/hash'); -var JSUtil = require('../util/js'); -var Transaction = require('../transaction'); -var $ = require('../util/preconditions'); + // Encode children first + var content = null; + var primitive = false; + if (state.any) { + // Anything that was given is translated to buffer + result = this._createEncoderBuffer(data); + } else if (state.choice) { + result = this._encodeChoice(data, reporter); + } else if (state.children) { + content = state.children.map(function(child) { + if (child._baseState.key === null) + return reporter.error('Child should have a key'); + var prevKey = reporter.enterKey(child._baseState.key); -/** - * Instantiate a MerkleBlock from a Buffer, JSON object, or Object with - * the properties of the Block - * - * @param {*} - A Buffer, JSON string, or Object representing a MerkleBlock - * @returns {MerkleBlock} - * @constructor - */ -function MerkleBlock(arg) { - /* jshint maxstatements: 18 */ + if (typeof data !== 'object') + return reporter.error('Child expected, but input is not object'); - if (!(this instanceof MerkleBlock)) { - return new MerkleBlock(arg); - } + var res = child._encode(data[child._baseState.key], reporter); + reporter.leaveKey(prevKey); - var info = {}; - if (BufferUtil.isBuffer(arg)) { - info = MerkleBlock._fromBufferReader(BufferReader(arg)); - } else if (JSUtil.isValidJSON(arg)) { - info = MerkleBlock._fromJSON(arg); - } else if (_.isObject(arg)) { - var header; - if(arg.header instanceof BlockHeader) { - header = arg.header; + return res; + }, this).filter(function(child) { + return child; + }); + + content = this._createEncoderBuffer(content); + } else { + if (state.tag === 'seqof' || state.tag === 'setof') { + // TODO(indutny): this should be thrown on DSL level + if (!(state.args && state.args.length === 1)) + return reporter.error('Too many args for : ' + state.tag); + + if (!Array.isArray(data)) + return reporter.error('seqof/setof, but data is not Array'); + + content = this._createEncoderBuffer(data.map(function(item) { + return this._getUse(state.args[0])._encode(item, reporter); + }, this)); + } else if (state.use !== null) { + result = this._getUse(state.use)._encode(data, reporter); } else { - header = BlockHeader.fromJSON(JSON.stringify(arg.header)); + content = this._encodePrimitive(state.tag, data); + primitive = true; } - info = { - /** - * @name MerkleBlock#header - * @type {BlockHeader} - */ - header: header, - /** - * @name MerkleBlock#numTransactions - * @type {Number} - */ - numTransactions: arg.numTransactions, - /** - * @name MerkleBlock#hashes - * @type {String[]} - */ - hashes: arg.hashes, - /** - * @name MerkleBlock#flags - * @type {Number[]} - */ - flags: arg.flags - }; - } else { - throw new TypeError('Unrecognized argument for MerkleBlock'); } - _.extend(this,info); - this._flagBitsUsed = 0; - this._hashesUsed = 0; - return this; -} -/** - * @param {Buffer} - MerkleBlock data in a Buffer object - * @returns {MerkleBlock} - A MerkleBlock object - */ -MerkleBlock.fromBuffer = function fromBuffer(buf) { - return MerkleBlock.fromBufferReader(BufferReader(buf)); -}; + // Encode data itself + var result; + if (!state.any && state.choice === null) { + var tag = state.implicit !== null ? state.implicit : state.tag; + var cls = state.implicit === null ? 'universal' : 'context'; -/** - * @param {BufferReader} - MerkleBlock data in a BufferReader object - * @returns {MerkleBlock} - A MerkleBlock object - */ -MerkleBlock.fromBufferReader = function fromBufferReader(br) { - return new MerkleBlock(MerkleBlock._fromBufferReader(br)); -}; + if (tag === null) { + if (state.use === null) + reporter.error('Tag could be ommited only for .use()'); + } else { + if (state.use === null) + result = this._encodeComposite(tag, primitive, cls, content); + } + } -/** - * @param {String|Object} - A JSON String or Object - * @returns {MerkleBlock} - A MerkleBlock object - */ -MerkleBlock.fromJSON = function fromJSON(buf) { - return new MerkleBlock(MerkleBlock._fromJSON(buf)); + // Wrap in explicit + if (state.explicit !== null) + result = this._encodeComposite(state.explicit, false, 'context', result); + + return result; }; -/** - * @returns {Buffer} - A buffer of the block - */ -MerkleBlock.prototype.toBuffer = function toBuffer() { - return this.toBufferWriter().concat(); +Node.prototype._encodeChoice = function encodeChoice(data, reporter) { + var state = this._baseState; + + var node = state.choice[data.type]; + return node._encode(data.value, reporter); }; -/** - * @param {BufferWriter} - An existing instance of BufferWriter - * @returns {BufferWriter} - An instance of BufferWriter representation of the MerkleBlock - */ -MerkleBlock.prototype.toBufferWriter = function toBufferWriter(bw) { - if (!bw) { - bw = new BufferWriter(); - } - bw.write(this.header.toBuffer()); - bw.writeUInt32LE(this.numTransactions); - bw.writeVarintNum(this.hashes.length); - for (var i = 0; i < this.hashes.length; i++) { - bw.write(new Buffer(this.hashes[i], 'hex')); - } - bw.writeVarintNum(this.flags.length); - for (i = 0; i < this.flags.length; i++) { - bw.writeUInt8(this.flags[i]); - } - return bw; +Node.prototype._encodePrimitive = function encodePrimitive(tag, data) { + var state = this._baseState; + + if (tag === 'octstr' || tag === 'bitstr') + return this._encodeStr(data, tag); + else if (tag === 'objid' && state.args) + return this._encodeObjid(data, state.reverseArgs[0], state.args[1]); + else if (tag === 'objid') + return this._encodeObjid(data, null, null); + else if (tag === 'gentime' || tag === 'utctime') + return this._encodeTime(data, tag); + else if (tag === 'null_') + return this._encodeNull(); + else if (tag === 'int' || tag === 'enum') + return this._encodeInt(data, state.args && state.reverseArgs[0]); + else if (tag === 'bool') + return this._encodeBool(data); + else + throw new Error('Unsupported tag: ' + tag); }; -/** - * @returns {Object} - A plain object with the MerkleBlock properties - */ -MerkleBlock.prototype.toObject = function toObject() { - return { - header: this.header.toObject(), - numTransactions: this.numTransactions, - hashes: this.hashes, - flags: this.flags +},{"../base":19,"assert":194}],21:[function(require,module,exports){ +var util = require('util'); + +function Reporter(options) { + this._reporterState = { + obj: null, + path: [], + options: options || {}, + errors: [] }; +} +exports.Reporter = Reporter; + +Reporter.prototype.isError = function isError(obj) { + return obj instanceof ReporterError; }; -/** - * @returns {String} - A JSON string of a MerkleBlock - */ -MerkleBlock.prototype.toJSON = function toJSON() { - return JSON.stringify(this.toObject()); +Reporter.prototype.enterKey = function enterKey(key) { + return this._reporterState.path.push(key); }; -/** - * Verify that the MerkleBlock is valid - * @returns {Boolean} - True/False whether this MerkleBlock is Valid - */ -MerkleBlock.prototype.validMerkleTree = function validMerkleTree() { - $.checkState(_.isArray(this.flags), 'MerkleBlock flags is not an array'); - $.checkState(_.isArray(this.hashes), 'MerkleBlock hashes is not an array'); +Reporter.prototype.leaveKey = function leaveKey(index, key, value) { + var state = this._reporterState; - // Can't have more hashes than numTransactions - if(this.hashes.length > this.numTransactions) { - return false; - } + state.path = state.path.slice(0, index - 1); + if (state.obj !== null) + state.obj[key] = value; +}; - // Can't have more flag bits than num hashes - if(this.flags.length * 8 < this.hashes.length) { - return false; - } +Reporter.prototype.enterObject = function enterObject() { + var state = this._reporterState; - var height = this._calcTreeHeight(); - var opts = { hashesUsed: 0, flagBitsUsed: 0 }; - var root = this._traverseMerkleTree(height, 0, opts); - if(opts.hashesUsed !== this.hashes.length) { - return false; - } - return BufferUtil.equals(root, this.header.merkleRoot); + var prev = state.obj; + state.obj = {}; + return prev; }; -/** - * Traverse a the tree in this MerkleBlock, validating it along the way - * Modeled after Bitcoin Core merkleblock.cpp TraverseAndExtract() - * @param {Number} - depth - Current height - * @param {Number} - pos - Current position in the tree - * @param {Object} - opts - Object with values that need to be mutated throughout the traversal - * @param {Number} - opts.flagBitsUsed - Number of flag bits used, should start at 0 - * @param {Number} - opts.hashesUsed - Number of hashes used, should start at 0 - * @param {Array} - opts.txs - Will finish populated by transactions found during traversal - * @returns {Buffer|null} - Buffer containing the Merkle Hash for that height - * @private - */ -MerkleBlock.prototype._traverseMerkleTree = function traverseMerkleTree(depth, pos, opts) { - /* jshint maxcomplexity: 12*/ - /* jshint maxstatements: 20 */ - - opts = opts || {}; - opts.txs = opts.txs || []; - opts.flagBitsUsed = opts.flagBitsUsed || 0; - opts.hashesUsed = opts.hashesUsed || 0; +Reporter.prototype.leaveObject = function leaveObject(prev) { + var state = this._reporterState; - if(opts.flagBitsUsed > this.flags.length * 8) { - return null; - } - var isParentOfMatch = (this.flags[opts.flagBitsUsed >> 3] >>> (opts.flagBitsUsed++ & 7)) & 1; - if(depth === 0 || !isParentOfMatch) { - if(opts.hashesUsed >= this.hashes.length) { - return null; - } - var hash = this.hashes[opts.hashesUsed++]; - if(depth === 0 && isParentOfMatch) { - opts.txs.push(hash); - } - return new Buffer(hash, 'hex'); - } else { - var left = this._traverseMerkleTree(depth-1, pos*2, opts); - var right = left; - if(pos*2+1 < this._calcTreeWidth(depth-1)) { - right = this._traverseMerkleTree(depth-1, pos*2+1, opts); - } - return Hash.sha256sha256(new Buffer.concat([left, right])); - } + var now = state.obj; + state.obj = prev; + return now; }; -/** Calculates the width of a merkle tree at a given height. - * Modeled after Bitcoin Core merkleblock.h CalcTreeWidth() - * @param {Number} - Height at which we want the tree width - * @returns {Number} - Width of the tree at a given height - * @private - */ -MerkleBlock.prototype._calcTreeWidth = function calcTreeWidth(height) { - return (this.numTransactions + (1 << height) - 1) >> height; -}; +Reporter.prototype.error = function error(msg) { + var err; + var state = this._reporterState; -/** Calculates the height of the merkle tree in this MerkleBlock - * @param {Number} - Height at which we want the tree width - * @returns {Number} - Height of the merkle tree in this MerkleBlock - * @private - */ -MerkleBlock.prototype._calcTreeHeight = function calcTreeHeight() { - var height = 0; - while (this._calcTreeWidth(height) > 1) { - height++; + var inherited = msg instanceof ReporterError; + if (inherited) { + err = msg; + } else { + err = new ReporterError(state.path.map(function(elem) { + return '[' + JSON.stringify(elem) + ']'; + }).join(''), msg.message || msg, msg.stack); } - return height; -}; -/** - * @param {Transaction|String} - Transaction or Transaction ID Hash - * @returns {Boolean} - return true/false if this MerkleBlock has the TX or not - * @private - */ -MerkleBlock.prototype.hasTransaction = function hasTransaction(tx) { - $.checkArgument(!_.isUndefined(tx), 'tx cannot be undefined'); - $.checkArgument(tx instanceof Transaction || typeof tx === 'string', - 'Invalid tx given, tx must be a "string" or "Transaction"'); + if (!state.options.partial) + throw err; - var hash = tx; - if(tx instanceof Transaction) { - // We need to reverse the id hash for the lookup - hash = BufferUtil.reverse(new Buffer(tx.id, 'hex')).toString('hex'); - } + if (!inherited) + state.errors.push(err); - var txs = []; - var height = this._calcTreeHeight(); - this._traverseMerkleTree(height, 0, { txs: txs }); - return txs.indexOf(hash) !== -1; + return err; }; -/** - * @param {Buffer} - MerkleBlock data - * @returns {Object} - An Object representing merkleblock data - * @private - */ -MerkleBlock._fromBufferReader = function _fromBufferReader(br) { - $.checkState(!br.finished(), 'No merkleblock data received'); - var info = {}; - info.header = BlockHeader.fromBufferReader(br); - info.numTransactions = br.readUInt32LE(); - var numHashes = br.readVarintNum(); - info.hashes = []; - for (var i = 0; i < numHashes; i++) { - info.hashes.push(br.read(32).toString('hex')); - } - var numFlags = br.readVarintNum(); - info.flags = []; - for (i = 0; i < numFlags; i++) { - info.flags.push(br.readUInt8()); - } - return info; -}; +Reporter.prototype.wrapResult = function wrapResult(result) { + var state = this._reporterState; + if (!state.options.partial) + return result; -/** - * @param {String|Object} - A JSON or String Object - * @returns {Object} - An Object representing merkleblock data - * @private - */ -MerkleBlock._fromJSON = function _fromJSON(data) { - if (JSUtil.isValidJSON(data)) { - data = JSON.parse(data); - } - var info = { - header: BlockHeader.fromJSON(data.header), - numTransactions: data.numTransactions, - hashes: data.hashes, - flags: data.flags, + return { + result: this.isError(result) ? null : result, + errors: state.errors }; - return info; }; -module.exports = MerkleBlock; - -}).call(this,require("buffer").Buffer) -},{"../crypto/hash":20,"../encoding/bufferreader":26,"../encoding/bufferwriter":27,"../transaction":41,"../util/buffer":53,"../util/js":54,"../util/preconditions":55,"./blockheader":15,"buffer":104,"lodash":79}],18:[function(require,module,exports){ -(function (Buffer){ -'use strict'; +function ReporterError(path, msg) { + this.path = path; + this.rethrow(msg); +}; +util.inherits(ReporterError, Error); -var BN = require('bn.js'); -var $ = require('../util/preconditions'); -var _ = require('lodash'); +ReporterError.prototype.rethrow = function rethrow(msg) { + this.message = msg + ' at: ' + (this.path || '(shallow)'); + Error.captureStackTrace(this, ReporterError); -var reversebuf = function(buf) { - var buf2 = new Buffer(buf.length); - for (var i = 0; i < buf.length; i++) { - buf2[i] = buf[buf.length - 1 - i]; - } - return buf2; + return this; }; -BN.Zero = new BN(0); -BN.One = new BN(1); -BN.Minus1 = new BN(-1); +},{"util":377}],22:[function(require,module,exports){ +var constants = require('../constants'); -BN.fromNumber = function(n) { - $.checkArgument(_.isNumber(n)); - return new BN(n); +exports.tagClass = { + 0: 'universal', + 1: 'application', + 2: 'context', + 3: 'private' }; +exports.tagClassByName = constants._reverse(exports.tagClass); -BN.fromString = function(str) { - $.checkArgument(_.isString(str)); - return new BN(str); +exports.tag = { + 0x00: 'end', + 0x01: 'bool', + 0x02: 'int', + 0x03: 'bitstr', + 0x04: 'octstr', + 0x05: 'null_', + 0x06: 'objid', + 0x07: 'objDesc', + 0x08: 'external', + 0x09: 'real', + 0x0a: 'enum', + 0x0b: 'embed', + 0x0c: 'utf8str', + 0x0d: 'relativeOid', + 0x10: 'seq', + 0x11: 'set', + 0x12: 'numstr', + 0x13: 'printstr', + 0x14: 't61str', + 0x15: 'videostr', + 0x16: 'ia5str', + 0x17: 'utctime', + 0x18: 'gentime', + 0x19: 'graphstr', + 0x1a: 'iso646str', + 0x1b: 'genstr', + 0x1c: 'unistr', + 0x1d: 'charstr', + 0x1e: 'bmpstr' }; +exports.tagByName = constants._reverse(exports.tag); -BN.fromBuffer = function(buf, opts) { - if (typeof opts !== 'undefined' && opts.endian === 'little') { - buf = reversebuf(buf); - } - var hex = buf.toString('hex'); - var bn = new BN(hex, 16); - return bn; -}; +},{"../constants":23}],23:[function(require,module,exports){ +var constants = exports; -/** - * Instantiate a BigNumber from a "signed magnitude buffer" - * (a buffer where the most significant bit represents the sign (0 = positive, -1 = negative)) - */ -BN.fromSM = function(buf, opts) { - var ret; - if (buf.length === 0) { - return BN.fromBuffer(new Buffer([0])); - } +// Helper +constants._reverse = function reverse(map) { + var res = {}; - var endian = 'big'; - if (opts) { - endian = opts.endian; - } - if (endian === 'little') { - buf = reversebuf(buf); - } + Object.keys(map).forEach(function(key) { + // Convert key to integer if it is stringified + if ((key | 0) == key) + key = key | 0; - if (buf[0] & 0x80) { - buf[0] = buf[0] & 0x7f; - ret = BN.fromBuffer(buf); - ret.neg().copy(ret); - } else { - ret = BN.fromBuffer(buf); - } - return ret; + var value = map[key]; + res[value] = key; + }); + + return res; }; +constants.der = require('./der'); -BN.prototype.toNumber = function() { - return parseInt(this.toString(10), 10); -}; +},{"./der":22}],24:[function(require,module,exports){ +var util = require('util'); -BN.prototype.toBuffer = function(opts) { - var buf, hex; - if (opts && opts.size) { - hex = this.toString(16, 2); - var natlen = hex.length / 2; - buf = new Buffer(hex, 'hex'); +var asn1 = require('../../asn1'); +var base = asn1.base; +var bignum = asn1.bignum; - if (natlen === opts.size) { - buf = buf; - } else if (natlen > opts.size) { - buf = BN.trim(buf, natlen); - } else if (natlen < opts.size) { - buf = BN.pad(buf, natlen, opts.size); - } - } else { - hex = this.toString(16, 2); - buf = new Buffer(hex, 'hex'); - } +// Import DER constants +var der = asn1.constants.der; - if (typeof opts !== 'undefined' && opts.endian === 'little') { - buf = reversebuf(buf); - } +function DERDecoder(entity) { + this.enc = 'der'; + this.name = entity.name; + this.entity = entity; - return buf; + // Construct base tree + this.tree = new DERNode(); + this.tree._init(entity.body); }; +module.exports = DERDecoder; -BN.prototype.toSMBigEndian = function() { - var buf; - if (this.cmp(BN.Zero) === -1) { - buf = this.neg().toBuffer(); - if (buf[0] & 0x80) { - buf = Buffer.concat([new Buffer([0x80]), buf]); - } else { - buf[0] = buf[0] | 0x80; - } - } else { - buf = this.toBuffer(); - if (buf[0] & 0x80) { - buf = Buffer.concat([new Buffer([0x00]), buf]); - } - } +DERDecoder.prototype.decode = function decode(data, options) { + if (!(data instanceof base.DecoderBuffer)) + data = new base.DecoderBuffer(data, options); - if (buf.length === 1 & buf[0] === 0) { - buf = new Buffer([]); - } - return buf; + return this.tree._decode(data, options); }; -BN.prototype.toSM = function(opts) { - var endian = opts ? opts.endian : 'big'; - var buf = this.toSMBigEndian(); +// Tree methods - if (endian === 'little') { - buf = reversebuf(buf); - } - return buf; -}; +function DERNode(parent) { + base.Node.call(this, 'der', parent); +} +util.inherits(DERNode, base.Node); -/** - * Create a BN from a "ScriptNum": - * This is analogous to the constructor for CScriptNum in bitcoind. Many ops in - * bitcoind's script interpreter use CScriptNum, which is not really a proper - * bignum. Instead, an error is thrown if trying to input a number bigger than - * 4 bytes. We copy that behavior here. - */ -BN.fromScriptNumBuffer = function(buf, fRequireMinimal) { - var nMaxNumSize = 4; - $.checkArgument(buf.length <= nMaxNumSize, new Error('script number overflow')); - if (fRequireMinimal && buf.length > 0) { - // Check that the number is encoded with the minimum possible - // number of bytes. - // - // If the most-significant-byte - excluding the sign bit - is zero - // then we're not minimal. Note how this test also rejects the - // negative-zero encoding, 0x80. - if ((buf[buf.length - 1] & 0x7f) === 0) { - // One exception: if there's more than one byte and the most - // significant bit of the second-most-significant-byte is set - // it would conflict with the sign bit. An example of this case - // is +-255, which encode to 0xff00 and 0xff80 respectively. - // (big-endian). - if (buf.length <= 1 || (buf[buf.length - 2] & 0x80) === 0) { - throw new Error('non-minimally encoded script number'); - } - } - } - return BN.fromSM(buf, { - endian: 'little' - }); -}; +DERNode.prototype._peekTag = function peekTag(buffer, tag) { + if (buffer.isEmpty()) + return false; -/** - * The corollary to the above, with the notable exception that we do not throw - * an error if the output is larger than four bytes. (Which can happen if - * performing a numerical operation that results in an overflow to more than 4 - * bytes). - */ -BN.prototype.toScriptNumBuffer = function() { - return this.toSM({ - endian: 'little' - }); + var state = buffer.save(); + var decodedTag = derDecodeTag(buffer, 'Failed to peek tag: "' + tag + '"'); + if (buffer.isError(decodedTag)) + return decodedTag; + + buffer.restore(state); + + return decodedTag.tag === tag || decodedTag.tagStr === tag; }; -BN.prototype.gt = function(b) { - return this.cmp(b) > 0; -}; +DERNode.prototype._decodeTag = function decodeTag(buffer, tag, any) { + var decodedTag = derDecodeTag(buffer, + 'Failed to decode tag of "' + tag + '"'); + if (buffer.isError(decodedTag)) + return decodedTag; -BN.prototype.lt = function(b) { - return this.cmp(b) < 0; -}; + var len = derDecodeLen(buffer, + decodedTag.primitive, + 'Failed to get length of "' + tag + '"'); -BN.trim = function(buf, natlen) { - return buf.slice(natlen - buf.length, buf.length); -}; + // Failure + if (buffer.isError(len)) + return len; -BN.pad = function(buf, natlen, size) { - var rbuf = new Buffer(size); - for (var i = 0; i < buf.length; i++) { - rbuf[rbuf.length - 1 - i] = buf[buf.length - 1 - i]; - } - for (i = 0; i < size - natlen; i++) { - rbuf[i] = 0; + if (!any && + decodedTag.tag !== tag && + decodedTag.tagStr !== tag && + decodedTag.tagStr + 'of' !== tag) { + return buffer.error('Failed to match tag: "' + tag + '"'); } - return rbuf; + + if (decodedTag.primitive || len !== null) + return buffer.skip(len, 'Failed to match body of: "' + tag + '"'); + + // Indefinite length... find END tag + var state = buffer.start(); + var res = this._skipUntilEnd( + buffer, + 'Failed to skip indefinite length body: "' + this.tag + '"'); + if (buffer.isError(res)) + return res; + + return buffer.cut(state); }; -module.exports = BN; +DERNode.prototype._skipUntilEnd = function skipUntilEnd(buffer, fail) { + while (true) { + var tag = derDecodeTag(buffer, fail); + if (buffer.isError(tag)) + return tag; + var len = derDecodeLen(buffer, tag.primitive, fail); + if (buffer.isError(len)) + return len; -}).call(this,require("buffer").Buffer) -},{"../util/preconditions":55,"bn.js":56,"buffer":104,"lodash":79}],19:[function(require,module,exports){ -(function (Buffer){ -'use strict'; + var res; + if (tag.primitive || len !== null) + res = buffer.skip(len) + else + res = this._skipUntilEnd(buffer, fail); -var BN = require('./bn'); -var Point = require('./point'); -var Signature = require('./signature'); -var PublicKey = require('../publickey'); -var Random = require('./random'); -var Hash = require('./hash'); -var BufferUtil = require('../util/buffer'); -var _ = require('lodash'); -var $ = require('../util/preconditions'); + // Failure + if (buffer.isError(res)) + return res; -var ECDSA = function ECDSA(obj) { - if (!(this instanceof ECDSA)) { - return new ECDSA(obj); - } - if (obj) { - this.set(obj); + if (tag.tagStr === 'end') + break; } }; -/* jshint maxcomplexity: 9 */ -ECDSA.prototype.set = function(obj) { - this.hashbuf = obj.hashbuf || this.hashbuf; - this.endian = obj.endian || this.endian; //the endianness of hashbuf - this.privkey = obj.privkey || this.privkey; - this.pubkey = obj.pubkey || (this.privkey ? this.privkey.publicKey : this.pubkey); - this.sig = obj.sig || this.sig; - this.k = obj.k || this.k; - this.verified = obj.verified || this.verified; - return this; +DERNode.prototype._decodeList = function decodeList(buffer, tag, decoder) { + var result = []; + while (!buffer.isEmpty()) { + var possibleEnd = this._peekTag(buffer, 'end'); + if (buffer.isError(possibleEnd)) + return possibleEnd; + + var res = decoder.decode(buffer, 'der'); + if (buffer.isError(res) && possibleEnd) + break; + result.push(res); + } + return result; }; -ECDSA.prototype.privkey2pubkey = function() { - this.pubkey = this.privkey.toPublicKey(); +DERNode.prototype._decodeStr = function decodeStr(buffer, tag) { + if (tag === 'octstr') { + return buffer.raw(); + } else if (tag === 'bitstr') { + var unused = buffer.readUInt8(); + if (buffer.isError(unused)) + return unused; + + return { unused: unused, data: buffer.raw() }; + } else { + return this.error('Decoding of string type: ' + tag + ' unsupported'); + } }; -ECDSA.prototype.calci = function() { - for (var i = 0; i < 4; i++) { - this.sig.i = i; - var Qprime; - try { - Qprime = this.toPublicKey(); - } catch (e) { - console.error(e); - continue; +DERNode.prototype._decodeObjid = function decodeObjid(buffer, values, relative) { + var identifiers = []; + var ident = 0; + while (!buffer.isEmpty()) { + var subident = buffer.readUInt8(); + ident <<= 7; + ident |= subident & 0x7f; + if ((subident & 0x80) === 0) { + identifiers.push(ident); + ident = 0; } + } + if (subident & 0x80) + identifiers.push(ident); - if (Qprime.point.eq(this.pubkey.point)) { - this.sig.compressed = this.pubkey.compressed; - return this; - } + var first = (identifiers[0] / 40) | 0; + var second = identifiers[0] % 40; + + if (relative) + result = identifiers; + else + result = [first, second].concat(identifiers.slice(1)); + + if (values) + result = values[result.join(' ')]; + + return result; +}; + +DERNode.prototype._decodeTime = function decodeTime(buffer, tag) { + var str = buffer.raw().toString(); + if (tag === 'gentime') { + var year = str.slice(0, 4) | 0; + var mon = str.slice(4, 6) | 0; + var day = str.slice(6, 8) | 0; + var hour = str.slice(8, 10) | 0; + var min = str.slice(10, 12) | 0; + var sec = str.slice(12, 14) | 0; + } else if (tag === 'utctime') { + var year = str.slice(0, 2) | 0; + var mon = str.slice(2, 4) | 0; + var day = str.slice(4, 6) | 0; + var hour = str.slice(6, 8) | 0; + var min = str.slice(8, 10) | 0; + var sec = str.slice(10, 12) | 0; + if (year < 70) + year = 2000 + year; + else + year = 1900 + year; + } else { + return this.error('Decoding ' + tag + ' time is not supported yet'); } - this.sig.i = undefined; - throw new Error('Unable to find valid recovery factor'); + return Date.UTC(year, mon - 1, day, hour, min, sec, 0); }; -ECDSA.fromString = function(str) { - var obj = JSON.parse(str); - return new ECDSA(obj); +DERNode.prototype._decodeNull = function decodeNull(buffer) { + return null; }; -ECDSA.prototype.randomK = function() { - var N = Point.getN(); - var k; - do { - k = BN.fromBuffer(Random.getRandomBuffer(32)); - } while (!(k.lt(N) && k.gt(BN.Zero))); - this.k = k; - return this; +DERNode.prototype._decodeBool = function decodeBool(buffer) { + var res = buffer.readUInt8(); + if (buffer.isError(res)) + return res; + else + return res !== 0; }; +DERNode.prototype._decodeInt = function decodeInt(buffer, values) { + var res = 0; -// https://tools.ietf.org/html/rfc6979#section-3.2 -ECDSA.prototype.deterministicK = function(badrs) { - /* jshint maxstatements: 25 */ - // if r or s were invalid when this function was used in signing, - // we do not want to actually compute r, s here for efficiency, so, - // we can increment badrs. explained at end of RFC 6979 section 3.2 - if (_.isUndefined(badrs)) { - badrs = 0; - } - var v = new Buffer(32); - v.fill(0x01); - var k = new Buffer(32); - k.fill(0x00); - var x = this.privkey.bn.toBuffer({ - size: 32 - }); - k = Hash.sha256hmac(Buffer.concat([v, new Buffer([0x00]), x, this.hashbuf]), k); - v = Hash.sha256hmac(v, k); - k = Hash.sha256hmac(Buffer.concat([v, new Buffer([0x01]), x, this.hashbuf]), k); - v = Hash.sha256hmac(v, k); - v = Hash.sha256hmac(v, k); - var T = BN.fromBuffer(v); - var N = Point.getN(); + // Bigint, return as it is (assume big endian) + var raw = buffer.raw(); + if (raw.length > 3) + return new bignum(raw); - // also explained in 3.2, we must ensure T is in the proper range (0, N) - for (var i = 0; i < badrs || !(T.lt(N) && T.gt(BN.Zero)); i++) { - k = Hash.sha256hmac(Buffer.concat([v, new Buffer([0x00])]), k); - v = Hash.sha256hmac(v, k); - v = Hash.sha256hmac(v, k); - T = BN.fromBuffer(v); + while (!buffer.isEmpty()) { + res <<= 8; + var i = buffer.readUInt8(); + if (buffer.isError(i)) + return i; + res |= i; } - this.k = T; - return this; + if (values) + res = values[res] || res; + + return res; }; -// Information about public key recovery: -// https://bitcointalk.org/index.php?topic=6430.0 -// http://stackoverflow.com/questions/19665491/how-do-i-get-an-ecdsa-public-key-from-just-a-bitcoin-signature-sec1-4-1-6-k -ECDSA.prototype.toPublicKey = function() { - /* jshint maxstatements: 25 */ - var i = this.sig.i; - $.checkArgument(i === 0 || i === 1 || i === 2 || i === 3, new Error('i must be equal to 0, 1, 2, or 3')); +DERNode.prototype._use = function use(entity) { + return entity._getDecoder('der').tree; +}; - var e = BN.fromBuffer(this.hashbuf); - var r = this.sig.r; - var s = this.sig.s; +// Utility methods - // A set LSB signifies that the y-coordinate is odd - var isYOdd = i & 1; +function derDecodeTag(buf, fail) { + var tag = buf.readUInt8(fail); + if (buf.isError(tag)) + return tag; - // The more significant bit specifies whether we should use the - // first or second candidate key. - var isSecondKey = i >> 1; + var cls = der.tagClass[tag >> 6]; + var primitive = (tag & 0x20) === 0; - var n = Point.getN(); - var G = Point.getG(); + // Multi-octet tag - load + if ((tag & 0x1f) === 0x1f) { + var oct = tag; + tag = 0; + while ((oct & 0x80) === 0x80) { + oct = buf.readUInt8(fail); + if (buf.isError(oct)) + return oct; - // 1.1 Let x = r + jn - var x = isSecondKey ? r.add(n) : r; - var R = Point.fromX(isYOdd, x); + tag <<= 7; + tag |= oct & 0x7f; + } + } else { + tag &= 0x1f; + } + var tagStr = der.tag[tag]; - // 1.4 Check that nR is at infinity - var nR = R.mul(n); + return { + cls: cls, + primitive: primitive, + tag: tag, + tagStr: tagStr + }; +} - if (!nR.isInfinity()) { - throw new Error('nR is not a valid curve point'); +function derDecodeLen(buf, primitive, fail) { + var len = buf.readUInt8(fail); + if (buf.isError(len)) + return len; + + // Indefinite form + if (!primitive && len === 0x80) + return null; + + // Definite form + if ((len & 0x80) === 0) { + // Short form + return len; } - // Compute -e from e - var eNeg = e.neg().mod(n); + // Long form + var num = len & 0x7f; + if (num >= 4) + return buf.error('length octect is too long'); - // 1.6.1 Compute Q = r^-1 (sR - eG) - // Q = r^-1 (sR + -eG) - var rInv = r.invm(n); + len = 0; + for (var i = 0; i < num; i++) { + len <<= 8; + var j = buf.readUInt8(fail); + if (buf.isError(j)) + return j; + len |= j; + } - //var Q = R.multiplyTwo(s, G, eNeg).mul(rInv); - var Q = R.mul(s).add(G.mul(eNeg)).mul(rInv); + return len; +} - var pubkey = PublicKey.fromPoint(Q, this.sig.compressed); +},{"../../asn1":16,"util":377}],25:[function(require,module,exports){ +var decoders = exports; - return pubkey; -}; +decoders.der = require('./der'); -ECDSA.prototype.sigError = function() { - /* jshint maxstatements: 25 */ - if (!BufferUtil.isBuffer(this.hashbuf) || this.hashbuf.length !== 32) { - return 'hashbuf must be a 32 byte buffer'; - } +},{"./der":24}],26:[function(require,module,exports){ +var util = require('util'); +var Buffer = require('buffer').Buffer; - var r = this.sig.r; - var s = this.sig.s; - if (!(r.gt(BN.Zero) && r.lt(Point.getN())) || !(s.gt(BN.Zero) && s.lt(Point.getN()))) { - return 'r and s not in range'; - } +var asn1 = require('../../asn1'); +var base = asn1.base; +var bignum = asn1.bignum; - var e = BN.fromBuffer(this.hashbuf, this.endian ? { - endian: this.endian - } : undefined); - var n = Point.getN(); - var sinv = s.invm(n); - var u1 = sinv.mul(e).mod(n); - var u2 = sinv.mul(r).mod(n); +// Import DER constants +var der = asn1.constants.der; - var p = Point.getG().mulAdd(u1, this.pubkey.point, u2); - if (p.isInfinity()) { - return 'p is infinity'; - } +function DEREncoder(entity) { + this.enc = 'der'; + this.name = entity.name; + this.entity = entity; - if (p.getX().mod(n).cmp(r) !== 0) { - return 'Invalid signature'; - } else { - return false; - } + // Construct base tree + this.tree = new DERNode(); + this.tree._init(entity.body); }; +module.exports = DEREncoder; -ECDSA.toLowS = function(s) { - //enforce low s - //see BIP 62, "low S values in signatures" - if (s.gt(BN.fromBuffer(new Buffer('7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0', 'hex')))) { - s = Point.getN().sub(s); - } - return s; +DEREncoder.prototype.encode = function encode(data, reporter) { + return this.tree._encode(data, reporter).join(); }; -ECDSA.prototype._findSignature = function(d, e) { - var N = Point.getN(); - var G = Point.getG(); - // try different values of k until r, s are valid - var badrs = 0; - var k, Q, r, s; - do { - if (!this.k || badrs > 0) { - this.deterministicK(badrs); - } - badrs++; - k = this.k; - Q = G.mul(k); - r = Q.x.mod(N); - s = k.invm(N).mul(e.add(d.mul(r))).mod(N); - } while (r.cmp(BN.Zero) <= 0 || s.cmp(BN.Zero) <= 0); +// Tree methods - s = ECDSA.toLowS(s); - return { - s: s, - r: r - }; +function DERNode(parent) { + base.Node.call(this, 'der', parent); +} +util.inherits(DERNode, base.Node); -}; +DERNode.prototype._encodeComposite = function encodeComposite(tag, + primitive, + cls, + content) { + var encodedTag = encodeTag(tag, primitive, cls, this.reporter); -ECDSA.prototype.sign = function() { - var hashbuf = this.hashbuf; - var privkey = this.privkey; - var d = privkey.bn; + // Short form + if (content.length < 0x80) { + var header = new Buffer(2); + header[0] = encodedTag; + header[1] = content.length; + return this._createEncoderBuffer([ header, content ]); + } - $.checkState(hashbuf && privkey && d, new Error('invalid parameters')); - $.checkState(BufferUtil.isBuffer(hashbuf) && hashbuf.length === 32, new Error('hashbuf must be a 32 byte buffer')); + // Long form + // Count octets required to store length + var lenOctets = 1; + for (var i = content.length; i >= 0x100; i >>= 8) + lenOctets++; - var e = BN.fromBuffer(hashbuf, this.endian ? { - endian: this.endian - } : undefined); + var header = new Buffer(1 + 1 + lenOctets); + header[0] = encodedTag; + header[1] = 0x80 | lenOctets; - var obj = this._findSignature(d, e); - obj.compressed = this.pubkey.compressed; + for (var i = 1 + lenOctets, j = content.length; j > 0; i--, j >>= 8) + header[i] = j & 0xff; - this.sig = new Signature(obj); - return this; + return this._createEncoderBuffer([ header, content ]); }; -ECDSA.prototype.signRandomK = function() { - this.randomK(); - return this.sign(); +DERNode.prototype._encodeStr = function encodeStr(str, tag) { + if (tag === 'octstr') + return this._createEncoderBuffer(str); + else if (tag === 'bitstr') + return this._createEncoderBuffer([ str.unused | 0, str.data ]); + return this.reporter.error('Encoding of string type: ' + tag + + ' unsupported'); }; -ECDSA.prototype.toString = function() { - var obj = {}; - if (this.hashbuf) { - obj.hashbuf = this.hashbuf.toString('hex'); - } - if (this.privkey) { - obj.privkey = this.privkey.toString(); - } - if (this.pubkey) { - obj.pubkey = this.pubkey.toString(); - } - if (this.sig) { - obj.sig = this.sig.toString(); +DERNode.prototype._encodeObjid = function encodeObjid(id, values, relative) { + if (typeof id === 'string') { + if (!values) + return this.reporter.error('string objid given, but no values map found'); + if (!values.hasOwnProperty(id)) + return this.reporter.error('objid not found in values map'); + id = values[id].split(/\s+/g); + for (var i = 0; i < id.length; i++) + id[i] |= 0; } - if (this.k) { - obj.k = this.k.toString(); + + if (!Array.isArray(id)) { + return this.reporter.error('objid() should be either array or string, ' + + 'got: ' + JSON.stringify(id)); } - return JSON.stringify(obj); -}; -ECDSA.prototype.verify = function() { - if (!this.sigError()) { - this.verified = true; - } else { - this.verified = false; + if (!relative) { + if (id[1] >= 40) + return this.reporter.error('Second objid identifier OOB'); + id.splice(0, 2, id[0] * 40 + id[1]); } - return this; -}; -ECDSA.sign = function(hashbuf, privkey, endian) { - return ECDSA().set({ - hashbuf: hashbuf, - endian: endian, - privkey: privkey - }).sign().sig; -}; - -ECDSA.verify = function(hashbuf, sig, pubkey, endian) { - return ECDSA().set({ - hashbuf: hashbuf, - endian: endian, - sig: sig, - pubkey: pubkey - }).verify().verified; -}; - -module.exports = ECDSA; - -}).call(this,require("buffer").Buffer) -},{"../publickey":37,"../util/buffer":53,"../util/preconditions":55,"./bn":18,"./hash":20,"./point":21,"./random":22,"./signature":23,"buffer":104,"lodash":79}],20:[function(require,module,exports){ -(function (Buffer){ -'use strict'; - -var hashjs = require('hash.js'); -var sha512 = require('sha512'); -var crypto = require('crypto'); -var BufferUtil = require('../util/buffer'); -var $ = require('../util/preconditions'); - -var Hash = module.exports; - -Hash.sha1 = function(buf) { - $.checkArgument(BufferUtil.isBuffer(buf)); - return crypto.createHash('sha1').update(buf).digest(); -}; + // Count number of octets + var size = 0; + for (var i = 0; i < id.length; i++) { + var ident = id[i]; + for (size++; ident >= 0x80; ident >>= 7) + size++; + } -Hash.sha1.blocksize = 512; + var objid = new Buffer(size); + var offset = objid.length - 1; + for (var i = id.length - 1; i >= 0; i--) { + var ident = id[i]; + objid[offset--] = ident & 0x7f; + while ((ident >>= 7) > 0) + objid[offset--] = 0x80 | (ident & 0x7f); + } -Hash.sha256 = function(buf) { - $.checkArgument(BufferUtil.isBuffer(buf)); - return crypto.createHash('sha256').update(buf).digest(); + return this._createEncoderBuffer(objid); }; -Hash.sha256.blocksize = 512; +function two(num) { + if (num <= 10) + return '0' + num; + else + return num; +} -Hash.sha256sha256 = function(buf) { - $.checkArgument(BufferUtil.isBuffer(buf)); - return Hash.sha256(Hash.sha256(buf)); -}; +DERNode.prototype._encodeTime = function encodeTime(time, tag) { + var str; + var date = new Date(time); -Hash.ripemd160 = function(buf) { - $.checkArgument(BufferUtil.isBuffer(buf)); - var hash = (new hashjs.ripemd160()).update(buf).digest(); - return new Buffer(hash); -}; + if (tag === 'gentime') { + str = [ + date.getFullYear(), + two(date.getUTCMonth() + 1), + two(date.getUTCDate()), + two(date.getUTCHours()), + two(date.getUTCMinutes()), + two(date.getUTCSeconds()), + 'Z' + ].join(''); + } else if (tag === 'utctime') { + str = [ + date.getFullYear() % 100, + two(date.getUTCMonth() + 1), + two(date.getUTCDate()), + two(date.getUTCHours()), + two(date.getUTCMinutes()), + two(date.getUTCSeconds()), + 'Z' + ].join(''); + } else { + this.reporter.error('Encoding ' + tag + ' time is not supported yet'); + } -Hash.sha256ripemd160 = function(buf) { - $.checkArgument(BufferUtil.isBuffer(buf)); - return Hash.ripemd160(Hash.sha256(buf)); + return this._encodeStr(str, 'octstr'); }; -Hash.sha512 = function(buf) { - $.checkArgument(BufferUtil.isBuffer(buf)); - var hash = sha512(buf); - return new Buffer(hash); +DERNode.prototype._encodeNull = function encodeNull() { + return this._createEncoderBuffer(''); }; -Hash.sha512.blocksize = 1024; +DERNode.prototype._encodeInt = function encodeInt(num, values) { + if (typeof num === 'string') { + if (!values) + return this.reporter.error('String int or enum given, but no values map'); + if (!values.hasOwnProperty(num)) { + return this.reporter.error('Values map doesn\'t contain: ' + + JSON.stringify(num)); + } + num = values[num]; + } -Hash.hmac = function(hashf, data, key) { - //http://en.wikipedia.org/wiki/Hash-based_message_authentication_code - //http://tools.ietf.org/html/rfc4868#section-2 - $.checkArgument(BufferUtil.isBuffer(data)); - $.checkArgument(BufferUtil.isBuffer(key)); - $.checkArgument(hashf.blocksize); + // Bignum, assume big endian + if (bignum !== null && num instanceof bignum) + num = new Buffer(num.toArray()); - var blocksize = hashf.blocksize / 8; + if (Buffer.isBuffer(num)) { + var size = num.length; + if (num.length === 0) + size++; - if (key.length > blocksize) { - key = hashf(key); - } else if (key < blocksize) { - var fill = new Buffer(blocksize); - fill.fill(0); - key.copy(fill); - key = fill; + var out = new Buffer(size); + num.copy(out); + if (num.length === 0) + out[0] = 0 + return this._createEncoderBuffer(out); } - var o_key = new Buffer(blocksize); - o_key.fill(0x5c); + if (num < 0x100) + return this._createEncoderBuffer(num); - var i_key = new Buffer(blocksize); - i_key.fill(0x36); + var size = 1; + for (var i = num; i >= 0x100; i >>= 8) + size++; - var o_key_pad = new Buffer(blocksize); - var i_key_pad = new Buffer(blocksize); - for (var i = 0; i < blocksize; i++) { - o_key_pad[i] = o_key[i] ^ key[i]; - i_key_pad[i] = i_key[i] ^ key[i]; + var out = new Buffer(size); + for (var i = out.length - 1; i >= 0; i--) { + out[i] = num & 0xff; + num >>= 8; } - return hashf(Buffer.concat([o_key_pad, hashf(Buffer.concat([i_key_pad, data]))])); + return this._createEncoderBuffer(out); }; -Hash.sha256hmac = function(data, key) { - return Hash.hmac(Hash.sha256, data, key); +DERNode.prototype._encodeBool = function encodeBool(value) { + return this._createEncoderBuffer(value ? 0xff : 0); }; -Hash.sha512hmac = function(data, key) { - return Hash.hmac(Hash.sha512, data, key); +DERNode.prototype._use = function use(entity) { + return entity._getEncoder('der').tree; }; -}).call(this,require("buffer").Buffer) -},{"../util/buffer":53,"../util/preconditions":55,"buffer":104,"crypto":108,"hash.js":72,"sha512":82}],21:[function(require,module,exports){ -(function (Buffer){ -'use strict'; +// Utility methods -var BN = require('./bn'); -var BufferUtil = require('../util/buffer'); -var ec = require('elliptic').curves.secp256k1; -var ecPoint = ec.curve.point.bind(ec.curve); -var ecPointFromX = ec.curve.pointFromX.bind(ec.curve); +function encodeTag(tag, primitive, cls, reporter) { + var res; -/** - * - * Instantiate a valid secp256k1 Point from the X and Y coordinates. - * - * @param {BN|String} x - The X coordinate - * @param {BN|String} y - The Y coordinate - * @link https://github.com/indutny/elliptic - * @augments elliptic.curve.point - * @throws {Error} A validation error if exists - * @returns {Point} An instance of Point - * @constructor - */ -var Point = function Point(x, y, isRed) { - var point = ecPoint(x, y, isRed); - point.validate(); - return point; -}; + if (tag === 'seqof') + tag = 'seq'; + else if (tag === 'setof') + tag = 'set'; -Point.prototype = Object.getPrototypeOf(ec.curve.point()); + if (der.tagByName.hasOwnProperty(tag)) + res = der.tagByName[tag]; + else if (typeof tag === 'number' && (tag | 0) === tag) + res = tag; + else + return reporter.error('Unknown tag: ' + tag); -/** - * - * Instantiate a valid secp256k1 Point from only the X coordinate - * - * @param {boolean} odd - If the Y coordinate is odd - * @param {BN|String} x - The X coordinate - * @throws {Error} A validation error if exists - * @returns {Point} An instance of Point - */ -Point.fromX = function fromX(odd, x){ - var point = ecPointFromX(odd, x); - point.validate(); - return point; -}; + if (res >= 0x1f) + return reporter.error('Multi-octet tag encoding unsupported'); -/** - * - * Will return a secp256k1 ECDSA base point. - * - * @link https://en.bitcoin.it/wiki/Secp256k1 - * @returns {Point} An instance of the base point. - */ -Point.getG = function getG() { - return ec.curve.g; -}; + if (!primitive) + res |= 0x20; -/** - * - * Will return the max of range of valid private keys as governed by the secp256k1 ECDSA standard. - * - * @link https://en.bitcoin.it/wiki/Private_key#Range_of_valid_ECDSA_private_keys - * @returns {BN} A BN instance of the number of points on the curve - */ -Point.getN = function getN() { - return new BN(ec.curve.n.toArray()); -}; + res |= (der.tagClassByName[cls || 'universal'] << 6); -Point.prototype._getX = Point.prototype.getX; + return res; +} -/** - * - * Will return the X coordinate of the Point - * - * @returns {BN} A BN instance of the X coordinate - */ -Point.prototype.getX = function getX() { - return new BN(this._getX().toArray()); -}; +},{"../../asn1":16,"buffer":209,"util":377}],27:[function(require,module,exports){ +var encoders = exports; -Point.prototype._getY = Point.prototype.getY; +encoders.der = require('./der'); -/** - * - * Will return the Y coordinate of the Point - * - * @returns {BN} A BN instance of the Y coordinate - */ -Point.prototype.getY = function getY() { - return new BN(this._getY().toArray()); -}; +},{"./der":26}],28:[function(require,module,exports){ +// Utils -/** - * - * Will determine if the point is valid - * - * @link https://www.iacr.org/archive/pkc2003/25670211/25670211.pdf - * @param {Point} An instance of Point - * @throws {Error} A validation error if exists - * @returns {Point} An instance of the same Point - */ -Point.prototype.validate = function validate() { +function assert(val, msg) { + if (!val) + throw new Error(msg || 'Assertion failed'); +} - if (this.isInfinity()){ - throw new Error('Point cannot be equal to Infinity'); - } +function assertEqual(l, r, msg) { + if (l != r) + throw new Error(msg || ('Assertion failed: ' + l + ' != ' + r)); +} - if (this.getX().cmp(BN.Zero) === 0 || this.getY().cmp(BN.Zero) === 0){ - throw new Error('Invalid x,y value for curve, cannot equal 0.'); - } +// 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 +} - var p2 = ecPointFromX(this.getY().isOdd(), this.getX()); +// BN - if (p2.y.cmp(this.y) !== 0) { - throw new Error('Invalid y value for curve.'); +function BN(number, base) { + // May be `new BN(bn)` ? + if (number !== null && + typeof number === 'object' && + Array.isArray(number.words)) { + return number; } - var xValidRange = (this.getX().gt(BN.Minus1) && this.getX().lt(Point.getN())); - var yValidRange = (this.getY().gt(BN.Minus1) && this.getY().lt(Point.getN())); + this.sign = false; + this.words = null; + this.length = 0; - if ( !xValidRange || !yValidRange ) { - throw new Error('Point does not lie on the curve'); - } + // Reduction context + this.red = null; - //todo: needs test case - if (!(this.mul(Point.getN()).isInfinity())) { - throw new Error('Point times N must be infinity'); - } + if (number !== null) + this._init(number || 0, base || 10); +} +if (typeof module === 'object') + module.exports = BN; - return this; +BN.BN = BN; +BN.wordSize = 26; -}; +BN.prototype._init = function init(number, base) { + if (typeof number === 'number') { + if (number < 0) { + this.sign = true; + number = -number; + } + if (number < 0x4000000) { + this.words = [ number & 0x3ffffff ]; + this.length = 1; + } else { + this.words = [ + number & 0x3ffffff, + (number / 0x4000000) & 0x3ffffff + ]; + this.length = 2; + } + return; + } else if (typeof number === 'object') { + // Perhaps a Uint8Array + assert(typeof number.length === 'number'); + 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; -Point.pointToCompressed = function pointToCompressed(point) { - var xbuf = point.getX().toBuffer({size: 32}); - var ybuf = point.getY().toBuffer({size: 32}); + // Assume big-endian + var off = 0; + for (var i = number.length - 1, j = 0; i >= 0; i -= 3) { + var 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++; + } + } - var prefix; - var odd = ybuf[ybuf.length - 1] % 2; - if (odd) { - prefix = new Buffer([0x03]); - } else { - prefix = new Buffer([0x02]); + return this.strip(); } - return BufferUtil.concat([prefix, xbuf]); -}; - -module.exports = Point; - -}).call(this,require("buffer").Buffer) -},{"../util/buffer":53,"./bn":18,"buffer":104,"elliptic":58}],22:[function(require,module,exports){ -(function (process,Buffer){ -'use strict'; - -function Random() { -} - -/* secure random bytes that sometimes throws an error due to lack of entropy */ -Random.getRandomBuffer = function(size) { - if (process.browser) - return Random.getRandomBufferBrowser(size); - else - return Random.getRandomBufferNode(size); -}; - -Random.getRandomBufferNode = function(size) { - var crypto = require('crypto'); - return crypto.randomBytes(size); -}; + if (base === 'hex') + base = 16; + assert(base <= 16); -Random.getRandomBufferBrowser = function(size) { - if (!window.crypto && !window.msCrypto) - throw new Error('window.crypto not available'); + number = number.toString().replace(/\s+/g, ''); + var start = 0; + if (number[0] === '-') + start++; - if (window.crypto && window.crypto.getRandomValues) - var crypto = window.crypto; - else if (window.msCrypto && window.msCrypto.getRandomValues) //internet explorer - var crypto = window.msCrypto; + if (base === 16) + this._parseHex(number, start); else - throw new Error('window.crypto.getRandomValues not available'); + this._parseBase(number, base, start); - var bbuf = new Uint8Array(size); - crypto.getRandomValues(bbuf); - var buf = new Buffer(bbuf); + if (number[0] === '-') + this.sign = true; - return buf; + this.strip(); }; -/* insecure random bytes, but it never fails */ -Random.getPseudoRandomBuffer = function(size) { - var b32 = 0x100000000; - var b = new Buffer(size); - var 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; - for (var i = 0; i <= size; i++) { - var j = Math.floor(i / 4); - var k = i - j * 4; - if (k === 0) { - r = Math.random() * b32; - b[i] = r & 0xff; - } else { - b[i] = (r = r >>> 8) & 0xff; + // Scan 24-bit chunks and add them to the number + var off = 0; + for (var i = number.length - 6, j = 0; i >= start; i -= 6) { + var w = parseInt(number.slice(i, i + 6), 16); + this.words[j] |= (w << off) & 0x3ffffff; + this.words[j + 1] |= w >>> (26 - off) & 0x3fffff; + off += 24; + if (off >= 26) { + off -= 26; + j++; } } - - return b; + if (i + 6 !== start) { + var w = parseInt(number.slice(start, i + 6), 16); + this.words[j] |= (w << off) & 0x3ffffff; + this.words[j + 1] |= w >>> (26 - off) & 0x3fffff; + } + this.strip(); }; -module.exports = Random; - -}).call(this,require('_process'),require("buffer").Buffer) -},{"_process":252,"buffer":104,"crypto":108}],23:[function(require,module,exports){ -(function (Buffer){ -'use strict'; +BN.prototype._parseBase = function parseBase(number, base, start) { + // Initialize as zero + this.words = [ 0 ]; + this.length = 1; -var BN = require('./bn'); -var _ = require('lodash'); -var $ = require('../util/preconditions'); -var BufferUtil = require('../util/buffer'); + var word = 0; + var q = 1; + var p = 0; + var bigQ = null; + for (var i = start; i < number.length; i++) { + var digit; + var ch = number[i]; + if (base === 10 || ch <= '9') + digit = ch | 0; + else if (ch >= 'a') + digit = ch.charCodeAt(0) - 97 + 10; + else + digit = ch.charCodeAt(0) - 65 + 10; + word *= base; + word += digit; + q *= base; + p++; -var Signature = function Signature(r, s) { - if (!(this instanceof Signature)) { - return new Signature(r, s); + if (q > 0xfffff) { + assert(q <= 0x3ffffff); + if (!bigQ) + bigQ = new BN(q); + this.mul(bigQ).copy(this); + this.iadd(new BN(word)); + word = 0; + q = 1; + p = 0; + } } - if (r instanceof BN) { - this.set({ - r: r, - s: s - }); - } else if (r) { - var obj = r; - this.set(obj); + if (p !== 0) { + this.mul(new BN(q)).copy(this); + this.iadd(new BN(word)); } }; -/* jshint maxcomplexity: 7 */ -Signature.prototype.set = function(obj) { - this.r = obj.r || this.r || undefined; - this.s = obj.s || this.s || undefined; - this.i = typeof obj.i !== 'undefined' ? obj.i : this.i; //public key recovery parameter in range [0, 3] - this.compressed = typeof obj.compressed !== 'undefined' ? - obj.compressed : this.compressed; //whether the recovered pubkey is compressed - return this; +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.sign = this.sign; + dest.red = this.red; }; -Signature.fromCompact = function(buf) { - var sig = new Signature(); - //TODO: handle uncompressed pubkeys - var compressed = true; - var i = buf.slice(0, 1)[0] - 27 - 4; - var b2 = buf.slice(1, 33); - var b3 = buf.slice(33, 65); - - $.checkArgument(i === 0 || i === 1 || i === 2 || i === 3, new Error('i must be 0, 1, 2, or 3')); - $.checkArgument(b2.length === 32, new Error('r must be 32 bytes')); - $.checkArgument(b3.length === 32, new Error('s must be 32 bytes')); - - sig.compressed = compressed; - sig.i = i; - sig.r = BN.fromBuffer(b2); - sig.s = BN.fromBuffer(b3); - - return sig; +BN.prototype.clone = function clone() { + var r = new BN(null); + this.copy(r); + return r; }; -Signature.fromDER = Signature.fromBuffer = function(buf, strict) { - var obj = Signature.parseDER(buf, strict); - var sig = new Signature(); - - sig.r = obj.r; - sig.s = obj.s; - - return sig; +// 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(); }; -// The format used in a tx -Signature.fromTxFormat = function(buf) { - var nhashtype = buf.readUInt8(buf.length - 1); - var derbuf = buf.slice(0, buf.length - 1); - var sig = new Signature.fromDER(derbuf, false); - sig.nhashtype = nhashtype; - return sig; +BN.prototype._normSign = function _normSign() { + // -0 = 0 + if (this.length === 1 && this.words[0] === 0) + this.sign = false; + return this; }; -Signature.fromString = function(str) { - var buf = new Buffer(str, 'hex'); - return Signature.fromDER(buf); +BN.prototype.inspect = function inspect() { + return (this.red ? ''; }; - -/** - * In order to mimic the non-strict DER encoding of OpenSSL, set strict = false. - */ -Signature.parseDER = function(buf, strict) { - $.checkArgument(BufferUtil.isBuffer(buf), new Error('DER formatted signature should be a buffer')); - if (_.isUndefined(strict)) { - strict = true; +/* +function _zero(n) { + var code = ''; + for (var i = n - 1; i > 0; i--) { + var pad = ''; + for (var j = 0; j < n - i; j++) + pad += '0'; + code += 'if (w.length === ' + i + ') return \'' + pad + '\' + w;\n'; } + code += 'return w'; - var header = buf[0]; - $.checkArgument(header === 0x30, new Error('Header byte should be 0x30')); - - var length = buf[1]; - var buflength = buf.slice(2).length; - $.checkArgument(!strict || length === buflength, new Error('Length byte should length of what follows')); + return new Function('w', code); +} - length = length < buflength ? length : buflength; +var zero6 = _zero(6); +var zero14 = _zero(14); +*/ - var rheader = buf[2 + 0]; - $.checkArgument(rheader === 0x02, new Error('Integer byte for r should be 0x02')); +// Sadly chrome apps could not contain `new Function()` calls +function zero6(w) { + if (w.length === 5) return '0' + w; + if (w.length === 4) return '00' + w; + if (w.length === 3) return '000' + w; + if (w.length === 2) return '0000' + w; + if (w.length === 1) return '00000' + w; + return w; +} + +function zero14(w) { + if (w.length === 13) return '0' + w; + if (w.length === 12) return '00' + w; + if (w.length === 11) return '000' + w; + if (w.length === 10) return '0000' + w; + if (w.length === 9) return '00000' + w; + if (w.length === 8) return '000000' + w; + if (w.length === 7) return '0000000' + w; + if (w.length === 6) return '00000000' + w; + if (w.length === 5) return '000000000' + w; + if (w.length === 4) return '0000000000' + w; + if (w.length === 3) return '00000000000' + w; + if (w.length === 2) return '000000000000' + w; + if (w.length === 1) return '0000000000000' + w; + return w; +} + +// Precomputed divisor for `.toString(10)` = 10 ^ 14 +var div10 = new BN(null); +div10.words = [ 0x7a4000, 0x16bcc4 ]; +div10.length = 2; + +BN.prototype.toString = function toString(base) { + base = base || 10; + if (base === 16 || base === 'hex') { + var 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 = zero6(word) + out; + else + out = word + out; + off += 2; + if (off >= 26) { + off -= 26; + i--; + } + } + if (carry !== 0) + out = carry.toString(16) + out; + if (this.sign) + out = '-' + out; + return out; + } else if (base === 10) { + var out = ''; + var c = this.clone(); + c.sign = false; + while (c.cmpn(0) !== 0) { + var r = c.modn(1000000); + c = c.idivn(1000000); - var rlength = buf[2 + 1]; - var rbuf = buf.slice(2 + 2, 2 + 2 + rlength); - var r = BN.fromBuffer(rbuf); - var rneg = buf[2 + 1 + 1] === 0x00 ? true : false; - $.checkArgument(rlength === rbuf.length, new Error('Length of r incorrect')); + if (c.cmpn(0) !== 0) + out = zero6(r + '') + out; + else + out = r + out; + } + if (this.cmpn(0) === 0) + out = '0' + out; + if (this.sign) + out = '-' + out; + return out; + } else { + assert(false, 'Only 16 and 10 base are supported'); + } +}; - var sheader = buf[2 + 2 + rlength + 0]; - $.checkArgument(sheader === 0x02, new Error('Integer byte for s should be 0x02')); +BN.prototype.toJSON = function toJSON() { + return this.toString(16); +}; - var slength = buf[2 + 2 + rlength + 1]; - var sbuf = buf.slice(2 + 2 + rlength + 2, 2 + 2 + rlength + 2 + slength); - var s = BN.fromBuffer(sbuf); - var sneg = buf[2 + 2 + rlength + 2 + 2] === 0x00 ? true : false; - $.checkArgument(slength === sbuf.length, new Error('Length of s incorrect')); +BN.prototype.toArray = function toArray() { + this.strip(); + var res = new Array(this.byteLength()); + res[0] = 0; - var sumlength = 2 + 2 + rlength + 2 + slength; - $.checkArgument(length === sumlength - 2, new Error('Length of signature incorrect')); + var q = this.clone(); + for (var i = 0; q.cmpn(0) !== 0; i++) { + var b = q.andln(0xff); + q.ishrn(8); - var obj = { - header: header, - length: length, - rheader: rheader, - rlength: rlength, - rneg: rneg, - rbuf: rbuf, - r: r, - sheader: sheader, - slength: slength, - sneg: sneg, - sbuf: sbuf, - s: s - }; + // Assume big-endian + res[res.length - i - 1] = b; + } - return obj; + return res; }; +/* +function genCountBits(bits) { + var arr = []; -Signature.prototype.toCompact = function(i, compressed) { - i = typeof i === 'number' ? i : this.i; - compressed = typeof compressed === 'boolean' ? compressed : this.compressed; - - if (!(i === 0 || i === 1 || i === 2 || i === 3)) { - throw new Error('i must be equal to 0, 1, 2, or 3'); + for (var i = bits - 1; i >= 0; i--) { + var bit = '0x' + (1 << i).toString(16); + arr.push('w >= ' + bit + ' ? ' + (i + 1)); } - var val = i + 27 + 4; - if (compressed === false) - val = val - 4; - var b1 = new Buffer([val]); - var b2 = this.r.toBuffer({ - size: 32 - }); - var b3 = this.s.toBuffer({ - size: 32 - }); - return Buffer.concat([b1, b2, b3]); + return new Function('w', 'return ' + arr.join(' :\n') + ' :\n0;'); }; -Signature.prototype.toBuffer = Signature.prototype.toDER = function() { - var rnbuf = this.r.toBuffer(); - var snbuf = this.s.toBuffer(); - - var rneg = rnbuf[0] & 0x80 ? true : false; - var sneg = snbuf[0] & 0x80 ? true : false; +BN.prototype._countBits = genCountBits(26); +*/ - var rbuf = rneg ? Buffer.concat([new Buffer([0x00]), rnbuf]) : rnbuf; - var sbuf = sneg ? Buffer.concat([new Buffer([0x00]), snbuf]) : snbuf; +// Sadly chrome apps could not contain `new Function()` calls +BN.prototype._countBits = function _countBits(w) { + return w >= 0x2000000 ? 26 : + w >= 0x1000000 ? 25 : + w >= 0x800000 ? 24 : + w >= 0x400000 ? 23 : + w >= 0x200000 ? 22 : + w >= 0x100000 ? 21 : + w >= 0x80000 ? 20 : + w >= 0x40000 ? 19 : + w >= 0x20000 ? 18 : + w >= 0x10000 ? 17 : + w >= 0x8000 ? 16 : + w >= 0x4000 ? 15 : + w >= 0x2000 ? 14 : + w >= 0x1000 ? 13 : + w >= 0x800 ? 12 : + w >= 0x400 ? 11 : + w >= 0x200 ? 10 : + w >= 0x100 ? 9 : + w >= 0x80 ? 8 : + w >= 0x40 ? 7 : + w >= 0x20 ? 6 : + w >= 0x10 ? 5 : + w >= 0x8 ? 4 : + w >= 0x4 ? 3 : + w >= 0x2 ? 2 : + w >= 0x1 ? 1 : + 0; +}; - var rlength = rbuf.length; - var slength = sbuf.length; - var length = 2 + rlength + 2 + slength; - var rheader = 0x02; - var sheader = 0x02; - var header = 0x30; +// Return number of used bits in a BN +BN.prototype.bitLength = function bitLength() { + var hi = 0; + var w = this.words[this.length - 1]; + var hi = this._countBits(w); + return (this.length - 1) * 26 + hi; +}; - var der = Buffer.concat([new Buffer([header, length, rheader, rlength]), rbuf, new Buffer([sheader, slength]), sbuf]); - return der; +BN.prototype.byteLength = function byteLength() { + var hi = 0; + var w = this.words[this.length - 1]; + return Math.ceil(this.bitLength() / 8); }; -Signature.prototype.toString = function() { - var buf = this.toDER(); - return buf.toString('hex'); +// Return negative clone of `this` +BN.prototype.neg = function neg() { + if (this.cmpn(0) === 0) + return this.clone(); + + var r = this.clone(); + r.sign = !this.sign; + return r; }; -/** - * This function is translated from bitcoind's IsDERSignature and is used in - * the script interpreter. This "DER" format actually includes an extra byte, - * the nhashtype, at the end. It is really the tx format, not DER format. - * - * A canonical signature exists of: [30] [total len] [02] [len R] [R] [02] [len S] [S] [hashtype] - * Where R and S are not negative (their first byte has its highest bit not set), and not - * excessively padded (do not start with a 0 byte, unless an otherwise negative number follows, - * in which case a single 0 byte is necessary and even required). - * - * See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623 - */ -Signature.isTxDER = function(buf) { - if (buf.length < 9) { - // Non-canonical signature: too short - return false; - } - if (buf.length > 73) { - // Non-canonical signature: too long - return false; - } - if (buf[0] !== 0x30) { - // Non-canonical signature: wrong type - return false; - } - if (buf[1] !== buf.length - 3) { - // Non-canonical signature: wrong length marker - return false; - } - var nLenR = buf[3]; - if (5 + nLenR >= buf.length) { - // Non-canonical signature: S length misplaced - return false; - } - var nLenS = buf[5 + nLenR]; - if ((nLenR + nLenS + 7) !== buf.length) { - // Non-canonical signature: R+S length mismatch - return false; - } +// Add `num` to `this` in-place +BN.prototype.iadd = function iadd(num) { + // negative + positive + if (this.sign && !num.sign) { + this.sign = false; + var r = this.isub(num); + this.sign = !this.sign; + return this._normSign(); - var R = buf.slice(4); - if (buf[4 - 2] !== 0x02) { - // Non-canonical signature: R value type mismatch - return false; - } - if (nLenR === 0) { - // Non-canonical signature: R length is zero - return false; - } - if (R[0] & 0x80) { - // Non-canonical signature: R value negative - return false; - } - if (nLenR > 1 && (R[0] === 0x00) && !(R[1] & 0x80)) { - // Non-canonical signature: R value excessively padded - return false; + // positive + negative + } else if (!this.sign && num.sign) { + num.sign = false; + var r = this.isub(num); + num.sign = true; + return r._normSign(); } - var S = buf.slice(6 + nLenR); - if (buf[6 + nLenR - 2] !== 0x02) { - // Non-canonical signature: S value type mismatch - return false; - } - if (nLenS === 0) { - // Non-canonical signature: S length is zero - return false; + // a.length > b.length + var a; + var b; + if (this.length > num.length) { + a = this; + b = num; + } else { + a = num; + b = this; } - if (S[0] & 0x80) { - // Non-canonical signature: S value negative - return false; + + var carry = 0; + for (var i = 0; i < b.length; i++) { + var r = a.words[i] + b.words[i] + carry; + this.words[i] = r & 0x3ffffff; + carry = r >>> 26; } - if (nLenS > 1 && (S[0] === 0x00) && !(S[1] & 0x80)) { - // Non-canonical signature: S value excessively padded - return false; + for (; carry !== 0 && i < a.length; i++) { + var r = a.words[i] + carry; + this.words[i] = r & 0x3ffffff; + carry = r >>> 26; } - return true; -}; -/** - * Compares to bitcoind's IsLowDERSignature - * See also ECDSA signature algorithm which enforces this. - * See also BIP 62, "low S values in signatures" - */ -Signature.prototype.hasLowS = function() { - if (this.s.lt(new BN(1)) || - this.s.gt(new BN('7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0'))) { - return false; + 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 true; + + return this; }; -/** - * @returns true if the nhashtype is exactly equal to one of the standard options or combinations thereof. - * Translated from bitcoind's IsDefinedHashtypeSignature - */ -Signature.prototype.hasDefinedHashtype = function() { - if (this.nhashtype < Signature.SIGHASH_ALL || this.nhashtype > Signature.SIGHASH_SINGLE) { - return false; +// Add `num` to `this` +BN.prototype.add = function add(num) { + if (num.sign && !this.sign) { + num.sign = false; + var res = this.sub(num); + num.sign = true; + return res; + } else if (!num.sign && this.sign) { + this.sign = false; + var res = num.sub(this); + this.sign = true; + return res; } - return true; -}; -Signature.prototype.toTxFormat = function() { - var derbuf = this.toDER(); - var buf = new Buffer(1); - buf.writeUInt8(this.nhashtype, 0); - return Buffer.concat([derbuf, buf]); + if (this.length > num.length) + return this.clone().iadd(num); + else + return num.clone().iadd(this); }; -Signature.SIGHASH_ALL = 0x01; -Signature.SIGHASH_NONE = 0x02; -Signature.SIGHASH_SINGLE = 0x03; -Signature.SIGHASH_ANYONECANPAY = 0x80; +// Subtract `num` from `this` in-place +BN.prototype.isub = function isub(num) { + // this - (-num) = this + num + if (num.sign) { + num.sign = false; + var r = this.iadd(num); + num.sign = true; + return r._normSign(); -module.exports = Signature; + // -this - num = -(this + num) + } else if (this.sign) { + this.sign = false; + this.iadd(num); + this.sign = true; + return this._normSign(); + } -}).call(this,require("buffer").Buffer) -},{"../util/buffer":53,"../util/preconditions":55,"./bn":18,"buffer":104,"lodash":79}],24:[function(require,module,exports){ -(function (Buffer){ -'use strict'; + // At this point both numbers are positive + var cmp = this.cmp(num); -var _ = require('lodash'); -var bs58 = require('bs58'); -var buffer = require('buffer'); + // Optimization - zeroify + if (cmp === 0) { + this.sign = false; + this.length = 1; + this.words[0] = 0; + return this; + } -var ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'.split(''); + // a > b + if (cmp > 0) { + var a = this; + var b = num; + } else { + var a = num; + var b = this; + } -var Base58 = function Base58(obj) { - /* jshint maxcomplexity: 8 */ - if (!(this instanceof Base58)) { - return new Base58(obj); + var carry = 0; + for (var i = 0; i < b.length; i++) { + var r = a.words[i] - b.words[i] - carry; + if (r < 0) { + r += 0x4000000; + carry = 1; + } else { + carry = 0; + } + this.words[i] = r; } - if (Buffer.isBuffer(obj)) { - var buf = obj; - this.fromBuffer(buf); - } else if (typeof obj === 'string') { - var str = obj; - this.fromString(str); - } else if (obj) { - this.set(obj); + for (; carry !== 0 && i < a.length; i++) { + var r = a.words[i] - carry; + if (r < 0) { + r += 0x4000000; + carry = 1; + } else { + carry = 0; + } + this.words[i] = r; } -}; -Base58.validCharacters = function validCharacters(chars) { - if (buffer.Buffer.isBuffer(chars)) { - chars = chars.toString(); - } - return _.all(_.map(chars, function(char) { return _.contains(ALPHABET, char); })); -}; + // 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); -Base58.prototype.set = function(obj) { - this.buf = obj.buf || this.buf || undefined; - return this; + if (a !== this) + this.sign = true; + + return this.strip(); }; -Base58.encode = function(buf) { - if (!buffer.Buffer.isBuffer(buf)) { - throw new Error('Input should be a buffer'); - } - return bs58.encode(buf); -}; - -Base58.decode = function(str) { - if (typeof str !== 'string') { - throw new Error('Input should be a string'); - } - return new Buffer(bs58.decode(str)); -}; - -Base58.prototype.fromBuffer = function(buf) { - this.buf = buf; - return this; +// Subtract `num` from `this` +BN.prototype.sub = function sub(num) { + return this.clone().isub(num); }; -Base58.prototype.fromString = function(str) { - var buf = Base58.decode(str); - this.buf = buf; - return this; -}; +/* +// NOTE: This could be potentionally used to generate loop-less multiplications +function _genCombMulTo(alen, blen) { + var len = alen + blen - 1; + var src = [ + 'var a = this.words, b = num.words, o = out.words, c = 0, w, ' + + 'mask = 0x3ffffff, shift = 0x4000000;', + 'out.length = ' + len + ';' + ]; + for (var k = 0; k < len; k++) { + var minJ = Math.max(0, k - alen + 1); + var maxJ = Math.min(k, blen - 1); -Base58.prototype.toBuffer = function() { - return this.buf; -}; + for (var j = minJ; j <= maxJ; j++) { + var i = k - j; + var mul = 'a[' + i + '] * b[' + j + ']'; -Base58.prototype.toString = function() { - return Base58.encode(this.buf); -}; + if (j === minJ) { + src.push('w = ' + mul + ' + c;'); + src.push('c = (w / shift) | 0;'); + } else { + src.push('w += ' + mul + ';'); + src.push('c += (w / shift) | 0;'); + } + src.push('w &= mask;'); + } + src.push('o[' + k + '] = w;'); + } + src.push('if (c !== 0) {', + ' o[' + k + '] = c;', + ' out.length++;', + '}', + 'return out;'); -module.exports = Base58; + return src.join('\n'); +} +*/ -}).call(this,require("buffer").Buffer) -},{"bs58":57,"buffer":104,"lodash":79}],25:[function(require,module,exports){ -(function (Buffer){ -'use strict'; +// Multiply `this` by `num` and store data in out +BN.prototype.mulTo = function mulTo(num, out) { + out.sign = num.sign !== this.sign; + out.length = this.length + num.length; -var _ = require('lodash'); -var Base58 = require('./base58'); -var buffer = require('buffer'); -var sha256sha256 = require('../crypto/hash').sha256sha256; + var carry = 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 = carry >>> 26; + var rword = carry & 0x3ffffff; + var maxJ = Math.min(k, num.length - 1); + for (var j = Math.max(0, k - this.length + 1); j <= maxJ; j++) { + var i = k - j; + var a = this.words[i]; + var b = num.words[j]; + var r = a * b; -var Base58Check = function Base58Check(obj) { - if (!(this instanceof Base58Check)) - return new Base58Check(obj); - if (Buffer.isBuffer(obj)) { - var buf = obj; - this.fromBuffer(buf); - } else if (typeof obj === 'string') { - var str = obj; - this.fromString(str); - } else if (obj) { - this.set(obj); + var lo = r & 0x3ffffff; + ncarry += (r / 0x4000000) | 0; + lo += rword; + rword = lo & 0x3ffffff; + ncarry += lo >>> 26; + } + out.words[k] = rword; + carry = ncarry; + } + if (carry !== 0) { + out.words[k] = carry; + } else { + out.length--; } -}; -Base58Check.prototype.set = function(obj) { - this.buf = obj.buf || this.buf || undefined; - return this; + return out.strip(); }; -Base58Check.validChecksum = function validChecksum(data, checksum) { - if (_.isString(data)) { - data = new buffer.Buffer(Base58.decode(data)); - } - if (_.isString(checksum)) { - checksum = new buffer.Buffer(Base58.decode(checksum)); - } - if (!checksum) { - checksum = data.slice(-4); - data = data.slice(0, -4); - } - return Base58Check.checksum(data).toString('hex') === checksum.toString('hex'); +// 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); }; -Base58Check.decode = function(s) { - if (typeof s !== 'string') - throw new Error('Input must be a string'); +// In-place Multiplication +BN.prototype.imul = function imul(num) { + if (this.cmpn(0) === 0 || num.cmpn(0) === 0) { + this.words[0] = 0; + this.length = 1; + return this; + } - var buf = new Buffer(Base58.decode(s)); + var tlen = this.length; + var nlen = num.length; - if (buf.length < 4) - throw new Error("Input string too short"); + this.sign = num.sign !== this.sign; + this.length = this.length + num.length; + this.words[this.length - 1] = 0; - var data = buf.slice(0, -4); - var csum = buf.slice(-4); + var lastCarry = 0; + for (var k = this.length - 2; k >= 0; k--) { + // Sum all words with the same `i + j = k` and accumulate `carry`, + // note that carry could be >= 0x3ffffff + var carry = 0; + var rword = 0; + var maxJ = Math.min(k, nlen - 1); + for (var j = Math.max(0, k - tlen + 1); j <= maxJ; j++) { + var i = k - j; + var a = this.words[i]; + var b = num.words[j]; + var r = a * b; - var hash = sha256sha256(data); - var hash4 = hash.slice(0, 4); + var lo = r & 0x3ffffff; + carry += (r / 0x4000000) | 0; + lo += rword; + rword = lo & 0x3ffffff; + carry += lo >>> 26; + } + this.words[k] = rword; + this.words[k + 1] += carry; + carry = 0; + } - if (csum.toString('hex') !== hash4.toString('hex')) - throw new Error("Checksum mismatch"); + // Propagate overflows + var carry = 0; + for (var i = 1; i < this.length; i++) { + var w = this.words[i] + carry; + this.words[i] = w & 0x3ffffff; + carry = w >>> 26; + } - return data; + return this.strip(); }; -Base58Check.checksum = function(buffer) { - return sha256sha256(buffer).slice(0, 4); +// `this` * `this` +BN.prototype.sqr = function sqr() { + return this.mul(this); }; -Base58Check.encode = function(buf) { - if (!Buffer.isBuffer(buf)) - throw new Error('Input must be a buffer'); - var checkedBuf = new Buffer(buf.length + 4); - var hash = Base58Check.checksum(buf); - buf.copy(checkedBuf); - hash.copy(checkedBuf, buf.length); - return Base58.encode(checkedBuf); +// `this` * `this` in-place +BN.prototype.isqr = function isqr() { + return this.mul(this); }; -Base58Check.prototype.fromBuffer = function(buf) { - this.buf = buf; - return this; -}; +// Shift-left in-place +BN.prototype.ishln = function ishln(bits) { + assert(typeof bits === 'number' && bits >= 0); + var r = bits % 26; + var s = (bits - r) / 26; + var carryMask = (0x3ffffff >>> (26 - r)) << (26 - r); -Base58Check.prototype.fromString = function(str) { - var buf = Base58Check.decode(str); - this.buf = buf; - return this; -}; + var o = this.clone(); + if (r !== 0) { + var carry = 0; + for (var i = 0; i < this.length; i++) { + var newCarry = this.words[i] & carryMask; + var c = (this.words[i] - newCarry) << r; + this.words[i] = c | carry; + carry = newCarry >>> (26 - r); + } + if (carry) { + this.words[i] = carry; + this.length++; + } + } -Base58Check.prototype.toBuffer = function() { - return this.buf; -}; + if (s !== 0) { + for (var i = this.length - 1; i >= 0; i--) + this.words[i + s] = this.words[i]; + for (var i = 0; i < s; i++) + this.words[i] = 0; + this.length += s; + } -Base58Check.prototype.toString = function() { - return Base58Check.encode(this.buf); + return this.strip(); }; -module.exports = Base58Check; +// Shift-right in-place +// NOTE: `hint` is a lowest bit before trailing zeroes +// NOTE: if `extended` is true - { lo: ..., hi: } object will be returned +BN.prototype.ishrn = function ishrn(bits, hint, extended) { + assert(typeof bits === 'number' && bits >= 0); + if (hint) + hint = (hint - (hint % 26)) / 26; + else + hint = 0; -}).call(this,require("buffer").Buffer) -},{"../crypto/hash":20,"./base58":24,"buffer":104,"lodash":79}],26:[function(require,module,exports){ -(function (Buffer){ -'use strict'; + var r = bits % 26; + var s = Math.min((bits - r) / 26, this.length); + var mask = 0x3ffffff ^ ((0x3ffffff >>> r) << r); + var maskedWords = extended; -var _ = require('lodash'); -var $ = require('../util/preconditions'); -var BufferUtil = require('../util/buffer'); -var BN = require('../crypto/bn'); + hint -= s; + hint = Math.max(0, hint); -var BufferReader = function BufferReader(buf) { - if (!(this instanceof BufferReader)) { - return new BufferReader(buf); + // Extended mode, copy masked part + if (maskedWords) { + for (var i = 0; i < s; i++) + maskedWords.words[i] = this.words[i]; + maskedWords.length = s; } - if (Buffer.isBuffer(buf)) { - this.set({ - buf: buf - }); - } else if (buf) { - var obj = buf; - this.set(obj); + + if (s === 0) { + // No-op, we should not move anything at all + } else if (this.length > s) { + this.length -= s; + for (var i = 0; i < this.length; i++) + this.words[i] = this.words[i + s]; + } else { + this.words[0] = 0; + this.length = 1; } -}; -BufferReader.prototype.set = function(obj) { - this.buf = obj.buf || this.buf || undefined; - this.pos = obj.pos || this.pos || 0; - return this; -}; + var carry = 0; + for (var i = this.length - 1; i >= 0 && (carry !== 0 || i >= hint); i--) { + var word = this.words[i]; + this.words[i] = (carry << (26 - r)) | (word >>> r); + carry = word & mask; + } -BufferReader.prototype.eof = function() { - return this.pos >= this.buf.length; -}; + // Push carried bits as a mask + if (maskedWords && carry !== 0) + maskedWords.words[maskedWords.length++] = carry; -BufferReader.prototype.finished = BufferReader.prototype.eof; + if (this.length === 0) { + this.words[0] = 0; + this.length = 1; + } -BufferReader.prototype.read = function(len) { - $.checkArgument(!_.isUndefined(len), 'Must specify a length'); - var buf = this.buf.slice(this.pos, this.pos + len); - this.pos = this.pos + len; - return buf; -}; + this.strip(); + if (extended) + return { hi: this, lo: maskedWords }; -BufferReader.prototype.readAll = function() { - var buf = this.buf.slice(this.pos, this.buf.length); - this.pos = this.buf.length; - return buf; + return this; }; -BufferReader.prototype.readUInt8 = function() { - var val = this.buf.readUInt8(this.pos); - this.pos = this.pos + 1; - return val; +// Shift-left +BN.prototype.shln = function shln(bits) { + return this.clone().ishln(bits); }; -BufferReader.prototype.readUInt16BE = function() { - var val = this.buf.readUInt16BE(this.pos); - this.pos = this.pos + 2; - return val; +// Shift-right +BN.prototype.shrn = function shrn(bits) { + return this.clone().ishrn(bits); }; -BufferReader.prototype.readUInt16LE = function() { - var val = this.buf.readUInt16LE(this.pos); - this.pos = this.pos + 2; - return val; -}; +// 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; -BufferReader.prototype.readUInt32BE = function() { - var val = this.buf.readUInt32BE(this.pos); - this.pos = this.pos + 4; - return val; -}; + // Fast case: bit is much higher than all existing words + if (this.length <= s) { + return false; + } -BufferReader.prototype.readUInt32LE = function() { - var val = this.buf.readUInt32LE(this.pos); - this.pos = this.pos + 4; - return val; -}; + // Check bit and return + var w = this.words[s]; -BufferReader.prototype.readUInt64BEBN = function() { - var buf = this.buf.slice(this.pos, this.pos + 8); - var bn = BN.fromBuffer(buf); - this.pos = this.pos + 8; - return bn; + return !!(w & q); }; -BufferReader.prototype.readUInt64LEBN = function() { - var buf = this.buf.slice(this.pos, this.pos + 8); - var reversebuf = BufferReader({ - buf: buf - }).readReverse(); - var bn = BN.fromBuffer(reversebuf); - this.pos = this.pos + 8; - return bn; -}; +// 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; -BufferReader.prototype.readVarintNum = function() { - var first = this.readUInt8(); - switch (first) { - case 0xFD: - return this.readUInt16LE(); - case 0xFE: - return this.readUInt32LE(); - case 0xFF: - var bn = this.readUInt64LEBN(); - var n = bn.toNumber(); - if (n <= Math.pow(2, 53)) { - return n; - } else { - throw new Error('number too large to retain precision - use readVarintBN'); - } - break; - default: - return first; - } -}; + assert(!this.sign, 'imaskn works only with positive numbers'); -/** - * reads a length prepended buffer - */ -BufferReader.prototype.readVarLengthBuffer = function() { - var len = this.readVarintNum(); - var buf = this.read(len); - $.checkState(buf.length === len, 'Invalid length while reading varlength buffer. ' + - 'Expected to read: ' + len + ' and read ' + buf.length); - return buf; -}; + if (r !== 0) + s++; + this.length = Math.min(s, this.length); -BufferReader.prototype.readVarintBuf = function() { - var first = this.buf.readUInt8(this.pos); - switch (first) { - case 0xFD: - return this.read(1 + 2); - case 0xFE: - return this.read(1 + 4); - case 0xFF: - return this.read(1 + 8); - default: - return this.read(1); + if (r !== 0) { + var mask = 0x3ffffff ^ ((0x3ffffff >>> r) << r); + this.words[this.length - 1] &= mask; } + + return this.strip(); }; -BufferReader.prototype.readVarintBN = function() { - var first = this.readUInt8(); - switch (first) { - case 0xFD: - return new BN(this.readUInt16LE()); - case 0xFE: - return new BN(this.readUInt32LE()); - case 0xFF: - return this.readUInt64LEBN(); - default: - return new BN(first); - } +// Return only lowers bits of number +BN.prototype.maskn = function maskn(bits) { + return this.clone().imaskn(bits); }; -BufferReader.prototype.reverse = function() { - var buf = new Buffer(this.buf.length); - for (var i = 0; i < buf.length; i++) { - buf[i] = this.buf[this.buf.length - 1 - i]; +// Add plain number `num` to `this` +BN.prototype.iaddn = function iaddn(num) { + assert(typeof num === 'number'); + if (num < 0) + return this.isubn(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.buf = buf; + this.length = Math.max(this.length, i + 1); + return this; }; -BufferReader.prototype.readReverse = function(len) { - if (_.isUndefined(len)) { - len = this.buf.length; +// Subtract plain number `num` from `this` +BN.prototype.isubn = function isubn(num) { + assert(typeof num === 'number'); + assert(this.cmpn(num) >= 0, 'Sign change is not supported in isubn'); + if (num < 0) + return this.iaddn(-num); + this.words[0] -= num; + + // Carry + for (var i = 0; i < this.length && this.words[i] < 0; i++) { + this.words[i] += 0x4000000; + this.words[i + 1] -= 1; } - var buf = this.buf.slice(this.pos, this.pos + len); - this.pos = this.pos + len; - return BufferUtil.reverse(buf); + + return this.strip(); }; -module.exports = BufferReader; +BN.prototype.addn = function addn(num) { + return this.clone().iaddn(num); +}; -}).call(this,require("buffer").Buffer) -},{"../crypto/bn":18,"../util/buffer":53,"../util/preconditions":55,"buffer":104,"lodash":79}],27:[function(require,module,exports){ -(function (Buffer){ -'use strict'; +BN.prototype.subn = function subn(num) { + return this.clone().isubn(num); +}; -var bufferUtil = require('../util/buffer'); -var assert = require('assert'); +BN.prototype.iabs = function iabs() { + this.sign = false; -var BufferWriter = function BufferWriter(obj) { - if (!(this instanceof BufferWriter)) - return new BufferWriter(obj); - if (obj) - this.set(obj); - else - this.bufs = []; + return this }; -BufferWriter.prototype.set = function(obj) { - this.bufs = obj.bufs || this.bufs || []; - return this; +BN.prototype.abs = function abs() { + return this.clone().iabs(); }; -BufferWriter.prototype.toBuffer = function() { - return this.concat(); -}; +BN.prototype._wordDiv = function _wordDiv(num, mode) { + var shift = this.length - num.length; -BufferWriter.prototype.concat = function() { - return Buffer.concat(this.bufs); -}; + var a = this.clone(); + var b = num; -BufferWriter.prototype.write = function(buf) { - assert(bufferUtil.isBuffer(buf)); - this.bufs.push(buf); - return this; -}; + var q = mode !== 'mod' && new BN(0); + var sign = false; -BufferWriter.prototype.writeReverse = function(buf) { - assert(bufferUtil.isBuffer(buf)); - this.bufs.push(bufferUtil.reverse(buf)); - return this; -}; + // Approximate quotient at each step + while (a.length > b.length) { + // NOTE: a.length is always >= 2, because of the condition .div() + var hi = a.words[a.length - 1] * 0x4000000 + a.words[a.length - 2]; + var sq = (hi / b.words[b.length - 1]); + var sqhi = (sq / 0x4000000) | 0; + var sqlo = sq & 0x3ffffff; + sq = new BN(null); + sq.words = [ sqlo, sqhi ]; + sq.length = 2; -BufferWriter.prototype.writeUInt8 = function(n) { - var buf = new Buffer(1); - buf.writeUInt8(n, 0); - this.write(buf); - return this; -}; + // Collect quotient + var shift = (a.length - b.length - 1) * 26; + if (q) { + var t = sq.shln(shift); + if (a.sign) + q.isub(t); + else + q.iadd(t); + } -BufferWriter.prototype.writeUInt16BE = function(n) { - var buf = new Buffer(2); - buf.writeUInt16BE(n, 0); - this.write(buf); - return this; -}; + sq = sq.mul(b).ishln(shift); + if (a.sign) + a.iadd(sq) + else + a.isub(sq); + } + // At this point a.length <= b.length + while (a.ucmp(b) >= 0) { + // NOTE: a.length is always >= 2, because of the condition above + var hi = a.words[a.length - 1]; + var sq = new BN((hi / b.words[b.length - 1]) | 0); + var shift = (a.length - b.length) * 26; -BufferWriter.prototype.writeUInt16LE = function(n) { - var buf = new Buffer(2); - buf.writeUInt16LE(n, 0); - this.write(buf); - return this; -}; + if (q) { + var t = sq.shln(shift); + if (a.sign) + q.isub(t); + else + q.iadd(t); + } -BufferWriter.prototype.writeUInt32BE = function(n) { - var buf = new Buffer(4); - buf.writeUInt32BE(n, 0); - this.write(buf); - return this; -}; + sq = sq.mul(b).ishln(shift); -BufferWriter.prototype.writeInt32LE = function(n) { - var buf = new Buffer(4); - buf.writeInt32LE(n, 0); - this.write(buf); - return this; -}; + if (a.sign) + a.iadd(sq); + else + a.isub(sq); + } -BufferWriter.prototype.writeUInt32LE = function(n) { - var buf = new Buffer(4); - buf.writeUInt32LE(n, 0); - this.write(buf); - return this; + if (a.sign) { + if (q) + q.isubn(1); + a.iadd(b); + } + return { div: q ? q : null, mod: a }; }; -BufferWriter.prototype.writeUInt64BEBN = function(bn) { - var buf = bn.toBuffer({size: 8}); - this.write(buf); - return this; -}; +BN.prototype.divmod = function divmod(num, mode) { + assert(num.cmpn(0) !== 0); -BufferWriter.prototype.writeUInt64LEBN = function(bn) { - var buf = bn.toBuffer({size: 8}); - var reversebuf = new Buffer(Array.apply(new Array(), buf).reverse()); - this.write(reversebuf); - return this; -}; + if (this.sign && !num.sign) { + var res = this.neg().divmod(num, mode); + var div; + var mod; + if (mode !== 'mod') + div = res.div.neg(); + if (mode !== 'div') + mod = res.mod.cmpn(0) === 0 ? res.mod : num.sub(res.mod); + return { + div: div, + mod: mod + }; + } else if (!this.sign && num.sign) { + var res = this.divmod(num.neg(), mode); + var div; + if (mode !== 'mod') + div = res.div.neg(); + return { div: div, mod: res.mod }; + } else if (this.sign && num.sign) { + return this.neg().divmod(num.neg(), mode); + } -BufferWriter.prototype.writeVarintNum = function(n) { - var buf = BufferWriter.varintBufNum(n); - this.write(buf); - return this; -}; + // Both numbers are positive at this point -BufferWriter.prototype.writeVarintBN = function(bn) { - var buf = BufferWriter.varintBufBN(bn); - this.write(buf); - return this; -}; + // Strip both numbers to approximate shift value + if (num.length > this.length || this.cmp(num) < 0) + return { div: new BN(0), mod: this }; -BufferWriter.varintBufNum = function(n) { - var buf = undefined; - if (n < 253) { - buf = new Buffer(1); - buf.writeUInt8(n, 0); - } else if (n < 0x10000) { - buf = new Buffer(1 + 2); - buf.writeUInt8(253, 0); - buf.writeUInt16LE(n, 1); - } else if (n < 0x100000000) { - buf = new Buffer(1 + 4); - buf.writeUInt8(254, 0); - buf.writeUInt32LE(n, 1); - } else { - buf = new Buffer(1 + 8); - buf.writeUInt8(255, 0); - buf.writeInt32LE(n & -1, 1); - buf.writeUInt32LE(Math.floor(n / 0x100000000), 5); + // Very short reduction + if (num.length === 1) { + if (mode === 'div') + return { div: this.divn(num.words[0]), mod: null }; + else 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 buf; + + return this._wordDiv(num, mode); }; -BufferWriter.varintBufBN = function(bn) { - var buf = undefined; - var n = bn.toNumber(); - if (n < 253) { - buf = new Buffer(1); - buf.writeUInt8(n, 0); - } else if (n < 0x10000) { - buf = new Buffer(1 + 2); - buf.writeUInt8(253, 0); - buf.writeUInt16LE(n, 1); - } else if (n < 0x100000000) { - buf = new Buffer(1 + 4); - buf.writeUInt8(254, 0); - buf.writeUInt32LE(n, 1); - } else { - var bw = new BufferWriter(); - bw.writeUInt8(255); - bw.writeUInt64LEBN(bn); - var buf = bw.concat(); - } - return buf; +// Find `this` / `num` +BN.prototype.div = function div(num) { + return this.divmod(num, 'div').div; }; -module.exports = BufferWriter; +// Find `this` % `num` +BN.prototype.mod = function mod(num) { + return this.divmod(num, 'mod').mod; +}; -}).call(this,require("buffer").Buffer) -},{"../util/buffer":53,"assert":89,"buffer":104}],28:[function(require,module,exports){ -(function (Buffer){ -'use strict'; +// Find Round(`this` / `num`) +BN.prototype.divRound = function divRound(num) { + var dm = this.divmod(num); -var BufferWriter = require('./bufferwriter'); -var BufferReader = require('./bufferreader'); -var BN = require('../crypto/bn'); + // Fast case - exact division + if (dm.mod.cmpn(0) === 0) + return dm.div; -var Varint = function Varint(buf) { - if (!(this instanceof Varint)) - return new Varint(buf); - if (Buffer.isBuffer(buf)) { - this.buf = buf; - } else if (typeof buf === 'number') { - var num = buf; - this.fromNumber(num); - } else if (buf instanceof BN) { - var bn = buf; - this.fromBN(bn); - } else if (buf) { - var obj = buf; - this.set(obj); - } -}; + var mod = dm.div.sign ? dm.mod.isub(num) : dm.mod; -Varint.prototype.set = function(obj) { - this.buf = obj.buf || this.buf; - return this; -}; + var half = num.shrn(1); + var r2 = num.andln(1); + var cmp = mod.cmp(half); -Varint.prototype.fromString = function(str) { - this.set({ - buf: new Buffer(str, 'hex') - }); - return this; -}; + // Round down + if (cmp < 0 || r2 === 1 && cmp === 0) + return dm.div; -Varint.prototype.toString = function() { - return this.buf.toString('hex'); + // Round up + return dm.div.sign ? dm.div.isubn(1) : dm.div.iaddn(1); }; -Varint.prototype.fromBuffer = function(buf) { - this.buf = buf; - return this; -}; +BN.prototype.modn = function modn(num) { + assert(num <= 0x3ffffff); + var p = (1 << 26) % num; -Varint.prototype.fromBufferReader = function(br) { - this.buf = br.readVarintBuf(); - return this; -}; + var acc = 0; + for (var i = this.length - 1; i >= 0; i--) + acc = (p * acc + this.words[i]) % num; -Varint.prototype.fromBN = function(bn) { - this.buf = BufferWriter().writeVarintBN(bn).concat(); - return this; + return acc; }; -Varint.prototype.fromNumber = function(num) { - this.buf = BufferWriter().writeVarintNum(num).concat(); - return this; -}; +// In-place division by number +BN.prototype.idivn = function idivn(num) { + assert(num <= 0x3ffffff); -Varint.prototype.toBuffer = function() { - return this.buf; -}; + var carry = 0; + for (var i = this.length - 1; i >= 0; i--) { + var w = this.words[i] + carry * 0x4000000; + this.words[i] = (w / num) | 0; + carry = w % num; + } -Varint.prototype.toBN = function() { - return BufferReader(this.buf).readVarintBN(); + return this.strip(); }; -Varint.prototype.toNumber = function() { - return BufferReader(this.buf).readVarintNum(); +BN.prototype.divn = function divn(num) { + return this.clone().idivn(num); }; -module.exports = Varint; +BN.prototype._egcd = function _egcd(x1, p) { + assert(!p.sign); + assert(p.cmpn(0) !== 0); -}).call(this,require("buffer").Buffer) -},{"../crypto/bn":18,"./bufferreader":26,"./bufferwriter":27,"buffer":104}],29:[function(require,module,exports){ -'use strict'; + var a = this; + var b = p.clone(); -var _ = require('lodash'); + if (a.sign) + a = a.mod(p); + else + a = a.clone(); -function format(message, args) { - return message - .replace('{0}', args[0]) - .replace('{1}', args[1]) - .replace('{2}', args[2]); -} -var traverseNode = function(parent, errorDefinition) { - var NodeError = function() { - if (_.isString(errorDefinition.message)) { - this.message = format(errorDefinition.message, arguments); - } else if (_.isFunction(errorDefinition.message)) { - this.message = errorDefinition.message.apply(null, arguments); + var x2 = new BN(0); + while (a.cmpn(1) > 0 && b.cmpn(1) > 0) { + while (a.isEven()) { + a.ishrn(1); + if (x1.isEven()) + x1.ishrn(1); + else + x1.iadd(p).ishrn(1); + } + while (b.isEven()) { + b.ishrn(1); + if (x2.isEven()) + x2.ishrn(1); + else + x2.iadd(p).ishrn(1); + } + if (a.cmp(b) >= 0) { + a.isub(b); + x1.isub(x2); } else { - throw new Error('Invalid error definition for ' + errorDefinition.name); + b.isub(a); + x2.isub(x1); } - this.stack = this.message + '\n' + (new Error()).stack; - }; - NodeError.prototype = Object.create(parent.prototype); - NodeError.prototype.name = parent.prototype.name + errorDefinition.name; - parent[errorDefinition.name] = NodeError; - if (errorDefinition.errors) { - childDefinitions(NodeError, errorDefinition.errors); } - return NodeError; + if (a.cmpn(1) === 0) + return x1; + else + return x2; }; -/* jshint latedef: false */ -var childDefinitions = function(parent, childDefinitions) { - _.each(childDefinitions, function(childDefinition) { - traverseNode(parent, childDefinition); - }); +BN.prototype.gcd = function gcd(num) { + if (this.cmpn(0) === 0) + return num.clone(); + if (num.cmpn(0) === 0) + return this.clone(); + + var a = this.clone(); + var b = num.clone(); + a.sign = false; + b.sign = false; + + // Remove common factor of two + for (var shift = 0; a.isEven() && b.isEven(); shift++) { + a.ishrn(1); + b.ishrn(1); + } + + while (a.isEven()) + a.ishrn(1); + + do { + while (b.isEven()) + b.ishrn(1); + + // Swap `a` and `b` to make `a` always bigger than `b` + if (a.cmp(b) < 0) { + var t = a; + a = b; + b = t; + } + a.isub(a.div(b).mul(b)); + } while (a.cmpn(0) !== 0 && b.cmpn(0) !== 0); + if (a.cmpn(0) === 0) + return b.ishln(shift); + else + return a.ishln(shift); }; -/* jshint latedef: true */ -var traverseRoot = function(parent, errorsDefinition) { - childDefinitions(parent, errorsDefinition); - return parent; +// Invert number in the field F(num) +BN.prototype.invm = function invm(num) { + return this._egcd(new BN(1), num).mod(num); }; +BN.prototype.isEven = function isEven(num) { + return (this.words[0] & 1) === 0; +}; -var bitcore = {}; -bitcore.Error = function() { - this.message = 'Internal error'; - this.stack = this.message + '\n' + (new Error()).stack; +BN.prototype.isOdd = function isOdd(num) { + return (this.words[0] & 1) === 1; }; -bitcore.Error.prototype = Object.create(Error.prototype); -bitcore.Error.prototype.name = 'bitcore.Error'; +// And first word and num +BN.prototype.andln = function andln(num) { + return this.words[0] & num; +}; -var data = require('./spec'); -traverseRoot(bitcore.Error, data); +// 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; -module.exports = bitcore.Error; + // Fast case: bit is much higher than all existing words + if (this.length <= s) { + for (var i = this.length; i < s + 1; i++) + this.words[i] = 0; + this.words[s] |= q; + this.length = s + 1; + return this; + } -module.exports.extend = function(spec) { - return traverseNode(bitcore.Error, spec); + // Add bit and propagate, if needed + var carry = q; + for (var i = s; carry !== 0 && i < this.length; i++) { + var w = this.words[i]; + w += carry; + carry = w >>> 26; + w &= 0x3ffffff; + this.words[i] = w; + } + if (carry !== 0) { + this.words[i] = carry; + this.length++; + } + return this; }; -},{"./spec":30,"lodash":79}],30:[function(require,module,exports){ -'use strict'; +BN.prototype.cmpn = function cmpn(num) { + var sign = num < 0; + if (sign) + num = -num; -var docsURL = 'http://bitcore.io/'; + if (this.sign && !sign) + return -1; + else if (!this.sign && sign) + return 1; -module.exports = [{ - name: 'InvalidB58Char', - message: 'Invalid Base58 character: {0} in {1}' -}, { - name: 'InvalidB58Checksum', - message: 'Invalid Base58 checksum for {0}' -}, { - name: 'InvalidNetwork', - message: 'Invalid version for network: got {0}' -}, { - name: 'InvalidState', - message: 'Invalid state: {0}' -}, { - name: 'NotImplemented', - message: 'Function {0} was not implemented yet' -}, { - name: 'InvalidNetworkArgument', - message: 'Invalid network: must be "livenet" or "testnet", got {0}' -}, { - name: 'InvalidArgument', - message: function() { - return 'Invalid Argument' + (arguments[0] ? (': ' + arguments[0]) : '') + - (arguments[1] ? (' Documentation: ' + docsURL + arguments[1]) : ''); + num &= 0x3ffffff; + this.strip(); + + var res; + if (this.length > 1) { + res = 1; + } else { + var w = this.words[0]; + res = w === num ? 0 : w < num ? -1 : 1; } -}, { - name: 'AbstractMethodInvoked', - message: 'Abstract Method Invokation: {0}' -}, { - name: 'InvalidArgumentType', - message: function() { - return 'Invalid Argument for ' + arguments[2] + ', expected ' + arguments[1] + ' but got ' + typeof arguments[0]; - } -}, { - name: 'Unit', - message: 'Internal Error on Unit {0}', - errors: [{ - 'name': 'UnknownCode', - 'message': 'Unrecognized unit code: {0}' - }, { - 'name': 'InvalidRate', - 'message': 'Invalid exchange rate: {0}' - }] -}, { - name: 'Transaction', - message: 'Internal Error on Transaction {0}', - errors: [{ - name: 'Input', - message: 'Internal Error on Input {0}', - errors: [{ - name: 'MissingScript', - message: 'Need a script to create an input' - }, { - name: 'UnsupportedScript', - message: 'Unsupported input script type: {0}' - }, { - name: 'MissingPreviousOutput', - message: 'No previous output information.' - }] - }, { - name: 'NeedMoreInfo', - message: '{0}' - }, { - name: 'InvalidSorting', - message: 'The sorting function provided did not return the change output as one of the array elements' - }, { - name: 'InvalidOutputAmountSum', - message: '{0}' - }, { - name: 'MissingSignatures', - message: 'Some inputs have not been fully signed' - }, { - name: 'InvalidIndex', - message: 'Invalid index: {0} is not between 0, {1}' - }, { - name: 'UnableToVerifySignature', - message: 'Unable to verify signature: {0}' - }, { - name: 'DustOutputs', - message: 'Dust amount detected in one output' - }, { - name: 'FeeError', - message: 'Fees are not correctly set {0}', - }, { - name: 'ChangeAddressMissing', - message: 'Change address is missing' - }, { - name: 'BlockHeightTooHigh', - message: 'Block Height can be at most 2^32 -1' - }, { - name: 'NLockTimeOutOfRange', - message: 'Block Height can only be between 0 and 499 999 999' - }, { - name: 'LockTimeTooEarly', - message: 'Lock Time can\'t be earlier than UNIX date 500 000 000' - }] -}, { - name: 'Script', - message: 'Internal Error on Script {0}', - errors: [{ - name: 'UnrecognizedAddress', - message: 'Expected argument {0} to be an address' - }] -}, { - name: 'HDPrivateKey', - message: 'Internal Error on HDPrivateKey {0}', - errors: [{ - name: 'InvalidDerivationArgument', - message: 'Invalid derivation argument {0}, expected string, or number and boolean' - }, { - name: 'InvalidEntropyArgument', - message: 'Invalid entropy: must be an hexa string or binary buffer, got {0}', - errors: [{ - name: 'TooMuchEntropy', - message: 'Invalid entropy: more than 512 bits is non standard, got "{0}"' - }, { - name: 'NotEnoughEntropy', - message: 'Invalid entropy: at least 128 bits needed, got "{0}"' - }] - }, { - name: 'InvalidLength', - message: 'Invalid length for xprivkey string in {0}' - }, { - name: 'InvalidPath', - message: 'Invalid derivation path: {0}' - }, { - name: 'UnrecognizedArgument', - message: 'Invalid argument: creating a HDPrivateKey requires a string, buffer, json or object, got "{0}"' - }] -}, { - name: 'HDPublicKey', - message: 'Internal Error on HDPublicKey {0}', - errors: [{ - name: 'ArgumentIsPrivateExtended', - message: 'Argument is an extended private key: {0}' - }, { - name: 'InvalidDerivationArgument', - message: 'Invalid derivation argument: got {0}' - }, { - name: 'InvalidLength', - message: 'Invalid length for xpubkey: got "{0}"' - }, { - name: 'InvalidPath', - message: 'Invalid derivation path, it should look like: "m/1/100", got "{0}"' - }, { - name: 'MustSupplyArgument', - message: 'Must supply an argument to create a HDPublicKey' - }, { - name: 'UnrecognizedArgument', - message: 'Invalid argument for creation, must be string, json, buffer, or object' - }] -}]; + if (this.sign) + res = -res; + return res; +}; -},{}],31:[function(require,module,exports){ -'use strict'; +// 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.sign && !num.sign) + return -1; + else if (!this.sign && num.sign) + return 1; -module.exports = { - _cache: {}, - _count: 0, - _eraseIndex: 0, - _usedList: {}, - _usedIndex: {}, - _CACHE_SIZE: 5000, + var res = this.ucmp(num); + if (this.sign) + return -res; + else + return res; +}; - get: function(xkey, number, hardened) { - hardened = !!hardened; - var key = xkey + '/' + number + '/' + hardened; - if (this._cache[key]) { - this._cacheHit(key); - return this._cache[key]; - } - }, - set: function(xkey, number, hardened, derived) { - hardened = !!hardened; - var key = xkey + '/' + number + '/' + hardened; - this._cache[key] = derived; - this._cacheHit(key); - }, - _cacheHit: function(key) { - if (this._usedIndex[key]) { - delete this._usedList[this._usedIndex[key]]; - } - this._usedList[this._count] = key; - this._usedIndex[key] = this._count; - this._count++; - this._cacheRemove(); - }, - _cacheRemove: function() { - while (this._eraseIndex < this._count - this._CACHE_SIZE) { - if (this._usedList[this._eraseIndex]) { - var removeKey = this._usedList[this._eraseIndex]; - delete this._usedIndex[removeKey]; - delete this._cache[removeKey]; - } - delete this._usedList[this._eraseIndex]; - this._eraseIndex++; - } +// Unsigned comparison +BN.prototype.ucmp = function ucmp(num) { + // At this point both numbers have the same sign + if (this.length > num.length) + return 1; + else if (this.length < num.length) + return -1; + + var res = 0; + for (var i = this.length - 1; i >= 0; i--) { + var a = this.words[i]; + var b = num.words[i]; + + if (a === b) + continue; + if (a < b) + res = -1; + else if (a > b) + res = 1; + break; } + return res; }; -},{}],32:[function(require,module,exports){ -(function (Buffer){ -'use strict'; +// +// 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.sign, 'red works only with positives'); + return ctx.convertTo(this)._forceRed(ctx); +}; -var assert = require('assert'); -var buffer = require('buffer'); -var _ = require('lodash'); -var $ = require('./util/preconditions'); +BN.prototype.fromRed = function fromRed() { + assert(this.red, 'fromRed works only with numbers in reduction context'); + return this.red.convertFrom(this); +}; -var BN = require('./crypto/bn'); -var Base58 = require('./encoding/base58'); -var Base58Check = require('./encoding/base58check'); -var Hash = require('./crypto/hash'); -var Network = require('./networks'); -var HDKeyCache = require('./hdkeycache'); -var Point = require('./crypto/point'); -var PrivateKey = require('./privatekey'); -var Random = require('./crypto/random'); +BN.prototype._forceRed = function _forceRed(ctx) { + this.red = ctx; + return this; +}; -var errors = require('./errors'); -var hdErrors = errors.HDPrivateKey; -var BufferUtil = require('./util/buffer'); -var JSUtil = require('./util/js'); +BN.prototype.forceRed = function forceRed(ctx) { + assert(!this.red, 'Already a number in reduction context'); + return this._forceRed(ctx); +}; -var MINIMUM_ENTROPY_BITS = 128; -var BITS_TO_BYTES = 1 / 8; -var MAXIMUM_ENTROPY_BITS = 512; +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); +}; -/** - * Represents an instance of an hierarchically derived private key. - * - * More info on https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki - * - * @constructor - * @param {string|Buffer|Object} arg - */ -function HDPrivateKey(arg) { - /* jshint maxcomplexity: 10 */ - if (arg instanceof HDPrivateKey) { - return arg; - } - if (!(this instanceof HDPrivateKey)) { - return new HDPrivateKey(arg); - } - if (!arg) { - return this._generateRandomly(); - } +BN.prototype.redSub = function redSub(num) { + assert(this.red, 'redSub works only with red numbers'); + return this.red.sub(this, num); +}; - if (Network.get(arg)) { - return this._generateRandomly(arg); - } else if (_.isString(arg) || BufferUtil.isBuffer(arg)) { - if (HDPrivateKey.isValidSerialized(arg)) { - this._buildFromSerialized(arg); - } else if (JSUtil.isValidJSON(arg)) { - this._buildFromJSON(arg); - } else if (BufferUtil.isBuffer(arg) && HDPrivateKey.isValidSerialized(arg.toString())) { - this._buildFromSerialized(arg.toString()); - } else { - throw HDPrivateKey.getSerializedError(arg); - } - } else if (_.isObject(arg)) { - this._buildFromObject(arg); - } else { - throw new hdErrors.UnrecognizedArgument(arg); - } -} +BN.prototype.redISub = function redISub(num) { + assert(this.red, 'redISub works only with red numbers'); + return this.red.isub(this, num); +}; -/** - * Verifies that a given path is valid. - * - * @param {string|number} arg - * @param {boolean?} hardened - * @return {boolean} - */ -HDPrivateKey.isValidPath = function(arg, hardened) { - if (_.isString(arg)) { - var indexes = HDPrivateKey._getDerivationIndexes(arg); - return indexes !== null && _.all(indexes, HDPrivateKey.isValidPath); - } +BN.prototype.redShl = function redShl(num) { + assert(this.red, 'redShl works only with red numbers'); + return this.red.shl(this, num); +}; - if (_.isNumber(arg)) { - if (arg < HDPrivateKey.Hardened && hardened === true) { - arg += HDPrivateKey.Hardened; - } - return arg >= 0 && arg < HDPrivateKey.MaxIndex; - } +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); +}; - return false; +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); }; -/** - * Internal function that splits a string path into a derivation index array. - * It will return null if the string path is malformed. - * It does not validate if indexes are in bounds. - * - * @param {string} path - * @return {Array} - */ -HDPrivateKey._getDerivationIndexes = function(path) { - var steps = path.split('/'); +BN.prototype.redSqr = function redSqr() { + assert(this.red, 'redSqr works only with red numbers'); + this.red._verify1(this); + return this.red.sqr(this); +}; - // Special cases: - if (_.contains(HDPrivateKey.RootElementAlias, path)) { - return []; - } +BN.prototype.redISqr = function redISqr() { + assert(this.red, 'redISqr works only with red numbers'); + this.red._verify1(this); + return this.red.isqr(this); +}; - if (!_.contains(HDPrivateKey.RootElementAlias, steps[0])) { - return null; - } +// 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); +}; - var indexes = steps.slice(1).map(function(step) { - var isHardened = step.slice(-1) === '\''; - if (isHardened) { - step = step.slice(0, -1); - } - if (!step || step[0] === '-') { - return NaN; - } - var index = +step; // cast to number - if (isHardened) { - index += HDPrivateKey.Hardened; - } +BN.prototype.redInvm = function redInvm() { + assert(this.red, 'redInvm works only with red numbers'); + this.red._verify1(this); + return this.red.invm(this); +}; - return index; - }); +// 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); +}; - return _.any(indexes, isNaN) ? null : indexes; +BN.prototype.redPow = function redPow(num) { + assert(this.red && !num.red, 'redPow(normalNum)'); + this.red._verify1(this); + return this.red.pow(this, num); }; -/** - * Get a derivated child based on a string or number. - * - * If the first argument is a string, it's parsed as the full path of - * derivation. Valid values for this argument include "m" (which returns the - * same private key), "m/0/1/40/2'/1000", where the ' quote means a hardened - * derivation. - * - * If the first argument is a number, the child with that index will be - * derived. If the second argument is truthy, the hardened version will be - * derived. See the example usage for clarification. - * - * @example - * ```javascript - * var parent = new HDPrivateKey('xprv...'); - * var child_0_1_2h = parent.derive(0).derive(1).derive(2, true); - * var copy_of_child_0_1_2h = parent.derive("m/0/1/2'"); - * assert(child_0_1_2h.xprivkey === copy_of_child_0_1_2h); - * ``` - * - * @param {string|number} arg - * @param {boolean?} hardened - */ -HDPrivateKey.prototype.derive = function(arg, hardened) { - if (_.isNumber(arg)) { - return this._deriveWithNumber(arg, hardened); - } else if (_.isString(arg)) { - return this._deriveFromString(arg); - } else { - throw new hdErrors.InvalidDerivationArgument(arg); - } +// Prime numbers with efficient reduction +var primes = { + k256: null, + p224: null, + p192: null, + p25519: null }; -HDPrivateKey.prototype._deriveWithNumber = function(index, hardened) { - /* jshint maxstatements: 20 */ - /* jshint maxcomplexity: 10 */ - if (!HDPrivateKey.isValidPath(index, hardened)) { - throw new hdErrors.InvalidPath(index); - } +// 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).ishln(this.n).isub(this.p); - hardened = index >= HDPrivateKey.Hardened ? true : hardened; - if (index < HDPrivateKey.Hardened && hardened === true) { - index += HDPrivateKey.Hardened; - } + this.tmp = this._tmp(); +} - var cached = HDKeyCache.get(this.xprivkey, index, hardened); - if (cached) { - return cached; - } +MPrime.prototype._tmp = function _tmp() { + var tmp = new BN(null); + tmp.words = new Array(Math.ceil(this.n / 13)); + return tmp; +}; - var indexBuffer = BufferUtil.integerAsBuffer(index); - var data; - if (hardened) { - data = BufferUtil.concat([new buffer.Buffer([0]), this.privateKey.toBuffer(), indexBuffer]); +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 { + var pair = r.ishrn(this.n, 0, this.tmp); + r = this.imulK(pair.hi); + r = r.iadd(pair.lo); + rlen = r.bitLength(); + } while (rlen > this.n); + + var cmp = rlen < this.n ? -1 : r.cmp(this.p); + if (cmp === 0) { + r.words[0] = 0; + r.length = 1; + } else if (cmp > 0) { + r.isub(this.p); } else { - data = BufferUtil.concat([this.publicKey.toBuffer(), indexBuffer]); + r.strip(); } - var hash = Hash.sha512hmac(data, this._buffers.chainCode); - var leftPart = BN.fromBuffer(hash.slice(0, 32), { - size: 32 - }); - var chainCode = hash.slice(32, 64); - var privateKey = leftPart.add(this.privateKey.toBigNumber()).mod(Point.getN()).toBuffer({ - size: 32 - }); + return r; +}; - var derived = new HDPrivateKey({ - network: this.network, - depth: this.depth + 1, - parentFingerPrint: this.fingerPrint, - childIndex: index, - chainCode: chainCode, - privateKey: privateKey - }); - HDKeyCache.set(this.xprivkey, index, hardened, derived); - return derived; +MPrime.prototype.imulK = function imulK(num) { + return num.imul(this.k); }; -HDPrivateKey.prototype._deriveFromString = function(path) { - if (!HDPrivateKey.isValidPath(path)) { - throw new hdErrors.InvalidPath(path); - } +function K256() { + MPrime.call( + this, + 'k256', + 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f'); +} +inherits(K256, MPrime); - var indexes = HDPrivateKey._getDerivationIndexes(path); - var derived = indexes.reduce(function(prev, index) { - return prev._deriveWithNumber(index); - }, this); +K256.prototype.imulK = function imulK(num) { + // K = 0x1000003d1 = [ 0x40, 0x3d1 ] + num.words[num.length] = 0; + num.words[num.length + 1] = 0; + num.length += 2; + for (var i = num.length - 3; i >= 0; i--) { + var w = num.words[i]; + var hi = w * 0x40; + var lo = w * 0x3d1; + hi += (lo / 0x4000000) | 0; + var uhi = (hi / 0x4000000) | 0; + hi &= 0x3ffffff; + lo &= 0x3ffffff; - return derived; + num.words[i + 2] += uhi; + num.words[i + 1] += hi; + num.words[i] = lo; + } + var w = num.words[num.length - 2]; + if (w >= 0x4000000) { + num.words[num.length - 1] += w >>> 26; + num.words[num.length - 2] = w & 0x3ffffff; + } + if (num.words[num.length - 1] === 0) + num.length--; + if (num.words[num.length - 1] === 0) + num.length--; + return num; }; -/** - * Verifies that a given serialized private key in base58 with checksum format - * is valid. - * - * @param {string|Buffer} data - the serialized private key - * @param {string|Network=} network - optional, if present, checks that the - * network provided matches the network serialized. - * @return {boolean} - */ -HDPrivateKey.isValidSerialized = function(data, network) { - return !HDPrivateKey.getSerializedError(data, network); -}; +function P224() { + MPrime.call( + this, + 'p224', + 'ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001'); +} +inherits(P224, MPrime); -/** - * Checks what's the error that causes the validation of a serialized private key - * in base58 with checksum to fail. - * - * @param {string|Buffer} data - the serialized private key - * @param {string|Network=} network - optional, if present, checks that the - * network provided matches the network serialized. - * @return {errors.InvalidArgument|null} - */ -HDPrivateKey.getSerializedError = function(data, network) { - /* jshint maxcomplexity: 10 */ - if (!(_.isString(data) || BufferUtil.isBuffer(data))) { - return new hdErrors.UnrecognizedArgument('Expected string or buffer'); - } - if (!Base58.validCharacters(data)) { - return new errors.InvalidB58Char('(unknown)', data); - } - try { - data = Base58Check.decode(data); - } catch (e) { - return new errors.InvalidB58Checksum(data); - } - if (data.length !== HDPrivateKey.DataLength) { - return new hdErrors.InvalidLength(data); - } - if (!_.isUndefined(network)) { - var error = HDPrivateKey._validateNetwork(data, network); - if (error) { - return error; - } +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] * 0x13 + carry; + var lo = hi & 0x3ffffff; + hi >>>= 26; + + num.words[i] = lo; + carry = hi; } - return null; + if (carry !== 0) + num.words[num.length++] = carry; + return num; }; -HDPrivateKey._validateNetwork = function(data, networkArg) { - var network = Network.get(networkArg); - if (!network) { - return new errors.InvalidNetworkArgument(networkArg); - } - var version = data.slice(0, 4); - if (BufferUtil.integerFromBuffer(version) !== network.xprivkey) { - return new errors.InvalidNetwork(version); +// 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 { + this.m = m; + this.prime = null; } - return null; +} + +Red.prototype._verify1 = function _verify1(a) { + assert(!a.sign, 'red works only with positives'); + assert(a.red, 'red works only with red numbers'); }; -HDPrivateKey.fromJSON = function(arg) { - $.checkArgument(JSUtil.isValidJSON(arg), 'No valid JSON string was provided'); - return new HDPrivateKey(arg); +Red.prototype._verify2 = function _verify2(a, b) { + assert(!a.sign && !b.sign, 'red works only with positives'); + assert(a.red && a.red === b.red, + 'red works only with red numbers'); }; -HDPrivateKey.fromString = function(arg) { - $.checkArgument(_.isString(arg), 'No valid string was provided'); - return new HDPrivateKey(arg); +Red.prototype.imod = function imod(a) { + if (this.prime) + return this.prime.ireduce(a)._forceRed(this); + return a.mod(this.m)._forceRed(this); }; -HDPrivateKey.fromObject = function(arg) { - $.checkArgument(_.isObject(arg), 'No valid argument was provided'); - return new HDPrivateKey(arg); +Red.prototype.neg = function neg(a) { + var r = a.clone(); + r.sign = !r.sign; + return r.iadd(this.m)._forceRed(this); }; -HDPrivateKey.prototype._buildFromJSON = function(arg) { - return this._buildFromObject(JSON.parse(arg)); +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); }; -HDPrivateKey.prototype._buildFromObject = function(arg) { - /* jshint maxcomplexity: 12 */ - // TODO: Type validation - var buffers = { - version: arg.network ? BufferUtil.integerAsBuffer(Network.get(arg.network).xprivkey) : arg.version, - depth: _.isNumber(arg.depth) ? BufferUtil.integerAsSingleByteBuffer(arg.depth) : arg.depth, - parentFingerPrint: _.isNumber(arg.parentFingerPrint) ? BufferUtil.integerAsBuffer(arg.parentFingerPrint) : arg.parentFingerPrint, - childIndex: _.isNumber(arg.childIndex) ? BufferUtil.integerAsBuffer(arg.childIndex) : arg.childIndex, - chainCode: _.isString(arg.chainCode) ? BufferUtil.hexToBuffer(arg.chainCode) : arg.chainCode, - privateKey: (_.isString(arg.privateKey) && JSUtil.isHexa(arg.privateKey)) ? BufferUtil.hexToBuffer(arg.privateKey) : arg.privateKey, - checksum: arg.checksum ? (arg.checksum.length ? arg.checksum : BufferUtil.integerAsBuffer(arg.checksum)) : undefined - }; - return this._buildFromBuffers(buffers); +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; }; -HDPrivateKey.prototype._buildFromSerialized = function(arg) { - var decoded = Base58Check.decode(arg); - var buffers = { - version: decoded.slice(HDPrivateKey.VersionStart, HDPrivateKey.VersionEnd), - depth: decoded.slice(HDPrivateKey.DepthStart, HDPrivateKey.DepthEnd), - parentFingerPrint: decoded.slice(HDPrivateKey.ParentFingerPrintStart, - HDPrivateKey.ParentFingerPrintEnd), - childIndex: decoded.slice(HDPrivateKey.ChildIndexStart, HDPrivateKey.ChildIndexEnd), - chainCode: decoded.slice(HDPrivateKey.ChainCodeStart, HDPrivateKey.ChainCodeEnd), - privateKey: decoded.slice(HDPrivateKey.PrivateKeyStart, HDPrivateKey.PrivateKeyEnd), - checksum: decoded.slice(HDPrivateKey.ChecksumStart, HDPrivateKey.ChecksumEnd), - xprivkey: arg - }; - return this._buildFromBuffers(buffers); +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); }; -HDPrivateKey.prototype._generateRandomly = function(network) { - return HDPrivateKey.fromSeed(Random.getRandomBuffer(64), network); +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; }; -/** - * Generate a private key from a seed, as described in BIP32 - * - * @param {string|Buffer} hexa - * @param {*} network - * @return HDPrivateKey - */ -HDPrivateKey.fromSeed = function(hexa, network) { - /* jshint maxcomplexity: 8 */ - if (JSUtil.isHexaString(hexa)) { - hexa = BufferUtil.hexToBuffer(hexa); - } - if (!Buffer.isBuffer(hexa)) { - throw new hdErrors.InvalidEntropyArgument(hexa); - } - if (hexa.length < MINIMUM_ENTROPY_BITS * BITS_TO_BYTES) { - throw new hdErrors.InvalidEntropyArgument.NotEnoughEntropy(hexa); - } - if (hexa.length > MAXIMUM_ENTROPY_BITS * BITS_TO_BYTES) { - throw new hdErrors.InvalidEntropyArgument.TooMuchEntropy(hexa); - } - var hash = Hash.sha512hmac(hexa, new buffer.Buffer('Bitcoin seed')); +Red.prototype.shl = function shl(a, num) { + this._verify1(a); + return this.imod(a.shln(num)); +}; - return new HDPrivateKey({ - network: Network.get(network) || Network.defaultNetwork, - depth: 0, - parentFingerPrint: 0, - childIndex: 0, - privateKey: hash.slice(0, 32), - chainCode: hash.slice(32, 64) - }); +Red.prototype.imul = function imul(a, b) { + this._verify2(a, b); + return this.imod(a.imul(b)); }; -/** - * Receives a object with buffers in all the properties and populates the - * internal structure - * - * @param {Object} arg - * @param {buffer.Buffer} arg.version - * @param {buffer.Buffer} arg.depth - * @param {buffer.Buffer} arg.parentFingerPrint - * @param {buffer.Buffer} arg.childIndex - * @param {buffer.Buffer} arg.chainCode - * @param {buffer.Buffer} arg.privateKey - * @param {buffer.Buffer} arg.checksum - * @param {string=} arg.xprivkey - if set, don't recalculate the base58 - * representation - * @return {HDPrivateKey} this - */ -HDPrivateKey.prototype._buildFromBuffers = function(arg) { - /* jshint maxcomplexity: 8 */ - /* jshint maxstatements: 20 */ +Red.prototype.mul = function mul(a, b) { + this._verify2(a, b); + return this.imod(a.mul(b)); +}; - HDPrivateKey._validateBufferArguments(arg); +Red.prototype.isqr = function isqr(a) { + return this.imul(a, a); +}; - JSUtil.defineImmutable(this, { - _buffers: arg - }); +Red.prototype.sqr = function sqr(a) { + return this.mul(a, a); +}; - var sequence = [ - arg.version, arg.depth, arg.parentFingerPrint, arg.childIndex, arg.chainCode, - BufferUtil.emptyBuffer(1), arg.privateKey - ]; - var concat = buffer.Buffer.concat(sequence); - if (!arg.checksum || !arg.checksum.length) { - arg.checksum = Base58Check.checksum(concat); - } else { - if (arg.checksum.toString() !== Base58Check.checksum(concat).toString()) { - throw new errors.InvalidB58Checksum(concat); - } +Red.prototype.sqrt = function sqrt(a) { + if (a.cmpn(0) === 0) + 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)).ishrn(2); + var r = this.pow(a, pow); + return r; } - var network = Network.get(BufferUtil.integerFromBuffer(arg.version)); - var xprivkey; - xprivkey = Base58Check.encode(buffer.Buffer.concat(sequence)); - arg.xprivkey = new Buffer(xprivkey); + // 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.cmpn(0) !== 0 && q.andln(1) === 0) { + s++; + q.ishrn(1); + } + assert(q.cmpn(0) !== 0); - var privateKey = new PrivateKey(BN.fromBuffer(arg.privateKey), network); - var publicKey = privateKey.toPublicKey(); - var size = HDPrivateKey.ParentFingerPrintSize; - var fingerPrint = Hash.sha256ripemd160(publicKey.toBuffer()).slice(0, size); + var one = new BN(1).toRed(this); + var nOne = one.redNeg(); - JSUtil.defineImmutable(this, { - xprivkey: xprivkey, - network: network, - depth: BufferUtil.integerFromSingleByteBuffer(arg.depth), - privateKey: privateKey, - publicKey: publicKey, - fingerPrint: fingerPrint - }); + // Find quadratic non-residue + // NOTE: Max is such because of generalized Riemann hypothesis. + var lpow = this.m.subn(1).ishrn(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 HDPublicKey = require('./hdpublickey'); - var hdPublicKey = new HDPublicKey(this); + var c = this.pow(z, q); + var r = this.pow(a, q.addn(1).ishrn(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).ishln(m - i - 1)); - JSUtil.defineImmutable(this, { - hdPublicKey: hdPublicKey, - xpubkey: hdPublicKey.xpubkey - }); + r = r.redMul(b); + c = b.redSqr(); + t = t.redMul(c); + m = i; + } - return this; + return r; }; -HDPrivateKey._validateBufferArguments = function(arg) { - var checkBuffer = function(name, size) { - var buff = arg[name]; - assert(BufferUtil.isBuffer(buff), name + ' argument is not a buffer'); - assert( - buff.length === size, - name + ' has not the expected size: found ' + buff.length + ', expected ' + size - ); - }; - checkBuffer('version', HDPrivateKey.VersionSize); - checkBuffer('depth', HDPrivateKey.DepthSize); - checkBuffer('parentFingerPrint', HDPrivateKey.ParentFingerPrintSize); - checkBuffer('childIndex', HDPrivateKey.ChildIndexSize); - checkBuffer('chainCode', HDPrivateKey.ChainCodeSize); - checkBuffer('privateKey', HDPrivateKey.PrivateKeySize); - if (arg.checksum && arg.checksum.length) { - checkBuffer('checksum', HDPrivateKey.CheckSumSize); +Red.prototype.invm = function invm(a) { + var inv = a._egcd(new BN(1), this.m); + if (inv.sign) { + inv.sign = false; + return this.imod(inv).redNeg(); + } else { + return this.imod(inv); } }; -/** - * Returns the string representation of this private key (a string starting - * with "xprv..." - * - * @return string - */ -HDPrivateKey.prototype.toString = function() { - return this.xprivkey; -}; +Red.prototype.pow = function pow(a, num) { + var w = []; + var q = num.clone(); + while (q.cmpn(0) !== 0) { + w.push(q.andln(1)); + q.ishrn(1); + } -/** - * Returns the console representation of this extended private key. - * @return string - */ -HDPrivateKey.prototype.inspect = function() { - return ''; -}; + // Skip leading zeroes + var res = a; + for (var i = 0; i < w.length; i++, res = this.sqr(res)) + if (w[i] !== 0) + break; -/** - * Returns a plain object with a representation of this private key. - * - * Fields include:
    - *
  • network: either 'livenet' or 'testnet' - *
  • depth: a number ranging from 0 to 255 - *
  • fingerPrint: a number ranging from 0 to 2^32-1, taken from the hash of the - *
  • associated public key - *
  • parentFingerPrint: a number ranging from 0 to 2^32-1, taken from the hash - *
  • of this parent's associated public key or zero. - *
  • childIndex: the index from which this child was derived (or zero) - *
  • chainCode: an hexa string representing a number used in the derivation - *
  • privateKey: the private key associated, in hexa representation - *
  • xprivkey: the representation of this extended private key in checksum - *
  • base58 format - *
  • checksum: the base58 checksum of xprivkey - *
- * @return {Object} - */ -HDPrivateKey.prototype.toObject = function toObject() { - return { - network: Network.get(BufferUtil.integerFromBuffer(this._buffers.version)).name, - depth: BufferUtil.integerFromSingleByteBuffer(this._buffers.depth), - fingerPrint: BufferUtil.integerFromBuffer(this.fingerPrint), - parentFingerPrint: BufferUtil.integerFromBuffer(this._buffers.parentFingerPrint), - childIndex: BufferUtil.integerFromBuffer(this._buffers.childIndex), - chainCode: BufferUtil.bufferToHex(this._buffers.chainCode), - privateKey: this.privateKey.toBuffer().toString('hex'), - checksum: BufferUtil.integerFromBuffer(this._buffers.checksum), - xprivkey: this.xprivkey - }; -}; + if (++i < w.length) { + for (var q = this.sqr(res); i < w.length; i++, q = this.sqr(q)) { + if (w[i] === 0) + continue; + res = this.mul(res, q); + } + } -/** - * Returns a JSON representation of the HDPrivateKey - * - * @return {string} - */ -HDPrivateKey.prototype.toJSON = function toJSON() { - return JSON.stringify(this.toObject()); + return res; }; -/** - * Build a HDPrivateKey from a buffer - * - * @param {Buffer} arg - * @return {HDPrivateKey} - */ -HDPrivateKey.fromBuffer = function(arg) { - return new HDPrivateKey(arg.toString()); +Red.prototype.convertTo = function convertTo(num) { + return num.clone(); }; -/** - * Returns a buffer representation of the HDPrivateKey - * - * @return {string} - */ -HDPrivateKey.prototype.toBuffer = function() { - return BufferUtil.copy(this._buffers.xprivkey); +Red.prototype.convertFrom = function convertFrom(num) { + var res = num.clone(); + res.red = null; + return res; }; -HDPrivateKey.DefaultDepth = 0; -HDPrivateKey.DefaultFingerprint = 0; -HDPrivateKey.DefaultChildIndex = 0; -HDPrivateKey.Hardened = 0x80000000; -HDPrivateKey.MaxIndex = 2 * HDPrivateKey.Hardened; +// +// Montgomery method engine +// -HDPrivateKey.RootElementAlias = ['m', 'M', 'm\'', 'M\'']; +BN.mont = function mont(num) { + return new Mont(num); +}; -HDPrivateKey.VersionSize = 4; -HDPrivateKey.DepthSize = 1; -HDPrivateKey.ParentFingerPrintSize = 4; -HDPrivateKey.ChildIndexSize = 4; -HDPrivateKey.ChainCodeSize = 32; -HDPrivateKey.PrivateKeySize = 32; -HDPrivateKey.CheckSumSize = 4; +function Mont(m) { + Red.call(this, m); -HDPrivateKey.DataLength = 78; -HDPrivateKey.SerializedByteSize = 82; + this.shift = this.m.bitLength(); + if (this.shift % 26 !== 0) + this.shift += 26 - (this.shift % 26); + this.r = new BN(1).ishln(this.shift); + this.r2 = this.imod(this.r.sqr()); + this.rinv = this.r.invm(this.m); -HDPrivateKey.VersionStart = 0; -HDPrivateKey.VersionEnd = HDPrivateKey.VersionStart + HDPrivateKey.VersionSize; -HDPrivateKey.DepthStart = HDPrivateKey.VersionEnd; -HDPrivateKey.DepthEnd = HDPrivateKey.DepthStart + HDPrivateKey.DepthSize; -HDPrivateKey.ParentFingerPrintStart = HDPrivateKey.DepthEnd; -HDPrivateKey.ParentFingerPrintEnd = HDPrivateKey.ParentFingerPrintStart + HDPrivateKey.ParentFingerPrintSize; -HDPrivateKey.ChildIndexStart = HDPrivateKey.ParentFingerPrintEnd; -HDPrivateKey.ChildIndexEnd = HDPrivateKey.ChildIndexStart + HDPrivateKey.ChildIndexSize; -HDPrivateKey.ChainCodeStart = HDPrivateKey.ChildIndexEnd; -HDPrivateKey.ChainCodeEnd = HDPrivateKey.ChainCodeStart + HDPrivateKey.ChainCodeSize; -HDPrivateKey.PrivateKeyStart = HDPrivateKey.ChainCodeEnd + 1; -HDPrivateKey.PrivateKeyEnd = HDPrivateKey.PrivateKeyStart + HDPrivateKey.PrivateKeySize; -HDPrivateKey.ChecksumStart = HDPrivateKey.PrivateKeyEnd; -HDPrivateKey.ChecksumEnd = HDPrivateKey.ChecksumStart + HDPrivateKey.CheckSumSize; + // TODO(indutny): simplify it + this.minv = this.rinv.mul(this.r) + .sub(new BN(1)) + .div(this.m) + .neg() + .mod(this.r); +} +inherits(Mont, Red); -assert(HDPrivateKey.ChecksumEnd === HDPrivateKey.SerializedByteSize); +Mont.prototype.convertTo = function convertTo(num) { + return this.imod(num.shln(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.cmpn(0) === 0 || b.cmpn(0) === 0) { + 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).ishrn(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.cmpn(0) === 0 || b.cmpn(0) === 0) + 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).ishrn(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.invm(this.m).mul(this.r2)); + return res._forceRed(this); +}; + +},{}],29:[function(require,module,exports){ +try { + var asn1 = require('asn1.js'); +} catch (e) { + var asn1 = require('../..'); +} + +var CRLReason = asn1.define('CRLReason', function() { + this.enum({ + 0: 'unspecified', + 1: 'keyCompromise', + 2: 'CACompromise', + 3: 'affiliationChanged', + 4: 'superseded', + 5: 'cessationOfOperation', + 6: 'certificateHold', + 8: 'removeFromCRL', + 9: 'privilegeWithdrawn', + 10: 'AACompromise' + }); +}); +exports.CRLReason = CRLReason; + +var AlgorithmIdentifier = asn1.define('AlgorithmIdentifier', function() { + this.seq().obj( + this.key('algorithm').objid(), + this.key('parameters').optional().any() + ); +}); +exports.AlgorithmIdentifier = AlgorithmIdentifier; + +var Certificate = asn1.define('Certificate', function() { + this.seq().obj( + this.key('tbsCertificate').use(TBSCertificate), + this.key('signatureAlgorithm').use(AlgorithmIdentifier), + this.key('signature').bitstr() + ); +}); +exports.Certificate = Certificate; + +var TBSCertificate = asn1.define('TBSCertificate', function() { + this.seq().obj( + this.key('version').def('v1').explicit(0).use(Version), + this.key('serialNumber').use(CertificateSerialNumber), + this.key('signature').use(AlgorithmIdentifier), + this.key('issuer').use(Name), + this.key('validity').use(Validity), + this.key('subject').use(Name), + this.key('subjectPublicKeyInfo').use(SubjectPublicKeyInfo), + + // TODO(indutny): validate that version is v2 or v3 + this.key('issuerUniqueID').optional().explicit(1).use(UniqueIdentifier), + this.key('subjectUniqueID').optional().explicit(2).use(UniqueIdentifier), + + // TODO(indutny): validate that version is v3 + this.key('extensions').optional().explicit(3).use(Extensions) + ); +}); +exports.TBSCertificate = TBSCertificate; + +var Version = asn1.define('Version', function() { + this.int({ + 0: 'v1', + 1: 'v2', + 2: 'v3' + }); +}); +exports.Version = Version; + +var CertificateSerialNumber = asn1.define('CertificateSerialNumber', + function() { + this.int(); +}); +exports.CertificateSerialNumber = CertificateSerialNumber; + +var Validity = asn1.define('Validity', function() { + this.seq().obj( + this.key('notBefore').use(Time), + this.key('notAfter').use(Time) + ); +}); +exports.Validity = Validity; + +var Time = asn1.define('Time', function() { + this.choice({ + utcTime: this.utctime(), + genTime: this.gentime() + }); +}); +exports.Time = Time; + +var UniqueIdentifier = asn1.define('UniqueIdentifier', function() { + this.bitstr(); +}); +exports.UniqueIdentifier = UniqueIdentifier; + +var SubjectPublicKeyInfo = asn1.define('SubjectPublicKeyInfo', function() { + this.seq().obj( + this.key('algorithm').use(AlgorithmIdentifier), + this.key('subjectPublicKey').bitstr() + ); +}); +exports.SubjectPublicKeyInfo = SubjectPublicKeyInfo; + +var Extensions = asn1.define('Extensions', function() { + this.seqof(Extension); +}); +exports.Extensions = Extensions; + +var Extension = asn1.define('Extension', function() { + this.seq().obj( + this.key('extnID').objid(), + this.key('critical').bool().def(false), + this.key('extnValue').octstr() + ); +}); +exports.Extension = Extension; + +var Name = asn1.define('Name', function() { + this.choice({ + rdn: this.use(RDNSequence) + }); +}); +exports.Name = Name; + +var RDNSequence = asn1.define('RDNSequence', function() { + this.seqof(RelativeDistinguishedName); +}); +exports.RDNSequence = RDNSequence; + +var RelativeDistinguishedName = asn1.define('RelativeDistinguishedName', + function() { + this.setof(AttributeTypeAndValue); +}); +exports.RelativeDistinguishedName = RelativeDistinguishedName; + +var AttributeTypeAndValue = asn1.define('AttributeTypeAndValue', function() { + this.seq().obj( + this.key('type').use(AttributeType), + this.key('value').use(AttributeValue) + ); +}); +exports.AttributeTypeAndValue = AttributeTypeAndValue; + +var AttributeType = asn1.define('AttributeType', function() { + this.objid(); +}); +exports.AttributeType = AttributeType; + +var AttributeValue = asn1.define('AttributeValue', function() { + this.any(); +}); +exports.AttributeValue = AttributeValue; + +},{"../..":16,"asn1.js":16}],30:[function(require,module,exports){ +(function (Buffer){ +var bitcore = module.exports; -module.exports = HDPrivateKey; + +// crypto +bitcore.crypto = {}; +bitcore.crypto.BN = require('./lib/crypto/bn'); +bitcore.crypto.ECDSA = require('./lib/crypto/ecdsa'); +bitcore.crypto.Hash = require('./lib/crypto/hash'); +bitcore.crypto.Random = require('./lib/crypto/random'); +bitcore.crypto.Point = require('./lib/crypto/point'); +bitcore.crypto.Signature = require('./lib/crypto/signature'); + +// encoding +bitcore.encoding = {}; +bitcore.encoding.Base58 = require('./lib/encoding/base58'); +bitcore.encoding.Base58Check = require('./lib/encoding/base58check'); +bitcore.encoding.BufferReader = require('./lib/encoding/bufferreader'); +bitcore.encoding.BufferWriter = require('./lib/encoding/bufferwriter'); +bitcore.encoding.Varint = require('./lib/encoding/varint'); + +// utilities +bitcore.util = {}; +bitcore.util.buffer = require('./lib/util/buffer'); +bitcore.util.js = require('./lib/util/js'); +bitcore.util.preconditions = require('./lib/util/preconditions'); + +// errors thrown by the library +bitcore.errors = require('./lib/errors'); + +// main bitcoin library +bitcore.Address = require('./lib/address'); +bitcore.Block = require('./lib/block'); +bitcore.BlockHeader = require('./lib/blockheader'); +bitcore.HDPrivateKey = require('./lib/hdprivatekey.js'); +bitcore.HDPublicKey = require('./lib/hdpublickey.js'); +bitcore.Networks = require('./lib/networks'); +bitcore.Opcode = require('./lib/opcode'); +bitcore.PrivateKey = require('./lib/privatekey'); +bitcore.PublicKey = require('./lib/publickey'); +bitcore.Script = require('./lib/script'); +bitcore.Transaction = require('./lib/transaction'); +bitcore.URI = require('./lib/uri'); +bitcore.Unit = require('./lib/unit'); + +// dependencies, subject to change +bitcore.deps = {}; +bitcore.deps.bnjs = require('bn.js'); +bitcore.deps.bs58 = require('bs58'); +bitcore.deps.Buffer = Buffer; +bitcore.deps.elliptic = require('elliptic'); +bitcore.deps._ = require('lodash'); + +// Internal usage, exposed for testing/advanced tweaking +bitcore._HDKeyCache = require('./lib/hdkeycache'); +bitcore.Transaction.sighash = require('./lib/transaction/sighash'); + +// module information +bitcore.version = 'v'+require('./package.json').version; }).call(this,require("buffer").Buffer) -},{"./crypto/bn":18,"./crypto/hash":20,"./crypto/point":21,"./crypto/random":22,"./encoding/base58":24,"./encoding/base58check":25,"./errors":29,"./hdkeycache":31,"./hdpublickey":33,"./networks":34,"./privatekey":36,"./util/buffer":53,"./util/js":54,"./util/preconditions":55,"assert":89,"buffer":104,"lodash":79}],33:[function(require,module,exports){ +},{"./lib/address":31,"./lib/block":32,"./lib/blockheader":33,"./lib/crypto/bn":34,"./lib/crypto/ecdsa":35,"./lib/crypto/hash":36,"./lib/crypto/point":37,"./lib/crypto/random":38,"./lib/crypto/signature":39,"./lib/encoding/base58":40,"./lib/encoding/base58check":41,"./lib/encoding/bufferreader":42,"./lib/encoding/bufferwriter":43,"./lib/encoding/varint":44,"./lib/errors":45,"./lib/hdkeycache":47,"./lib/hdprivatekey.js":48,"./lib/hdpublickey.js":49,"./lib/networks":50,"./lib/opcode":51,"./lib/privatekey":52,"./lib/publickey":53,"./lib/script":54,"./lib/transaction":57,"./lib/transaction/sighash":63,"./lib/unit":67,"./lib/uri":68,"./lib/util/buffer":69,"./lib/util/js":70,"./lib/util/preconditions":71,"./package.json":102,"bn.js":72,"bs58":73,"buffer":209,"elliptic":74,"lodash":95}],31:[function(require,module,exports){ (function (Buffer){ 'use strict'; var _ = require('lodash'); var $ = require('./util/preconditions'); - -var BN = require('./crypto/bn'); -var Base58 = require('./encoding/base58'); var Base58Check = require('./encoding/base58check'); +var Networks = require('./networks'); var Hash = require('./crypto/hash'); -var HDPrivateKey = require('./hdprivatekey'); -var HDKeyCache = require('./hdkeycache'); -var Network = require('./networks'); -var Point = require('./crypto/point'); -var PublicKey = require('./publickey'); - -var bitcoreErrors = require('./errors'); -var errors = bitcoreErrors; -var hdErrors = bitcoreErrors.HDPublicKey; -var assert = require('assert'); - var JSUtil = require('./util/js'); -var BufferUtil = require('./util/buffer'); /** - * The representation of an hierarchically derived public key. + * Instantiate an address from an address String or Buffer, a public key or script hash Buffer, + * or an instance of {@link PublicKey} or {@link Script}. * - * See https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki + * This is an immutable class, and if the first parameter provided to this constructor is an + * `Address` instance, the same argument will be returned. + * + * An address has two key properties: `network` and `type`. The type is either + * `Address.PayToPublicKeyHash` (value is the `'pubkeyhash'` string) + * or `Address.PayToScriptHash` (the string `'scripthash'`). The network is an instance of {@link Network}. + * You can quickly check whether an address is of a given kind by using the methods + * `isPayToPublicKeyHash` and `isPayToScriptHash` + * + * @example + * ```javascript + * // validate that an input field is valid + * var error = Address.getValidationError(input, 'testnet'); + * if (!error) { + * var address = Address(input, 'testnet'); + * } else { + * // invalid network or checksum (typo?) + * var message = error.messsage; + * } + * + * // get an address from a public key + * var address = Address(publicKey, 'testnet').toString(); + * ``` * + * @param {*} data - The encoded data in various formats + * @param {Network|String|number} [network] - The network: 'livenet' or 'testnet' + * @param {String} [type] - The type of address: 'script' or 'pubkey' + * @returns {Address} A new valid and frozen instance of an Address * @constructor - * @param {Object|string|Buffer} arg */ -function HDPublicKey(arg) { +function Address(data, network, type) { /* jshint maxcomplexity: 12 */ /* jshint maxstatements: 20 */ - if (arg instanceof HDPublicKey) { - return arg; - } - if (!(this instanceof HDPublicKey)) { - return new HDPublicKey(arg); - } - if (arg) { - if (_.isString(arg) || BufferUtil.isBuffer(arg)) { - var error = HDPublicKey.getSerializedError(arg); - if (!error) { - return this._buildFromSerialized(arg); - } else if (JSUtil.isValidJSON(arg)) { - return this._buildFromJSON(arg); - } else if (BufferUtil.isBuffer(arg) && !HDPublicKey.getSerializedError(arg.toString())) { - return this._buildFromSerialized(arg.toString()); - } else { - if (error instanceof hdErrors.ArgumentIsPrivateExtended) { - return new HDPrivateKey(arg).hdPublicKey; - } - throw error; - } - } else { - if (_.isObject(arg)) { - if (arg instanceof HDPrivateKey) { - return this._buildFromPrivate(arg); - } else { - return this._buildFromObject(arg); - } - } else { - throw new hdErrors.UnrecognizedArgument(arg); - } - } - } else { - throw new hdErrors.MustSupplyArgument(); + + if (!(this instanceof Address)) { + return new Address(data, network, type); } -} -/** - * Verifies that a given path is valid. - * - * @param {string|number} arg - * @return {boolean} - */ -HDPublicKey.isValidPath = function(arg) { - if (_.isString(arg)) { - var indexes = HDPrivateKey._getDerivationIndexes(arg); - return indexes !== null && _.all(indexes, HDPublicKey.isValidPath); + if (_.isArray(data) && _.isNumber(network)) { + return Address.createMultisig(data, network, type); } - if (_.isNumber(arg)) { - return arg >= 0 && arg < HDPublicKey.Hardened; + if (data instanceof Address) { + // Immutable instance + return data; } - return false; -}; + $.checkArgument(data, 'First argument is required, please include address data.', 'guide/address.html'); -/** - * Get a derivated child based on a string or number. - * - * If the first argument is a string, it's parsed as the full path of - * derivation. Valid values for this argument include "m" (which returns the - * same public key), "m/0/1/40/2/1000". - * - * Note that hardened keys can't be derived from a public extended key. - * - * If the first argument is a number, the child with that index will be - * derived. See the example usage for clarification. - * - * @example - * ```javascript - * var parent = new HDPublicKey('xpub...'); - * var child_0_1_2 = parent.derive(0).derive(1).derive(2); - * var copy_of_child_0_1_2 = parent.derive("m/0/1/2"); - * assert(child_0_1_2.xprivkey === copy_of_child_0_1_2); - * ``` - * - * @param {string|number} arg - */ -HDPublicKey.prototype.derive = function (arg) { - if (_.isNumber(arg)) { - return this._deriveWithNumber(arg); - } else if (_.isString(arg)) { - return this._deriveFromString(arg); - } else { - throw new hdErrors.InvalidDerivationArgument(arg); + if (network && !Networks.get(network)) { + throw new TypeError('Second argument must be "livenet" or "testnet".'); } -}; -HDPublicKey.prototype._deriveWithNumber = function (index) { - if (index >= HDPublicKey.Hardened) { - throw new hdErrors.InvalidIndexCantDeriveHardened(); - } - if (index < 0) { - throw new hdErrors.InvalidPath(index); - } - var cached = HDKeyCache.get(this.xpubkey, index, false); - if (cached) { - return cached; + if (type && (type !== Address.PayToPublicKeyHash && type !== Address.PayToScriptHash)) { + throw new TypeError('Third argument must be "pubkeyhash" or "scripthash".'); } - var indexBuffer = BufferUtil.integerAsBuffer(index); - var data = BufferUtil.concat([this.publicKey.toBuffer(), indexBuffer]); - var hash = Hash.sha512hmac(data, this._buffers.chainCode); - var leftPart = BN.fromBuffer(hash.slice(0, 32), {size: 32}); - var chainCode = hash.slice(32, 64); + var info = this._classifyArguments(data, network, type); - var publicKey = PublicKey.fromPoint(Point.getG().mul(leftPart).add(this.publicKey.point)); + // set defaults if not set + info.network = info.network || Networks.get(network) || Networks.defaultNetwork; + info.type = info.type || type || Address.PayToPublicKeyHash; - var derived = new HDPublicKey({ - network: this.network, - depth: this.depth + 1, - parentFingerPrint: this.fingerPrint, - childIndex: index, - chainCode: chainCode, - publicKey: publicKey + JSUtil.defineImmutable(this, { + hashBuffer: info.hashBuffer, + network: info.network, + type: info.type }); - HDKeyCache.set(this.xpubkey, index, false, derived); - return derived; -}; - -HDPublicKey.prototype._deriveFromString = function (path) { - /* jshint maxcomplexity: 8 */ - if (_.contains(path, "'")) { - throw new hdErrors.InvalidIndexCantDeriveHardened(); - } else if (!HDPublicKey.isValidPath(path)) { - throw new hdErrors.InvalidPath(path); - } - - var indexes = HDPrivateKey._getDerivationIndexes(path); - var derived = indexes.reduce(function(prev, index) { - return prev._deriveWithNumber(index); - }, this); - return derived; -}; + return this; +} /** - * Verifies that a given serialized public key in base58 with checksum format - * is valid. - * - * @param {string|Buffer} data - the serialized public key - * @param {string|Network=} network - optional, if present, checks that the - * network provided matches the network serialized. - * @return {boolean} + * Internal function used to split different kinds of arguments of the constructor + * @param {*} data - The encoded data in various formats + * @param {Network|String|number} [network] - The network: 'livenet' or 'testnet' + * @param {String} [type] - The type of address: 'script' or 'pubkey' + * @returns {Object} An "info" object with "type", "network", and "hashBuffer" */ -HDPublicKey.isValidSerialized = function (data, network) { - return _.isNull(HDPublicKey.getSerializedError(data, network)); +Address.prototype._classifyArguments = function(data, network, type) { + var PublicKey = require('./publickey'); + var Script = require('./script'); + /* jshint maxcomplexity: 10 */ + // transform and validate input data + if ((data instanceof Buffer || data instanceof Uint8Array) && data.length === 20) { + return Address._transformHash(data); + } else if ((data instanceof Buffer || data instanceof Uint8Array) && data.length === 21) { + return Address._transformBuffer(data, network, type); + } else if (data instanceof PublicKey) { + return Address._transformPublicKey(data); + } else if (data instanceof Script) { + return Address._transformScript(data, network); + } else if (typeof(data) === 'string') { + return Address._transformString(data, network, type); + } else if (_.isObject(data)) { + return Address._transformObject(data); + } else { + throw new TypeError('First argument is an unrecognized data format.'); + } }; +/** @static */ +Address.PayToPublicKeyHash = 'pubkeyhash'; +/** @static */ +Address.PayToScriptHash = 'scripthash'; + /** - * Checks what's the error that causes the validation of a serialized public key - * in base58 with checksum to fail. - * - * @param {string|Buffer} data - the serialized public key - * @param {string|Network=} network - optional, if present, checks that the - * network provided matches the network serialized. - * @return {errors|null} + * @param {Buffer} hash - An instance of a hash Buffer + * @returns {Object} An object with keys: hashBuffer + * @private */ -HDPublicKey.getSerializedError = function (data, network) { - /* jshint maxcomplexity: 10 */ - /* jshint maxstatements: 20 */ - if (!(_.isString(data) || BufferUtil.isBuffer(data))) { - return new hdErrors.UnrecognizedArgument('expected buffer or string'); - } - if (!Base58.validCharacters(data)) { - return new errors.InvalidB58Char('(unknown)', data); - } - try { - data = Base58Check.decode(data); - } catch (e) { - return new errors.InvalidB58Checksum(data); - } - if (data.length !== HDPublicKey.DataSize) { - return new errors.InvalidLength(data); - } - if (!_.isUndefined(network)) { - var error = HDPublicKey._validateNetwork(data, network); - if (error) { - return error; - } +Address._transformHash = function(hash){ + var info = {}; + if (!(hash instanceof Buffer) && !(hash instanceof Uint8Array)) { + throw new TypeError('Address supplied is not a buffer.'); } - var version = BufferUtil.integerFromBuffer(data.slice(0, 4)); - if (version === Network.livenet.xprivkey || version === Network.testnet.xprivkey ) { - return new hdErrors.ArgumentIsPrivateExtended(); + if (hash.length !== 20) { + throw new TypeError('Address hashbuffers must be exactly 20 bytes.'); } - return null; + info.hashBuffer = hash; + return info; }; -HDPublicKey._validateNetwork = function (data, networkArg) { - var network = Network.get(networkArg); - if (!network) { - return new errors.InvalidNetworkArgument(networkArg); - } - var version = data.slice(HDPublicKey.VersionStart, HDPublicKey.VersionEnd); - if (BufferUtil.integerFromBuffer(version) !== network.xpubkey) { - return new errors.InvalidNetwork(version); - } - return null; +/** + * Deserializes an address serialized through `Address#toObject()` + * @param {Object} data + * @param {string} data.hash - the hash that this address encodes + * @param {string} data.type - either 'pubkeyhash' or 'scripthash' + * @param {Network=} data.network - the name of the network associated + * @return {Address} + */ +Address._transformObject = function(data) { + $.checkArgument(data.hash || data.hashBuffer, 'Must provide a `hash` or `hashBuffer` property'); + $.checkArgument(data.type, 'Must provide a `type` property'); + return { + hashBuffer: data.hash ? new Buffer(data.hash, 'hex') : data.hashBuffer, + network: Networks.get(data.network) || Networks.defaultNetwork, + type: data.type + }; }; -HDPublicKey.prototype._buildFromJSON = function (arg) { - return this._buildFromObject(JSON.parse(arg)); -}; +/** + * Internal function to discover the network and type based on the first data byte + * + * @param {Buffer} buffer - An instance of a hex encoded address Buffer + * @returns {Object} An object with keys: network and type + * @private + */ +Address._classifyFromVersion = function(buffer){ + var version = {}; + version.network = Networks.get(buffer[0]); + switch (buffer[0]) { // the version byte + case Networks.livenet.pubkeyhash: + version.type = Address.PayToPublicKeyHash; + break; -HDPublicKey.prototype._buildFromPrivate = function (arg) { - var args = _.clone(arg._buffers); - var point = Point.getG().mul(BN.fromBuffer(args.privateKey)); - args.publicKey = Point.pointToCompressed(point); - args.version = BufferUtil.integerAsBuffer(Network.get(BufferUtil.integerFromBuffer(args.version)).xpubkey); - args.privateKey = undefined; - args.checksum = undefined; - args.xprivkey = undefined; - return this._buildFromBuffers(args); -}; + case Networks.livenet.scripthash: + version.type = Address.PayToScriptHash; + break; -HDPublicKey.prototype._buildFromObject = function (arg) { - /* jshint maxcomplexity: 10 */ - // TODO: Type validation - var buffers = { - version: arg.network ? BufferUtil.integerAsBuffer(Network.get(arg.network).xpubkey) : arg.version, - depth: _.isNumber(arg.depth) ? BufferUtil.integerAsSingleByteBuffer(arg.depth) : arg.depth, - parentFingerPrint: _.isNumber(arg.parentFingerPrint) ? BufferUtil.integerAsBuffer(arg.parentFingerPrint) : arg.parentFingerPrint, - childIndex: _.isNumber(arg.childIndex) ? BufferUtil.integerAsBuffer(arg.childIndex) : arg.childIndex, - chainCode: _.isString(arg.chainCode) ? BufferUtil.hexToBuffer(arg.chainCode) : arg.chainCode, - publicKey: _.isString(arg.publicKey) ? BufferUtil.hexToBuffer(arg.publicKey) : - BufferUtil.isBuffer(arg.publicKey) ? arg.publicKey : arg.publicKey.toBuffer(), - checksum: _.isNumber(arg.checksum) ? BufferUtil.integerAsBuffer(arg.checksum) : arg.checksum - }; - return this._buildFromBuffers(buffers); -}; + case Networks.testnet.pubkeyhash: + version.type = Address.PayToPublicKeyHash; + break; -HDPublicKey.prototype._buildFromSerialized = function (arg) { - var decoded = Base58Check.decode(arg); - var buffers = { - version: decoded.slice(HDPublicKey.VersionStart, HDPublicKey.VersionEnd), - depth: decoded.slice(HDPublicKey.DepthStart, HDPublicKey.DepthEnd), - parentFingerPrint: decoded.slice(HDPublicKey.ParentFingerPrintStart, - HDPublicKey.ParentFingerPrintEnd), - childIndex: decoded.slice(HDPublicKey.ChildIndexStart, HDPublicKey.ChildIndexEnd), - chainCode: decoded.slice(HDPublicKey.ChainCodeStart, HDPublicKey.ChainCodeEnd), - publicKey: decoded.slice(HDPublicKey.PublicKeyStart, HDPublicKey.PublicKeyEnd), - checksum: decoded.slice(HDPublicKey.ChecksumStart, HDPublicKey.ChecksumEnd), - xpubkey: arg - }; - return this._buildFromBuffers(buffers); + case Networks.testnet.scripthash: + version.type = Address.PayToScriptHash; + break; + } + return version; }; /** - * Receives a object with buffers in all the properties and populates the - * internal structure + * Internal function to transform a bitcoin address buffer * - * @param {Object} arg - * @param {buffer.Buffer} arg.version - * @param {buffer.Buffer} arg.depth - * @param {buffer.Buffer} arg.parentFingerPrint - * @param {buffer.Buffer} arg.childIndex - * @param {buffer.Buffer} arg.chainCode - * @param {buffer.Buffer} arg.publicKey - * @param {buffer.Buffer} arg.checksum - * @param {string=} arg.xpubkey - if set, don't recalculate the base58 - * representation - * @return {HDPublicKey} this + * @param {Buffer} buffer - An instance of a hex encoded address Buffer + * @param {String} [network] - The network: 'livenet' or 'testnet' + * @param {String} [type] - The type: 'pubkeyhash' or 'scripthash' + * @returns {Object} An object with keys: hashBuffer, network and type + * @private */ -HDPublicKey.prototype._buildFromBuffers = function (arg) { - /* jshint maxcomplexity: 8 */ - /* jshint maxstatements: 20 */ - - HDPublicKey._validateBufferArguments(arg); - - JSUtil.defineImmutable(this, { - _buffers: arg - }); - - var sequence = [ - arg.version, arg.depth, arg.parentFingerPrint, arg.childIndex, arg.chainCode, - arg.publicKey - ]; - var concat = BufferUtil.concat(sequence); - var checksum = Base58Check.checksum(concat); - if (!arg.checksum || !arg.checksum.length) { - arg.checksum = checksum; - } else { - if (arg.checksum.toString('hex') !== checksum.toString('hex')) { - throw new errors.InvalidB58Checksum(concat, checksum); - } +Address._transformBuffer = function(buffer, network, type){ + /* jshint maxcomplexity: 9 */ + var info = {}; + if (!(buffer instanceof Buffer) && !(buffer instanceof Uint8Array)) { + throw new TypeError('Address supplied is not a buffer.'); + } + if (buffer.length !== 1 + 20) { + throw new TypeError('Address buffers must be exactly 21 bytes.'); } - var network = Network.get(BufferUtil.integerFromBuffer(arg.version)); - var xpubkey; - xpubkey = Base58Check.encode(BufferUtil.concat(sequence)); - arg.xpubkey = new Buffer(xpubkey); + network = Networks.get(network); + var bufferVersion = Address._classifyFromVersion(buffer); - var publicKey = new PublicKey(arg.publicKey, {network: network}); - var size = HDPublicKey.ParentFingerPrintSize; - var fingerPrint = Hash.sha256ripemd160(publicKey.toBuffer()).slice(0, size); + if (!bufferVersion.network || (network && network !== bufferVersion.network)) { + throw new TypeError('Address has mismatched network type.'); + } - JSUtil.defineImmutable(this, { - xpubkey: xpubkey, - network: network, - depth: BufferUtil.integerFromSingleByteBuffer(arg.depth), - publicKey: publicKey, - fingerPrint: fingerPrint - }); + if (!bufferVersion.type || ( type && type !== bufferVersion.type )) { + throw new TypeError('Address has mismatched type.'); + } - return this; + info.hashBuffer = buffer.slice(1); + info.network = bufferVersion.network; + info.type = bufferVersion.type; + return info; }; -HDPublicKey._validateBufferArguments = function (arg) { - var checkBuffer = function(name, size) { - var buff = arg[name]; - assert(BufferUtil.isBuffer(buff), name + ' argument is not a buffer, it\'s ' + typeof buff); - assert( - buff.length === size, - name + ' has not the expected size: found ' + buff.length + ', expected ' + size - ); - }; - checkBuffer('version', HDPublicKey.VersionSize); - checkBuffer('depth', HDPublicKey.DepthSize); - checkBuffer('parentFingerPrint', HDPublicKey.ParentFingerPrintSize); - checkBuffer('childIndex', HDPublicKey.ChildIndexSize); - checkBuffer('chainCode', HDPublicKey.ChainCodeSize); - checkBuffer('publicKey', HDPublicKey.PublicKeySize); - if (arg.checksum && arg.checksum.length) { - checkBuffer('checksum', HDPublicKey.CheckSumSize); +/** + * Internal function to transform a {@link PublicKey} + * + * @param {PublicKey} pubkey - An instance of PublicKey + * @returns {Object} An object with keys: hashBuffer, type + * @private + */ +Address._transformPublicKey = function(pubkey){ + var PublicKey = require('./publickey'); + var info = {}; + if (!(pubkey instanceof PublicKey)) { + throw new TypeError('Address must be an instance of PublicKey.'); } + info.hashBuffer = Hash.sha256ripemd160(pubkey.toBuffer()); + info.type = Address.PayToPublicKeyHash; + return info; }; -HDPublicKey.fromJSON = function(arg) { - $.checkArgument(JSUtil.isValidJSON(arg), 'No valid JSON string was provided'); - return new HDPublicKey(arg); -}; - -HDPublicKey.fromObject = function(arg) { - $.checkArgument(_.isObject(arg), 'No valid argument was provided'); - return new HDPublicKey(arg); +/** + * Internal function to transform a {@link Script} into a `info` object. + * + * @param {Script} script - An instance of Script + * @returns {Object} An object with keys: hashBuffer, type + * @private + */ +Address._transformScript = function(script, network){ + var Script = require('./script'); + var info = {}; + if (!(script instanceof Script)) { + throw new TypeError('Address must be an instance of Script.'); + } + if (script.isScriptHashOut()) { + info.hashBuffer = script.getData(); + info.type = Address.PayToScriptHash; + } else if (script.isPublicKeyHashOut()) { + info.hashBuffer = script.getData(); + info.type = Address.PayToPublicKeyHash; + } else { + info.hashBuffer = Hash.sha256ripemd160(script.toBuffer()); + info.type = Address.PayToScriptHash; + } + info.network = Networks.get(network) || Networks.defaultNetwork; + return info; }; -HDPublicKey.fromString = function(arg) { - $.checkArgument(_.isString(arg), 'No valid string was provided'); - return new HDPublicKey(arg); +/** + * Creates a P2SH address from a set of public keys and a threshold. + * + * The addresses will be sorted lexicographically, as that is the trend in bitcoin. + * To create an address from unsorted public keys, use the {@link Script#buildMultisigOut} + * interface. + * + * @param {Array} publicKeys - a set of public keys to create an address + * @param {number} threshold - the number of signatures needed to release the funds + * @param {String|Network} network - either a Network instance, 'livenet', or 'testnet' + * @return {Address} + */ +Address.createMultisig = function(publicKeys, threshold, network) { + var Script = require('./script'); + network = network || publicKeys[0].network; + return new Address(Script.buildMultisigOut(publicKeys, threshold), network || Networks.defaultNetwork); }; /** - * Returns the base58 checked representation of the public key - * @return {string} a string starting with "xpub..." in livenet + * Internal function to transform a bitcoin address string + * + * @param {String} data + * @param {String|Network} [network] - either a Network instance, 'livenet', or 'testnet' + * @param {String} [type] - The type: 'pubkeyhash' or 'scripthash' + * @returns {Object} An object with keys: hashBuffer, network and type + * @private */ -HDPublicKey.prototype.toString = function () { - return this.xpubkey; +Address._transformString = function(data, network, type){ + if( typeof(data) !== 'string' ) { + throw new TypeError('Address supplied is not a string.'); + } + var addressBuffer = Base58Check.decode(data); + var info = Address._transformBuffer(addressBuffer, network, type); + return info; }; /** - * Returns the console representation of this extended public key. - * @return string + * Instantiate an address from a PublicKey instance + * + * @param {PublicKey} data + * @param {String|Network} network - either a Network instance, 'livenet', or 'testnet' + * @returns {Address} A new valid and frozen instance of an Address */ -HDPublicKey.prototype.inspect = function() { - return ''; +Address.fromPublicKey = function(data, network){ + var info = Address._transformPublicKey(data); + network = network || Networks.defaultNetwork; + return new Address(info.hashBuffer, network, info.type); }; /** - * Returns a plain javascript object with information to reconstruct a key. + * Instantiate an address from a ripemd160 public key hash * - * Fields are:
    - *
  • network: 'livenet' or 'testnet' - *
  • depth: a number from 0 to 255, the depth to the master extended key - *
  • fingerPrint: a number of 32 bits taken from the hash of the public key - *
  • fingerPrint: a number of 32 bits taken from the hash of this key's - *
  • parent's public key - *
  • childIndex: index with which this key was derived - *
  • chainCode: string in hexa encoding used for derivation - *
  • publicKey: string, hexa encoded, in compressed key format - *
  • checksum: BufferUtil.integerFromBuffer(this._buffers.checksum), - *
  • xpubkey: the string with the base58 representation of this extended key - *
  • checksum: the base58 checksum of xpubkey - *
+ * @param {Buffer} hash - An instance of buffer of the hash + * @param {String|Network} network - either a Network instance, 'livenet', or 'testnet' + * @returns {Address} A new valid and frozen instance of an Address */ -HDPublicKey.prototype.toObject = function toObject() { - return { - network: Network.get(BufferUtil.integerFromBuffer(this._buffers.version)).name, - depth: BufferUtil.integerFromSingleByteBuffer(this._buffers.depth), - fingerPrint: BufferUtil.integerFromBuffer(this.fingerPrint), - parentFingerPrint: BufferUtil.integerFromBuffer(this._buffers.parentFingerPrint), - childIndex: BufferUtil.integerFromBuffer(this._buffers.childIndex), - chainCode: BufferUtil.bufferToHex(this._buffers.chainCode), - publicKey: this.publicKey.toString(), - checksum: BufferUtil.integerFromBuffer(this._buffers.checksum), - xpubkey: this.xpubkey - }; +Address.fromPublicKeyHash = function(hash, network) { + var info = Address._transformHash(hash); + return new Address(info.hashBuffer, network, Address.PayToPublicKeyHash); }; /** - * Serializes this object into a JSON string - * @return {string} + * Instantiate an address from a ripemd160 script hash + * + * @param {Buffer} hash - An instance of buffer of the hash + * @param {String|Network} network - either a Network instance, 'livenet', or 'testnet' + * @returns {Address} A new valid and frozen instance of an Address */ -HDPublicKey.prototype.toJSON = function toJSON() { - return JSON.stringify(this.toObject()); +Address.fromScriptHash = function(hash, network) { + var info = Address._transformHash(hash); + return new Address(info.hashBuffer, network, Address.PayToScriptHash); }; /** - * Create a HDPublicKey from a buffer argument + * Instantiate an address from a Script * - * @param {Buffer} arg - * @return {HDPublicKey} + * @param {Script} script - An instance of Script + * @param {String|Network} network - either a Network instance, 'livenet', or 'testnet' + * @returns {Address} A new valid and frozen instance of an Address */ -HDPublicKey.fromBuffer = function(arg) { - return new HDPublicKey(arg); +Address.fromScript = function(script, network) { + var info = Address._transformScript(script, network); + return new Address(info.hashBuffer, network, info.type); }; /** - * Return a buffer representation of the xpubkey + * Instantiate an address from a buffer of the address * - * @return {Buffer} + * @param {Buffer} buffer - An instance of buffer of the address + * @param {String|Network} [network] - either a Network instance, 'livenet', or 'testnet' + * @param {String} [type] - The type of address: 'script' or 'pubkey' + * @returns {Address} A new valid and frozen instance of an Address */ -HDPublicKey.prototype.toBuffer = function() { - return BufferUtil.copy(this._buffers.xpubkey); +Address.fromBuffer = function(buffer, network, type) { + var info = Address._transformBuffer(buffer, network, type); + return new Address(info.hashBuffer, info.network, info.type); }; -HDPublicKey.Hardened = 0x80000000; -HDPublicKey.RootElementAlias = ['m', 'M']; - -HDPublicKey.VersionSize = 4; -HDPublicKey.DepthSize = 1; -HDPublicKey.ParentFingerPrintSize = 4; -HDPublicKey.ChildIndexSize = 4; -HDPublicKey.ChainCodeSize = 32; -HDPublicKey.PublicKeySize = 33; -HDPublicKey.CheckSumSize = 4; - -HDPublicKey.DataSize = 78; -HDPublicKey.SerializedByteSize = 82; - -HDPublicKey.VersionStart = 0; -HDPublicKey.VersionEnd = HDPublicKey.VersionStart + HDPublicKey.VersionSize; -HDPublicKey.DepthStart = HDPublicKey.VersionEnd; -HDPublicKey.DepthEnd = HDPublicKey.DepthStart + HDPublicKey.DepthSize; -HDPublicKey.ParentFingerPrintStart = HDPublicKey.DepthEnd; -HDPublicKey.ParentFingerPrintEnd = HDPublicKey.ParentFingerPrintStart + HDPublicKey.ParentFingerPrintSize; -HDPublicKey.ChildIndexStart = HDPublicKey.ParentFingerPrintEnd; -HDPublicKey.ChildIndexEnd = HDPublicKey.ChildIndexStart + HDPublicKey.ChildIndexSize; -HDPublicKey.ChainCodeStart = HDPublicKey.ChildIndexEnd; -HDPublicKey.ChainCodeEnd = HDPublicKey.ChainCodeStart + HDPublicKey.ChainCodeSize; -HDPublicKey.PublicKeyStart = HDPublicKey.ChainCodeEnd; -HDPublicKey.PublicKeyEnd = HDPublicKey.PublicKeyStart + HDPublicKey.PublicKeySize; -HDPublicKey.ChecksumStart = HDPublicKey.PublicKeyEnd; -HDPublicKey.ChecksumEnd = HDPublicKey.ChecksumStart + HDPublicKey.CheckSumSize; - -assert(HDPublicKey.PublicKeyEnd === HDPublicKey.DataSize); -assert(HDPublicKey.ChecksumEnd === HDPublicKey.SerializedByteSize); - -module.exports = HDPublicKey; - -}).call(this,require("buffer").Buffer) -},{"./crypto/bn":18,"./crypto/hash":20,"./crypto/point":21,"./encoding/base58":24,"./encoding/base58check":25,"./errors":29,"./hdkeycache":31,"./hdprivatekey":32,"./networks":34,"./publickey":37,"./util/buffer":53,"./util/js":54,"./util/preconditions":55,"assert":89,"buffer":104,"lodash":79}],34:[function(require,module,exports){ -'use strict'; -var _ = require('lodash'); - -var BufferUtil = require('./util/buffer'); -var networks = []; -var networkMaps = {}; - /** - * A network is merely a map containing values that correspond to version - * numbers for each bitcoin network. Currently only supporting "livenet" - * (a.k.a. "mainnet") and "testnet". - * @constructor + * Instantiate an address from an address string + * + * @param {String} str - An string of the bitcoin address + * @param {String|Network} [network] - either a Network instance, 'livenet', or 'testnet' + * @param {String} [type] - The type of address: 'script' or 'pubkey' + * @returns {Address} A new valid and frozen instance of an Address */ -function Network() {} - -Network.prototype.toString = function toString() { - return this.name; +Address.fromString = function(str, network, type) { + var info = Address._transformString(str, network, type); + return new Address(info.hashBuffer, info.network, info.type); }; /** - * @function - * @member Networks#get - * Retrieves the network associated with a magic number or string. - * @param {string|number|Network} arg - * @param {string} key - if set, only check if the magic number associated with this name matches - * @return Network + * Instantiate an address from JSON + * + * @param {String} json - An JSON string or Object with keys: hash, network and type + * @returns {Address} A new valid instance of an Address */ -function getNetwork(arg, key) { - if (~networks.indexOf(arg)) { - return arg; - } - if (key) { - for (var index in networks) { - if (networks[index][key] === arg) { - return networks[index]; - } - } - return undefined; +Address.fromJSON = function fromJSON(json) { + if (JSUtil.isValidJSON(json)) { + json = JSON.parse(json); } - return networkMaps[arg]; -} + $.checkState( + JSUtil.isHexa(json.hash), + 'Unexpected hash property, "' + json.hash + '", expected to be hex.' + ); + var hashBuffer = new Buffer(json.hash, 'hex'); + return new Address(hashBuffer, json.network, json.type); +}; /** - * @function - * @member Networks#add - * Will add a custom Network - * @param {Object} data - * @param {string} data.name - The name of the network - * @param {string} data.alias - The aliased name of the network - * @param {Number} data.pubkeyhash - The publickey hash prefix - * @param {Number} data.privatekey - The privatekey prefix - * @param {Number} data.scripthash - The scripthash prefix - * @param {Number} data.xpubkey - The extended public key magic - * @param {Number} data.xprivkey - The extended private key magic - * @param {Number} data.networkMagic - The network magic number - * @param {Number} data.port - The network port - * @param {Array} data.dnsSeeds - An array of dns seeds - * @return Network + * Will return a validation error if exists + * + * @example + * ```javascript + * // a network mismatch error + * var error = Address.getValidationError('15vkcKf7gB23wLAnZLmbVuMiiVDc1Nm4a2', 'testnet'); + * ``` + * + * @param {String} data - The encoded data + * @param {String|Network} network - either a Network instance, 'livenet', or 'testnet' + * @param {String} type - The type of address: 'script' or 'pubkey' + * @returns {null|Error} The corresponding error message */ -function addNetwork(data) { - - var network = new Network(); - - _.extend(network, { - name: data.name, - alias: data.alias, - pubkeyhash: data.pubkeyhash, - privatekey: data.privatekey, - scripthash: data.scripthash, - xpubkey: data.xpubkey, - xprivkey: data.xprivkey, - networkMagic: BufferUtil.integerAsBuffer(data.networkMagic), - port: data.port, - dnsSeeds: data.dnsSeeds - }); - - _.each(_.values(network), function(value) { - if (!_.isObject(value)) { - networkMaps[value] = network; - } - }); +Address.getValidationError = function(data, network, type) { + var error; + try { + /* jshint nonew: false */ + new Address(data, network, type); + } catch (e) { + error = e; + } + return error; +}; - networks.push(network); +/** + * Will return a boolean if an address is valid + * + * @example + * ```javascript + * assert(Address.isValid('15vkcKf7gB23wLAnZLmbVuMiiVDc1Nm4a2', 'livenet')); + * ``` + * + * @param {String} data - The encoded data + * @param {String|Network} network - either a Network instance, 'livenet', or 'testnet' + * @param {String} type - The type of address: 'script' or 'pubkey' + * @returns {boolean} The corresponding error message + */ +Address.isValid = function(data, network, type) { + return !Address.getValidationError(data, network, type); +}; - return network; +/** + * Returns true if an address is of pay to public key hash type + * @return boolean + */ +Address.prototype.isPayToPublicKeyHash = function() { + return this.type === Address.PayToPublicKeyHash; +}; -} +/** + * Returns true if an address is of pay to script hash type + * @return boolean + */ +Address.prototype.isPayToScriptHash = function() { + return this.type === Address.PayToScriptHash; +}; -addNetwork({ - name: 'livenet', - alias: 'mainnet', - pubkeyhash: 0x00, - privatekey: 0x80, - scripthash: 0x05, - xpubkey: 0x0488b21e, - xprivkey: 0x0488ade4, - networkMagic: 0xf9beb4d9, - port: 8333, - dnsSeeds: [ - 'seed.bitcoin.sipa.be', - 'dnsseed.bluematt.me', - 'dnsseed.bitcoin.dashjr.org', - 'seed.bitcoinstats.com', - 'seed.bitnodes.io', - 'bitseed.xf2.org' - ] -}); +/** + * Will return a buffer representation of the address + * + * @returns {Buffer} Bitcoin address buffer + */ +Address.prototype.toBuffer = function() { + var version = new Buffer([this.network[this.type]]); + var buf = Buffer.concat([version, this.hashBuffer]); + return buf; +}; -addNetwork({ - name: 'testnet', - alias: 'testnet', - pubkeyhash: 0x6f, - privatekey: 0xef, - scripthash: 0xc4, - xpubkey: 0x043587cf, - xprivkey: 0x04358394, - networkMagic: 0x0b110907, - port: 18333, - dnsSeeds: [ - 'testnet-seed.bitcoin.petertodd.org', - 'testnet-seed.bluematt.me', - 'testnet-seed.alexykot.me', - 'testnet-seed.bitcoin.schildbach.de' - ], -}); +/** + * @returns {Object} A plain object with the address information + */ +Address.prototype.toObject = function toObject() { + return { + hash: this.hashBuffer.toString('hex'), + type: this.type, + network: this.network.toString() + }; +}; /** -* @instance -* @member Networks#livenet -*/ -var livenet = getNetwork('livenet'); + * @returns {String} A JSON representation of a plain object with the address information + */ +Address.prototype.toJSON = function toJSON() { + return JSON.stringify(this.toObject()); +}; /** -* @instance -* @member Networks#testnet -*/ -var testnet = getNetwork('testnet'); + * Will return a the string representation of the address + * + * @returns {String} Bitcoin address + */ +Address.prototype.toString = function() { + return Base58Check.encode(this.toBuffer()); +}; /** - * @namespace Networks + * Will return a string formatted for the console + * + * @returns {String} Bitcoin address */ -module.exports = { - add: addNetwork, - defaultNetwork: livenet, - livenet: livenet, - mainnet: livenet, - testnet: testnet, - get: getNetwork +Address.prototype.inspect = function() { + return ''; }; -},{"./util/buffer":53,"lodash":79}],35:[function(require,module,exports){ +module.exports = Address; + +}).call(this,require("buffer").Buffer) +},{"./crypto/hash":36,"./encoding/base58check":41,"./networks":50,"./publickey":53,"./script":54,"./util/js":70,"./util/preconditions":71,"buffer":209,"lodash":95}],32:[function(require,module,exports){ (function (Buffer){ 'use strict'; var _ = require('lodash'); -var $ = require('./util/preconditions'); +var BlockHeader = require('./blockheader'); +var BN = require('./crypto/bn'); var BufferUtil = require('./util/buffer'); +var BufferReader = require('./encoding/bufferreader'); +var BufferWriter = require('./encoding/bufferwriter'); +var Hash = require('./crypto/hash'); var JSUtil = require('./util/js'); +var Transaction = require('./transaction'); +var $ = require('./util/preconditions'); -function Opcode(num) { - if (!(this instanceof Opcode)) { - return new Opcode(num); +/** + * Instantiate a Block from a Buffer, JSON object, or Object with + * the properties of the Block + * + * @param {*} - A Buffer, JSON string, or Object + * @returns {Block} + * @constructor + */ +function Block(arg) { + if (!(this instanceof Block)) { + return new Block(arg); } + _.extend(this, Block._from(arg)); + return this; +} - var value; +// https://github.com/bitcoin/bitcoin/blob/b5fa132329f0377d787a4a21c1686609c2bfaece/src/primitives/block.h#L14 +Block.MAX_BLOCK_SIZE = 1000000; - if (_.isNumber(num)) { - value = num; - } else if (_.isString(num)) { - value = Opcode.map[num]; +/** + * @param {*} - A Buffer, JSON string or Object + * @returns {Object} - An object representing block data + * @throws {TypeError} - If the argument was not recognized + * @private + */ +Block._from = function _from(arg) { + var info = {}; + if (BufferUtil.isBuffer(arg)) { + info = Block._fromBufferReader(BufferReader(arg)); + } else if (JSUtil.isValidJSON(arg)) { + info = Block._fromJSON(arg); + } else if (_.isObject(arg)) { + info = { + /** + * @name Block#header + * @type {BlockHeader} + */ + header: arg.header, + /** + * @name Block#transactions + * @type {Transaction[]} + */ + transactions: arg.transactions + }; } else { - throw new TypeError('Unrecognized num type: "' + typeof(num) + '" for Opcode'); + throw new TypeError('Unrecognized argument for Block'); } + return info; +}; - JSUtil.defineImmutable(this, { - num: value +/** + * @param {String|Object} - A JSON string or object + * @returns {Object} - An object representing block data + * @private + */ +Block._fromJSON = function _fromJSON(data) { + if (JSUtil.isValidJSON(data)) { + data = JSON.parse(data); + } + var transactions = []; + data.transactions.forEach(function(data) { + transactions.push(Transaction().fromJSON(data)); }); - - return this; -} - -Opcode.fromBuffer = function(buf) { - $.checkArgument(BufferUtil.isBuffer(buf)); - return new Opcode(Number('0x' + buf.toString('hex'))); + var info = { + header: BlockHeader.fromJSON(data.header), + transactions: transactions + }; + return info; }; -Opcode.fromNumber = function(num) { - $.checkArgument(_.isNumber(num)); - return new Opcode(num); +/** + * @param {String|Object} - A JSON string or object + * @returns {Block} - An instance of block + */ +Block.fromJSON = function fromJSON(json) { + var info = Block._fromJSON(json); + return new Block(info); }; -Opcode.fromString = function(str) { - $.checkArgument(_.isString(str)); - var value = Opcode.map[str]; - if (typeof value === 'undefined') { - throw new TypeError('Invalid opcodestr'); +/** + * @param {BufferReader} - Block data + * @returns {Object} - An object representing the block data + * @private + */ +Block._fromBufferReader = function _fromBufferReader(br) { + var info = {}; + $.checkState(!br.finished(), 'No block data received'); + info.header = BlockHeader.fromBufferReader(br); + var transactions = br.readVarintNum(); + info.transactions = []; + for (var i = 0; i < transactions; i++) { + info.transactions.push(Transaction().fromBufferReader(br)); } - return new Opcode(value); + return info; }; -Opcode.prototype.toHex = function() { - return this.num.toString(16); +/** + * @param {BufferReader} - A buffer reader of the block + * @returns {Block} - An instance of block + */ +Block.fromBufferReader = function fromBufferReader(br) { + var info = Block._fromBufferReader(br); + return new Block(info); }; -Opcode.prototype.toBuffer = function() { - return new Buffer(this.toHex(), 'hex'); +/** + * @param {Buffer} - A buffer of the block + * @returns {Block} - An instance of block + */ +Block.fromBuffer = function fromBuffer(buf) { + return Block.fromBufferReader(BufferReader(buf)); }; -Opcode.prototype.toNumber = function() { - return this.num; +/** + * @param {String} - str - A hex encoded string of the block + * @returns {Block} - A hex encoded string of the block + */ +Block.fromString = function fromString(str) { + var buf = new Buffer(str, 'hex'); + return Block.fromBuffer(buf); }; -Opcode.prototype.toString = function() { - var str = Opcode.reverseMap[this.num]; - if (typeof str === 'undefined') { - throw new Error('Opcode does not have a string representation'); +/** + * @param {Binary} - Raw block binary data or buffer + * @returns {Block} - An instance of block + */ +Block.fromRawBlock = function fromRawBlock(data) { + if (!BufferUtil.isBuffer(data)) { + data = new Buffer(data, 'binary'); } - return str; + var br = BufferReader(data); + br.pos = Block.Values.START_OF_BLOCK; + var info = Block._fromBufferReader(br); + return new Block(info); }; -Opcode.smallInt = function(n) { - $.checkArgument(n >= 0 && n <= 16, 'Invalid Argument: n must be between 0 and 16'); - if (n === 0) { - return Opcode('OP_0'); - } - return new Opcode(Opcode.map.OP_1 + n - 1); +/** + * @returns {Object} - A plain object with the block properties + */ +Block.prototype.toObject = function toObject() { + var transactions = []; + this.transactions.forEach(function(tx) { + transactions.push(tx.toObject()); + }); + return { + header: this.header.toObject(), + transactions: transactions + }; }; -Opcode.map = { - // push value - OP_FALSE: 0, - OP_0: 0, - OP_PUSHDATA1: 76, - OP_PUSHDATA2: 77, - OP_PUSHDATA4: 78, - OP_1NEGATE: 79, - OP_RESERVED: 80, - OP_TRUE: 81, - OP_1: 81, - OP_2: 82, - OP_3: 83, - OP_4: 84, - OP_5: 85, - OP_6: 86, - OP_7: 87, - OP_8: 88, - OP_9: 89, - OP_10: 90, - OP_11: 91, - OP_12: 92, - OP_13: 93, - OP_14: 94, - OP_15: 95, - OP_16: 96, - - // control - OP_NOP: 97, - OP_VER: 98, - OP_IF: 99, - OP_NOTIF: 100, - OP_VERIF: 101, - OP_VERNOTIF: 102, - OP_ELSE: 103, - OP_ENDIF: 104, - OP_VERIFY: 105, - OP_RETURN: 106, - - // stack ops - OP_TOALTSTACK: 107, - OP_FROMALTSTACK: 108, - OP_2DROP: 109, - OP_2DUP: 110, - OP_3DUP: 111, - OP_2OVER: 112, - OP_2ROT: 113, - OP_2SWAP: 114, - OP_IFDUP: 115, - OP_DEPTH: 116, - OP_DROP: 117, - OP_DUP: 118, - OP_NIP: 119, - OP_OVER: 120, - OP_PICK: 121, - OP_ROLL: 122, - OP_ROT: 123, - OP_SWAP: 124, - OP_TUCK: 125, - - // splice ops - OP_CAT: 126, - OP_SUBSTR: 127, - OP_LEFT: 128, - OP_RIGHT: 129, - OP_SIZE: 130, - - // bit logic - OP_INVERT: 131, - OP_AND: 132, - OP_OR: 133, - OP_XOR: 134, - OP_EQUAL: 135, - OP_EQUALVERIFY: 136, - OP_RESERVED1: 137, - OP_RESERVED2: 138, - - // numeric - OP_1ADD: 139, - OP_1SUB: 140, - OP_2MUL: 141, - OP_2DIV: 142, - OP_NEGATE: 143, - OP_ABS: 144, - OP_NOT: 145, - OP_0NOTEQUAL: 146, - - OP_ADD: 147, - OP_SUB: 148, - OP_MUL: 149, - OP_DIV: 150, - OP_MOD: 151, - OP_LSHIFT: 152, - OP_RSHIFT: 153, - - OP_BOOLAND: 154, - OP_BOOLOR: 155, - OP_NUMEQUAL: 156, - OP_NUMEQUALVERIFY: 157, - OP_NUMNOTEQUAL: 158, - OP_LESSTHAN: 159, - OP_GREATERTHAN: 160, - OP_LESSTHANOREQUAL: 161, - OP_GREATERTHANOREQUAL: 162, - OP_MIN: 163, - OP_MAX: 164, - - OP_WITHIN: 165, - - // crypto - OP_RIPEMD160: 166, - OP_SHA1: 167, - OP_SHA256: 168, - OP_HASH160: 169, - OP_HASH256: 170, - OP_CODESEPARATOR: 171, - OP_CHECKSIG: 172, - OP_CHECKSIGVERIFY: 173, - OP_CHECKMULTISIG: 174, - OP_CHECKMULTISIGVERIFY: 175, - - // expansion - OP_NOP1: 176, - OP_NOP2: 177, - OP_NOP3: 178, - OP_NOP4: 179, - OP_NOP5: 180, - OP_NOP6: 181, - OP_NOP7: 182, - OP_NOP8: 183, - OP_NOP9: 184, - OP_NOP10: 185, - - // template matching params - OP_PUBKEYHASH: 253, - OP_PUBKEY: 254, - OP_INVALIDOPCODE: 255 +/** + * @returns {String} - A JSON string + */ +Block.prototype.toJSON = function toJSON() { + return JSON.stringify(this.toObject()); }; -Opcode.reverseMap = []; - -for (var k in Opcode.map) { - Opcode.reverseMap[Opcode.map[k]] = k; -} - -// Easier access to opcodes -_.extend(Opcode, Opcode.map); - /** - * @returns true if opcode is one of OP_0, OP_1, ..., OP_16 + * @returns {Buffer} - A buffer of the block */ -Opcode.isSmallIntOp = function(opcode) { - if (opcode instanceof Opcode) { - opcode = opcode.toNumber(); - } - return ((opcode === Opcode.map.OP_0) || - ((opcode >= Opcode.map.OP_1) && (opcode <= Opcode.map.OP_16))); +Block.prototype.toBuffer = function toBuffer() { + return this.toBufferWriter().concat(); }; /** - * Will return a string formatted for the console - * - * @returns {string} Script opcode + * @returns {String} - A hex encoded string of the block */ -Opcode.prototype.inspect = function() { - return ''; +Block.prototype.toString = function toString() { + return this.toBuffer().toString('hex'); }; -module.exports = Opcode; - -}).call(this,require("buffer").Buffer) -},{"./util/buffer":53,"./util/js":54,"./util/preconditions":55,"buffer":104,"lodash":79}],36:[function(require,module,exports){ -(function (Buffer){ -'use strict'; - -var _ = require('lodash'); -var Address = require('./address'); -var Base58Check = require('./encoding/base58check'); -var BN = require('./crypto/bn'); -var JSUtil = require('./util/js'); -var Networks = require('./networks'); -var Point = require('./crypto/point'); -var PublicKey = require('./publickey'); -var Random = require('./crypto/random'); - /** - * Instantiate a PrivateKey from a BN, Buffer and WIF. - * - * @example - * ```javascript - * // generate a new random key - * var key = PrivateKey(); - * - * // get the associated address - * var address = key.toAddress(); - * - * // encode into wallet export format - * var exported = key.toWIF(); - * - * // instantiate from the exported (and saved) private key - * var imported = PrivateKey.fromWIF(exported); - * ``` - * - * @param {string} data - The encoded data in various formats - * @param {Network|string=} network - a {@link Network} object, or a string with the network name - * @returns {PrivateKey} A new valid instance of an PrivateKey - * @constructor + * @param {BufferWriter} - An existing instance of BufferWriter + * @returns {BufferWriter} - An instance of BufferWriter representation of the Block */ -var PrivateKey = function PrivateKey(data, network) { - /* jshint maxstatements: 20 */ - /* jshint maxcomplexity: 8 */ - - if (!(this instanceof PrivateKey)) { - return new PrivateKey(data, network); +Block.prototype.toBufferWriter = function toBufferWriter(bw) { + if (!bw) { + bw = new BufferWriter(); } - if (data instanceof PrivateKey) { - return data; + bw.write(this.header.toBuffer()); + bw.writeVarintNum(this.transactions.length); + for (var i = 0; i < this.transactions.length; i++) { + this.transactions[i].toBufferWriter(bw); } + return bw; +}; - var info = this._classifyArguments(data, network); - - // validation - if (!info.bn || info.bn.cmp(new BN(0)) === 0){ - throw new TypeError('Number can not be equal to zero, undefined, null or false'); - } - if (!info.bn.lt(Point.getN())) { - throw new TypeError('Number must be less than N'); +/** + * Will iterate through each transaction and return an array of hashes + * @returns {Array} - An array with transaction hashes + */ +Block.prototype.getTransactionHashes = function getTransactionHashes() { + var hashes = []; + if (this.transactions.length === 0) { + return [Block.Values.NULL_HASH]; } - if (typeof(info.network) === 'undefined') { - throw new TypeError('Must specify the network ("livenet" or "testnet")'); + for (var t = 0; t < this.transactions.length; t++) { + hashes.push(this.transactions[t]._getHash()); } - - JSUtil.defineImmutable(this, { - bn: info.bn, - compressed: info.compressed, - network: info.network - }); - - Object.defineProperty(this, 'publicKey', { - configurable: false, - enumerable: true, - get: this.toPublicKey.bind(this) - }); - - return this; - + return hashes; }; /** - * Internal helper to instantiate PrivateKey internal `info` object from - * different kinds of arguments passed to the constructor. - * - * @param {*} data - * @param {Network|string=} network - a {@link Network} object, or a string with the network name - * @return {Object} + * Will build a merkle tree of all the transactions, ultimately arriving at + * a single point, the merkle root. + * @link https://en.bitcoin.it/wiki/Protocol_specification#Merkle_Trees + * @returns {Array} - An array with each level of the tree after the other. */ -PrivateKey.prototype._classifyArguments = function(data, network) { - /* jshint maxcomplexity: 10 */ - var info = { - compressed: true, - network: network ? Networks.get(network) : Networks.defaultNetwork - }; +Block.prototype.getMerkleTree = function getMerkleTree() { - // detect type of data - if (_.isUndefined(data) || _.isNull(data)){ - info.bn = PrivateKey._getRandomBN(); - } else if (data instanceof BN) { - info.bn = data; - } else if (data instanceof Buffer || data instanceof Uint8Array) { - info = PrivateKey._transformBuffer(data, network); - } else if (PrivateKey._isJSON(data)){ - info = PrivateKey._transformJSON(data); - } else if (!network && Networks.get(data)) { - info.bn = PrivateKey._getRandomBN(); - info.network = Networks.get(data); - } else if (typeof(data) === 'string'){ - if (JSUtil.isHexa(data)) { - info.bn = new BN(new Buffer(data, 'hex')); - } else { - info = PrivateKey._transformWIF(data, network); + var tree = this.getTransactionHashes(); + + var j = 0; + for (var size = this.transactions.length; size > 1; size = Math.floor((size + 1) / 2)) { + for (var i = 0; i < size; i += 2) { + var i2 = Math.min(i + 1, size - 1); + var buf = Buffer.concat([tree[j + i], tree[j + i2]]); + tree.push(Hash.sha256sha256(buf)); } - } else { - throw new TypeError('First argument is an unrecognized data type.'); + j += size; } - return info; -}; -/** - * Internal function to get a random Big Number (BN) - * - * @returns {BN} A new randomly generated BN - * @private - */ -PrivateKey._getRandomBN = function(){ - var condition; - var bn; - do { - var privbuf = Random.getRandomBuffer(32); - bn = BN.fromBuffer(privbuf); - condition = bn.lt(Point.getN()); - } while (!condition); - return bn; + return tree; }; /** - * Internal function to detect if a param is a JSON string or plain object - * - * @param {*} param - value to test - * @returns {boolean} - * @private + * Calculates the merkleRoot from the transactions. + * @returns {Buffer} - A buffer of the merkle root hash */ -PrivateKey._isJSON = function(json) { - return JSUtil.isValidJSON(json) || (json.bn && json.network); +Block.prototype.getMerkleRoot = function getMerkleRoot() { + var tree = this.getMerkleTree(); + return tree[tree.length - 1]; }; /** - * Internal function to transform a WIF Buffer into a private key - * - * @param {Buffer} buf - An WIF string - * @param {Network|string=} network - a {@link Network} object, or a string with the network name - * @returns {Object} An object with keys: bn, network and compressed - * @private + * Verifies that the transactions in the block match the header merkle root + * @returns {Boolean} - If the merkle roots match */ -PrivateKey._transformBuffer = function(buf, network) { +Block.prototype.validMerkleRoot = function validMerkleRoot() { - var info = {}; + var h = new BN(this.header.merkleRoot.toString('hex'), 'hex'); + var c = new BN(this.getMerkleRoot().toString('hex'), 'hex'); - if (buf.length === 32) { - return PrivateKey._transformBNBuffer(buf, network); + if (h.cmp(c) !== 0) { + return false; } - info.network = Networks.get(buf[0], 'privatekey'); - if (buf[0] === Networks.livenet.privatekey) { - info.network = Networks.livenet; - } else if (buf[0] === Networks.testnet.privatekey) { - info.network = Networks.testnet; - } else { - throw new Error('Invalid network'); - } + return true; +}; - if (network && info.network !== Networks.get(network)) { - throw new TypeError('Private key network mismatch'); - } +/** + * @returns {Buffer} - The little endian hash buffer of the header + */ +Block.prototype._getHash = function() { + return this.header._getHash(); +}; - if (buf.length === 1 + 32 + 1 && buf[1 + 32 + 1 - 1] === 1) { - info.compressed = true; - } else if (buf.length === 1 + 32) { - info.compressed = false; - } else { - throw new Error('Length of buffer must be 33 (uncompressed) or 34 (compressed)'); - } +var idProperty = { + configurable: false, + writeable: false, + /** + * @returns {string} - The big endian hash buffer of the header + */ + get: function() { + if (!this._id) { + this._id = this.header.id; + } + return this._id; + }, + set: _.noop +}; +Object.defineProperty(Block.prototype, 'id', idProperty); +Object.defineProperty(Block.prototype, 'hash', idProperty); - info.bn = BN.fromBuffer(buf.slice(1, 32 + 1)); +/** + * @returns {String} - A string formated for the console + */ +Block.prototype.inspect = function inspect() { + return ''; +}; - return info; +Block.Values = { + START_OF_BLOCK: 8, // Start of block in raw block data + NULL_HASH: new Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex') }; +module.exports = Block; + +}).call(this,require("buffer").Buffer) +},{"./blockheader":33,"./crypto/bn":34,"./crypto/hash":36,"./encoding/bufferreader":42,"./encoding/bufferwriter":43,"./transaction":57,"./util/buffer":69,"./util/js":70,"./util/preconditions":71,"buffer":209,"lodash":95}],33:[function(require,module,exports){ +(function (Buffer){ +'use strict'; + +var _ = require('lodash'); +var BN = require('./crypto/bn'); +var BufferUtil = require('./util/buffer'); +var BufferReader = require('./encoding/bufferreader'); +var BufferWriter = require('./encoding/bufferwriter'); +var Hash = require('./crypto/hash'); +var JSUtil = require('./util/js'); + /** - * Internal function to transform a BN buffer into a private key + * Instantiate a BlockHeader from a Buffer, JSON object, or Object with + * the properties of the BlockHeader * - * @param {Buffer} buf - * @param {Network|string=} network - a {@link Network} object, or a string with the network name - * @returns {object} an Object with keys: bn, network, and compressed - * @private + * @param {*} - A Buffer, JSON string, or Object + * @returns {BlockHeader} - An instance of block header + * @constructor */ -PrivateKey._transformBNBuffer = function(buf, network) { - var info = {}; - info.network = Networks.get(network) || Networks.defaultNetwork; - info.bn = BN.fromBuffer(buf); - info.compressed = false; - return info; +var BlockHeader = function BlockHeader(arg) { + if (!(this instanceof BlockHeader)) { + return new BlockHeader(arg); + } + _.extend(this, BlockHeader._from(arg)); + return this; }; /** - * Internal function to transform a WIF string into a private key - * - * @param {string} buf - An WIF string - * @returns {Object} An object with keys: bn, network and compressed + * @param {*} - A Buffer, JSON string or Object + * @returns {Object} - An object representing block header data + * @throws {TypeError} - If the argument was not recognized * @private */ -PrivateKey._transformWIF = function(str, network) { - return PrivateKey._transformBuffer(Base58Check.decode(str), network); +BlockHeader._from = function _from(arg) { + var info = {}; + if (BufferUtil.isBuffer(arg)) { + info = BlockHeader._fromBufferReader(BufferReader(arg)); + } else if (JSUtil.isValidJSON(arg)) { + info = BlockHeader._fromJSON(arg); + } else if (_.isObject(arg)) { + info = { + version: arg.version, + prevHash: arg.prevHash, + merkleRoot: arg.merkleRoot, + time: arg.time, + bits: arg.bits, + nonce: arg.nonce + }; + } else { + throw new TypeError('Unrecognized argument for BlockHeader'); + } + return info; }; /** - * Instantiate a PrivateKey from a JSON string - * - * @param {string} json - The JSON encoded private key string - * @returns {PrivateKey} A new valid instance of PrivateKey + * @param {String|Object} - A JSON string or object + * @returns {Object} - An object representing block header data + * @private */ -PrivateKey.fromJSON = function(json) { - if (!PrivateKey._isJSON(json)) { - throw new TypeError('Must be a valid JSON string or plain object'); +BlockHeader._fromJSON = function _fromJSON(data) { + if (JSUtil.isValidJSON(data)) { + data = JSON.parse(data); } - - return new PrivateKey(json); + var info = { + version: data.version, + prevHash: new Buffer(data.prevHash, 'hex'), + merkleRoot: new Buffer(data.merkleRoot, 'hex'), + time: data.time, + timestamp: data.time, + bits: data.bits, + nonce: data.nonce + }; + return info; }; /** - * Instantiate a PrivateKey from a Buffer with the DER or WIF representation - * - * @param {Buffer} arg - * @param {Network} network - * @return {PrivateKey} + * @param {String|Object} - A JSON string or object + * @returns {BlockHeader} - An instance of block header */ -PrivateKey.fromBuffer = function(arg, network) { - return new PrivateKey(arg, network); +BlockHeader.fromJSON = function fromJSON(json) { + var info = BlockHeader._fromJSON(json); + return new BlockHeader(info); }; /** - * Internal function to transform a JSON string on plain object into a private key - * return this. - * - * @param {string} json - A JSON string or plain object - * @returns {Object} An object with keys: bn, network and compressed - * @private + * @param {Binary} - Raw block binary data or buffer + * @returns {BlockHeader} - An instance of block header */ -PrivateKey._transformJSON = function(json) { - if (JSUtil.isValidJSON(json)) { - json = JSON.parse(json); +BlockHeader.fromRawBlock = function fromRawBlock(data) { + if (!BufferUtil.isBuffer(data)) { + data = new Buffer(data, 'binary'); } - var bn = new BN(json.bn, 'hex'); - return { - bn: bn, - network: json.network, - compressed: json.compressed - }; + var br = BufferReader(data); + br.pos = BlockHeader.Constants.START_OF_HEADER; + var info = BlockHeader._fromBufferReader(br); + return new BlockHeader(info); }; /** - * Instantiate a PrivateKey from a WIF string - * - * @param {string} str - The WIF encoded private key string - * @returns {PrivateKey} A new valid instance of PrivateKey + * @param {Buffer} - A buffer of the block header + * @returns {BlockHeader} - An instance of block header */ -PrivateKey.fromString = PrivateKey.fromWIF = function(str) { - return new PrivateKey(str); +BlockHeader.fromBuffer = function fromBuffer(buf) { + var info = BlockHeader._fromBufferReader(BufferReader(buf)); + return new BlockHeader(info); }; /** - * Instantiate a PrivateKey from random bytes - * - * @param {string=} network - Either "livenet" or "testnet" - * @returns {PrivateKey} A new valid instance of PrivateKey + * @param {String} - A hex encoded buffer of the block header + * @returns {BlockHeader} - An instance of block header */ -PrivateKey.fromRandom = function(network) { - var bn = PrivateKey._getRandomBN(); - return new PrivateKey(bn, network); +BlockHeader.fromString = function fromString(str) { + var buf = new Buffer(str, 'hex'); + return BlockHeader.fromBuffer(buf); }; /** - * Check if there would be any errors when initializing a PrivateKey - * - * @param {string} data - The encoded data in various formats - * @param {string=} network - Either "livenet" or "testnet" - * @returns {null|Error} An error if exists + * @param {BufferReader} - A BufferReader of the block header + * @returns {Object} - An object representing block header data + * @private */ - -PrivateKey.getValidationError = function(data, network) { - var error; - try { - /* jshint nonew: false */ - new PrivateKey(data, network); - } catch (e) { - error = e; - } - return error; +BlockHeader._fromBufferReader = function _fromBufferReader(br) { + var info = {}; + info.version = br.readUInt32LE(); + info.prevHash = br.read(32); + info.merkleRoot = br.read(32); + info.time = br.readUInt32LE(); + info.bits = br.readUInt32LE(); + info.nonce = br.readUInt32LE(); + return info; }; /** - * Check if the parameters are valid - * - * @param {string} data - The encoded data in various formats - * @param {string=} network - Either "livenet" or "testnet" - * @returns {Boolean} If the private key is would be valid + * @param {BufferReader} - A BufferReader of the block header + * @returns {BlockHeader} - An instance of block header */ -PrivateKey.isValid = function(data, network){ - if (!data) { - return false; - } - return !PrivateKey.getValidationError(data, network); +BlockHeader.fromBufferReader = function fromBufferReader(br) { + var info = BlockHeader._fromBufferReader(br); + return new BlockHeader(info); }; /** - * Will output the PrivateKey encoded as hex string - * - * @returns {string} + * @returns {Object} - A plain object of the BlockHeader */ -PrivateKey.prototype.toString = function() { - return this.toBuffer().toString('hex'); +BlockHeader.prototype.toObject = function toObject() { + return { + version: this.version, + prevHash: this.prevHash.toString('hex'), + merkleRoot: this.merkleRoot.toString('hex'), + time: this.time, + bits: this.bits, + nonce: this.nonce + }; }; /** - * Will output the PrivateKey to a WIF string - * - * @returns {string} A WIP representation of the private key + * @returns {String} - A JSON string */ -PrivateKey.prototype.toWIF = function() { - var network = this.network; - var compressed = this.compressed; - - var buf; - if (compressed) { - buf = Buffer.concat([new Buffer([network.privatekey]), - this.bn.toBuffer({size: 32}), - new Buffer([0x01])]); - } else { - buf = Buffer.concat([new Buffer([network.privatekey]), - this.bn.toBuffer({size: 32})]); - } - - return Base58Check.encode(buf); +BlockHeader.prototype.toJSON = function toJSON() { + return JSON.stringify(this.toObject()); }; /** - * Will return the private key as a BN instance - * - * @returns {BN} A BN instance of the private key + * @returns {Buffer} - A Buffer of the BlockHeader */ -PrivateKey.prototype.toBigNumber = function(){ - return this.bn; +BlockHeader.prototype.toBuffer = function toBuffer() { + return this.toBufferWriter().concat(); }; /** - * Will return the private key as a BN buffer - * - * @returns {Buffer} A buffer of the private key + * @returns {String} - A hex encoded string of the BlockHeader */ -PrivateKey.prototype.toBuffer = function(){ - return this.bn.toBuffer(); +BlockHeader.prototype.toString = function toString() { + return this.toBuffer().toString('hex'); }; /** - * Will return the corresponding public key - * - * @returns {PublicKey} A public key generated from the private key + * @param {BufferWriter} - An existing instance BufferWriter + * @returns {BufferWriter} - An instance of BufferWriter representation of the BlockHeader */ -PrivateKey.prototype.toPublicKey = function(){ - if (!this._pubkey) { - this._pubkey = PublicKey.fromPrivateKey(this); +BlockHeader.prototype.toBufferWriter = function toBufferWriter(bw) { + if (!bw) { + bw = new BufferWriter(); } - return this._pubkey; + bw.writeUInt32LE(this.version); + bw.write(this.prevHash); + bw.write(this.merkleRoot); + bw.writeUInt32LE(this.time); + bw.writeUInt32LE(this.bits); + bw.writeUInt32LE(this.nonce); + return bw; }; /** - * Will return an address for the private key - * @param {Network=} network - optional parameter specifying - * the desired network for the address - * - * @returns {Address} An address generated from the private key + * @link https://en.bitcoin.it/wiki/Difficulty + * @returns {BN} - An instance of BN with the decoded difficulty bits */ -PrivateKey.prototype.toAddress = function(network) { - var pubkey = this.toPublicKey(); - return Address.fromPublicKey(pubkey, network || this.network); +BlockHeader.prototype.getTargetDifficulty = function getTargetDifficulty(info) { + var target = new BN(this.bits & 0xffffff); + var mov = 8 * ((this.bits >>> 24) - 3); + while (mov-- > 0) { + target = target.mul(new BN(2)); + } + return target; }; /** - * @returns {Object} A plain object representation + * @returns {Buffer} - The little endian hash buffer of the header */ -PrivateKey.prototype.toObject = function toObject() { - return { - bn: this.bn.toString('hex'), - compressed: this.compressed, - network: this.network.toString() - }; +BlockHeader.prototype._getHash = function hash() { + var buf = this.toBuffer(); + return Hash.sha256sha256(buf); }; -PrivateKey.prototype.toJSON = function toJSON() { - return JSON.stringify(this.toObject()); +var idProperty = { + configurable: false, + writeable: false, + enumerable: true, + /** + * @returns {string} - The big endian hash buffer of the header + */ + get: function() { + if (!this._id) { + this._id = BufferReader(this._getHash()).readReverse().toString('hex'); + } + return this._id; + }, + set: _.noop }; +Object.defineProperty(BlockHeader.prototype, 'id', idProperty); +Object.defineProperty(BlockHeader.prototype, 'hash', idProperty); /** - * Will return a string formatted for the console - * - * @returns {string} Private key + * @returns {Boolean} - If timestamp is not too far in the future */ -PrivateKey.prototype.inspect = function() { - var uncompressed = !this.compressed ? ', uncompressed' : ''; - return ''; +BlockHeader.prototype.validTimestamp = function validTimestamp() { + var currentTime = Math.round(new Date().getTime() / 1000); + if (this.time > currentTime + BlockHeader.Constants.MAX_TIME_OFFSET) { + return false; + } + return true; }; -module.exports = PrivateKey; - -}).call(this,require("buffer").Buffer) -},{"./address":13,"./crypto/bn":18,"./crypto/point":21,"./crypto/random":22,"./encoding/base58check":25,"./networks":34,"./publickey":37,"./util/js":54,"buffer":104,"lodash":79}],37:[function(require,module,exports){ -(function (Buffer){ -'use strict'; +/** + * @returns {Boolean} - If the proof-of-work hash satisfies the target difficulty + */ +BlockHeader.prototype.validProofOfWork = function validProofOfWork() { + var pow = new BN(this.id, 'hex'); + var target = this.getTargetDifficulty(); -var Address = require('./address'); -var BN = require('./crypto/bn'); -var Point = require('./crypto/point'); -var Hash = require('./crypto/hash'); -var JSUtil = require('./util/js'); -var Network = require('./networks'); -var _ = require('lodash'); -var $ = require('./util/preconditions'); + if (pow.cmp(target) > 0) { + return false; + } + return true; +}; /** - * Instantiate a PublicKey from a {@link PrivateKey}, {@link Point}, `string`, or `Buffer`. - * - * There are two internal properties, `network` and `compressed`, that deal with importing - * a PublicKey from a PrivateKey in WIF format. More details described on {@link PrivateKey} - * - * @example - * ```javascript - * // instantiate from a private key - * var key = PublicKey(privateKey, true); - * - * // export to as a DER hex encoded string - * var exported = key.toString(); - * - * // import the public key - * var imported = PublicKey.fromString(exported); - * ``` - * - * @param {string} data - The encoded data in various formats - * @param {Object} extra - additional options - * @param {Network=} extra.network - Which network should the address for this public key be for - * @param {String=} extra.compressed - If the public key is compressed - * @returns {PublicKey} A new valid instance of an PublicKey - * @constructor + * @returns {String} - A string formated for the console */ -var PublicKey = function PublicKey(data, extra) { +BlockHeader.prototype.inspect = function inspect() { + return ''; +}; - if (!(this instanceof PublicKey)) { - return new PublicKey(data, extra); - } +BlockHeader.Constants = { + START_OF_HEADER: 8, // Start buffer position in raw block data + MAX_TIME_OFFSET: 2 * 60 * 60, // The max a timestamp can be in the future + LARGEST_HASH: new BN('10000000000000000000000000000000000000000000000000000000000000000', 'hex') +}; - $.checkArgument(data, new TypeError('First argument is required, please include public key data.')); +module.exports = BlockHeader; - if (data instanceof PublicKey) { - // Return copy, but as it's an immutable object, return same argument - return data; +}).call(this,require("buffer").Buffer) +},{"./crypto/bn":34,"./crypto/hash":36,"./encoding/bufferreader":42,"./encoding/bufferwriter":43,"./util/buffer":69,"./util/js":70,"buffer":209,"lodash":95}],34:[function(require,module,exports){ +(function (Buffer){ +'use strict'; + +var BN = require('bn.js'); +var $ = require('../util/preconditions'); +var _ = require('lodash'); + +var reversebuf = function(buf) { + var buf2 = new Buffer(buf.length); + for (var i = 0; i < buf.length; i++) { + buf2[i] = buf[buf.length - 1 - i]; } - extra = extra || {}; + return buf2; +}; - var info = this._classifyArgs(data, extra); +BN.Zero = new BN(0); +BN.One = new BN(1); +BN.Minus1 = new BN(-1); - // validation - info.point.validate(); +BN.fromNumber = function(n) { + $.checkArgument(_.isNumber(n)); + return new BN(n); +}; - JSUtil.defineImmutable(this, { - point: info.point, - compressed: info.compressed, - network: info.network || Network.defaultNetwork - }); +BN.fromString = function(str) { + $.checkArgument(_.isString(str)); + return new BN(str); +}; - return this; +BN.fromBuffer = function(buf, opts) { + if (typeof opts !== 'undefined' && opts.endian === 'little') { + buf = reversebuf(buf); + } + var hex = buf.toString('hex'); + var bn = new BN(hex, 16); + return bn; }; /** - * Internal function to differentiate between arguments passed to the constructor - * @param {*} data - * @param {Object} extra + * Instantiate a BigNumber from a "signed magnitude buffer" + * (a buffer where the most significant bit represents the sign (0 = positive, -1 = negative)) */ -PublicKey.prototype._classifyArgs = function(data, extra) { - /* jshint maxcomplexity: 10 */ - var info = { - compressed: _.isUndefined(extra.compressed) || extra.compressed - }; +BN.fromSM = function(buf, opts) { + var ret; + if (buf.length === 0) { + return BN.fromBuffer(new Buffer([0])); + } - // detect type of data - if (data instanceof Point) { - info.point = data; - } else if (PublicKey._isJSON(data)) { - info = PublicKey._transformJSON(data); - } else if (typeof(data) === 'string') { - info = PublicKey._transformDER(new Buffer(data, 'hex')); - } else if (PublicKey._isBuffer(data)) { - info = PublicKey._transformDER(data); - } else if (PublicKey._isPrivateKey(data)) { - info = PublicKey._transformPrivateKey(data); - } else { - throw new TypeError('First argument is an unrecognized data format.'); + var endian = 'big'; + if (opts) { + endian = opts.endian; } - if (!info.network) { - info.network = _.isUndefined(extra.network) ? undefined : Network.get(extra.network); + if (endian === 'little') { + buf = reversebuf(buf); } - return info; -}; -/** - * Internal function to detect if an object is a {@link PrivateKey} - * - * @param {*} param - object to test - * @returns {boolean} - * @private - */ -PublicKey._isPrivateKey = function(param) { - var PrivateKey = require('./privatekey'); - return param instanceof PrivateKey; + if (buf[0] & 0x80) { + buf[0] = buf[0] & 0x7f; + ret = BN.fromBuffer(buf); + ret.neg().copy(ret); + } else { + ret = BN.fromBuffer(buf); + } + return ret; }; -/** - * Internal function to detect if an object is a Buffer - * - * @param {*} param - object to test - * @returns {boolean} - * @private - */ -PublicKey._isBuffer = function(param) { - return (param instanceof Buffer) || (param instanceof Uint8Array); -}; -/** - * Internal function to detect if a param is a JSON string or plain object - * - * @param {*} json - value to test - * @returns {boolean} - * @private - */ -PublicKey._isJSON = function(json) { - return !!(JSUtil.isValidJSON(json) || (json.x && json.y)); +BN.prototype.toNumber = function() { + return parseInt(this.toString(10), 10); }; -/** - * Internal function to transform a private key into a public key point - * - * @param {PrivateKey} privkey - An instance of PrivateKey - * @returns {Object} An object with keys: point and compressed - * @private - */ -PublicKey._transformPrivateKey = function(privkey) { - $.checkArgument(PublicKey._isPrivateKey(privkey), - new TypeError('Must be an instance of PrivateKey')); - var info = {}; - info.point = Point.getG().mul(privkey.bn); - info.compressed = privkey.compressed; - info.network = privkey.network; - return info; -}; +BN.prototype.toBuffer = function(opts) { + var buf, hex; + if (opts && opts.size) { + hex = this.toString(16, 2); + var natlen = hex.length / 2; + buf = new Buffer(hex, 'hex'); -/** - * Internal function to transform DER into a public key point - * - * @param {Buffer} buf - An hex encoded buffer - * @param {bool=} strict - if set to false, will loosen some conditions - * @returns {Object} An object with keys: point and compressed - * @private - */ -PublicKey._transformDER = function(buf, strict) { - /* jshint maxstatements: 30 */ - /* jshint maxcomplexity: 12 */ - $.checkArgument(PublicKey._isBuffer(buf), new TypeError('Must be a hex buffer of DER encoded public key')); - var info = {}; + if (natlen === opts.size) { + buf = buf; + } else if (natlen > opts.size) { + buf = BN.trim(buf, natlen); + } else if (natlen < opts.size) { + buf = BN.pad(buf, natlen, opts.size); + } + } else { + hex = this.toString(16, 2); + buf = new Buffer(hex, 'hex'); + } - strict = _.isUndefined(strict) ? true : strict; + if (typeof opts !== 'undefined' && opts.endian === 'little') { + buf = reversebuf(buf); + } - var x; - var y; - var xbuf; - var ybuf; + return buf; +}; - if (buf[0] === 0x04 || (!strict && (buf[0] === 0x06 || buf[0] === 0x07))) { - xbuf = buf.slice(1, 33); - ybuf = buf.slice(33, 65); - if (xbuf.length !== 32 || ybuf.length !== 32 || buf.length !== 65) { - throw new TypeError('Length of x and y must be 32 bytes'); +BN.prototype.toSMBigEndian = function() { + var buf; + if (this.cmp(BN.Zero) === -1) { + buf = this.neg().toBuffer(); + if (buf[0] & 0x80) { + buf = Buffer.concat([new Buffer([0x80]), buf]); + } else { + buf[0] = buf[0] | 0x80; } - x = new BN(xbuf); - y = new BN(ybuf); - info.point = new Point(x, y); - info.compressed = false; - } else if (buf[0] === 0x03) { - xbuf = buf.slice(1); - x = new BN(xbuf); - info = PublicKey._transformX(true, x); - info.compressed = true; - } else if (buf[0] === 0x02) { - xbuf = buf.slice(1); - x = new BN(xbuf); - info = PublicKey._transformX(false, x); - info.compressed = true; } else { - throw new TypeError('Invalid DER format public key'); + buf = this.toBuffer(); + if (buf[0] & 0x80) { + buf = Buffer.concat([new Buffer([0x00]), buf]); + } } - return info; -}; -/** - * Internal function to transform X into a public key point - * - * @param {Boolean} odd - If the point is above or below the x axis - * @param {Point} x - The x point - * @returns {Object} An object with keys: point and compressed - * @private - */ -PublicKey._transformX = function(odd, x) { - $.checkArgument(typeof odd === 'boolean', - new TypeError('Must specify whether y is odd or not (true or false)')); - var info = {}; - info.point = Point.fromX(odd, x); - return info; + if (buf.length === 1 & buf[0] === 0) { + buf = new Buffer([]); + } + return buf; }; -/** - * Instantiate a PublicKey from JSON - * - * @param {string} json - A JSON string - * @returns {PublicKey} A new valid instance of PublicKey - */ -PublicKey.fromJSON = function(json) { - $.checkArgument(PublicKey._isJSON(json), - new TypeError('Must be a valid JSON string or plain object')); - return new PublicKey(json); -}; +BN.prototype.toSM = function(opts) { + var endian = opts ? opts.endian : 'big'; + var buf = this.toSMBigEndian(); -/** - * Internal function to transform a JSON into a public key point - * - * @param {String|Object} json - a JSON string or plain object - * @returns {Object} An object with keys: point and compressed - * @private - */ -PublicKey._transformJSON = function(json) { - if (JSUtil.isValidJSON(json)) { - json = JSON.parse(json); + if (endian === 'little') { + buf = reversebuf(buf); } - var x = new BN(json.x, 'hex'); - var y = new BN(json.y, 'hex'); - var point = new Point(x, y); - return new PublicKey(point, { - compressed: json.compressed - }); + return buf; }; /** - * Instantiate a PublicKey from a PrivateKey - * - * @param {PrivateKey} privkey - An instance of PrivateKey - * @returns {PublicKey} A new valid instance of PublicKey + * Create a BN from a "ScriptNum": + * This is analogous to the constructor for CScriptNum in bitcoind. Many ops in + * bitcoind's script interpreter use CScriptNum, which is not really a proper + * bignum. Instead, an error is thrown if trying to input a number bigger than + * 4 bytes. We copy that behavior here. */ -PublicKey.fromPrivateKey = function(privkey) { - $.checkArgument(PublicKey._isPrivateKey(privkey), new TypeError('Must be an instance of PrivateKey')); - var info = PublicKey._transformPrivateKey(privkey); - return new PublicKey(info.point, { - compressed: info.compressed, - network: info.network +BN.fromScriptNumBuffer = function(buf, fRequireMinimal) { + var nMaxNumSize = 4; + $.checkArgument(buf.length <= nMaxNumSize, new Error('script number overflow')); + if (fRequireMinimal && buf.length > 0) { + // Check that the number is encoded with the minimum possible + // number of bytes. + // + // If the most-significant-byte - excluding the sign bit - is zero + // then we're not minimal. Note how this test also rejects the + // negative-zero encoding, 0x80. + if ((buf[buf.length - 1] & 0x7f) === 0) { + // One exception: if there's more than one byte and the most + // significant bit of the second-most-significant-byte is set + // it would conflict with the sign bit. An example of this case + // is +-255, which encode to 0xff00 and 0xff80 respectively. + // (big-endian). + if (buf.length <= 1 || (buf[buf.length - 2] & 0x80) === 0) { + throw new Error('non-minimally encoded script number'); + } + } + } + return BN.fromSM(buf, { + endian: 'little' }); }; /** - * Instantiate a PublicKey from a Buffer - * @param {Buffer} buf - A DER hex buffer - * @param {bool=} strict - if set to false, will loosen some conditions - * @returns {PublicKey} A new valid instance of PublicKey + * The corollary to the above, with the notable exception that we do not throw + * an error if the output is larger than four bytes. (Which can happen if + * performing a numerical operation that results in an overflow to more than 4 + * bytes). */ -PublicKey.fromDER = PublicKey.fromBuffer = function(buf, strict) { - $.checkArgument(PublicKey._isBuffer(buf), - new TypeError('Must be a hex buffer of DER encoded public key')); - var info = PublicKey._transformDER(buf, strict); - return new PublicKey(info.point, { - compressed: info.compressed +BN.prototype.toScriptNumBuffer = function() { + return this.toSM({ + endian: 'little' }); }; -/** - * Instantiate a PublicKey from a Point - * - * @param {Point} point - A Point instance - * @param {boolean=} compressed - whether to store this public key as compressed format - * @returns {PublicKey} A new valid instance of PublicKey - */ -PublicKey.fromPoint = function(point, compressed) { - $.checkArgument(point instanceof Point, - new TypeError('First argument must be an instance of Point.')); - return new PublicKey(point, { - compressed: compressed - }); +BN.prototype.gt = function(b) { + return this.cmp(b) > 0; }; -/** - * Instantiate a PublicKey from a DER hex encoded string - * - * @param {string} str - A DER hex string - * @param {String=} encoding - The type of string encoding - * @returns {PublicKey} A new valid instance of PublicKey - */ -PublicKey.fromString = function(str, encoding) { - var buf = new Buffer(str, encoding || 'hex'); - var info = PublicKey._transformDER(buf); - return new PublicKey(info.point, { - compressed: info.compressed - }); +BN.prototype.lt = function(b) { + return this.cmp(b) < 0; }; -/** - * Instantiate a PublicKey from an X Point - * - * @param {Boolean} odd - If the point is above or below the x axis - * @param {Point} x - The x point - * @returns {PublicKey} A new valid instance of PublicKey - */ -PublicKey.fromX = function(odd, x) { - var info = PublicKey._transformX(odd, x); - return new PublicKey(info.point, { - compressed: info.compressed - }); +BN.trim = function(buf, natlen) { + return buf.slice(natlen - buf.length, buf.length); }; -/** - * Check if there would be any errors when initializing a PublicKey - * - * @param {string} data - The encoded data in various formats - * @returns {null|Error} An error if exists - */ -PublicKey.getValidationError = function(data) { - var error; - try { - /* jshint nonew: false */ - new PublicKey(data); - } catch (e) { - error = e; +BN.pad = function(buf, natlen, size) { + var rbuf = new Buffer(size); + for (var i = 0; i < buf.length; i++) { + rbuf[rbuf.length - 1 - i] = buf[buf.length - 1 - i]; } - return error; -}; - -/** - * Check if the parameters are valid - * - * @param {string} data - The encoded data in various formats - * @returns {Boolean} If the public key would be valid - */ -PublicKey.isValid = function(data) { - return !PublicKey.getValidationError(data); + for (i = 0; i < size - natlen; i++) { + rbuf[i] = 0; + } + return rbuf; }; -/** - * @returns {Object} A plain object of the PublicKey - */ -PublicKey.prototype.toObject = function toObject() { - return { - x: this.point.getX().toString('hex'), - y: this.point.getY().toString('hex'), - compressed: this.compressed - }; -}; +module.exports = BN; -/** - * @returns {string} A JSON string of the PublicKey - */ -PublicKey.prototype.toJSON = function toJSON() { - return JSON.stringify(this.toObject()); -}; +}).call(this,require("buffer").Buffer) +},{"../util/preconditions":71,"bn.js":72,"buffer":209,"lodash":95}],35:[function(require,module,exports){ +(function (Buffer){ +'use strict'; -/** - * Will output the PublicKey to a DER Buffer - * - * @returns {Buffer} A DER hex encoded buffer - */ -PublicKey.prototype.toBuffer = PublicKey.prototype.toDER = function() { - var x = this.point.getX(); - var y = this.point.getY(); +var BN = require('./bn'); +var Point = require('./point'); +var Signature = require('./signature'); +var PublicKey = require('../publickey'); +var Random = require('./random'); +var Hash = require('./hash'); +var BufferUtil = require('../util/buffer'); +var _ = require('lodash'); +var $ = require('../util/preconditions'); - var xbuf = x.toBuffer({ - size: 32 - }); - var ybuf = y.toBuffer({ - size: 32 - }); +var ECDSA = function ECDSA(obj) { + if (!(this instanceof ECDSA)) { + return new ECDSA(obj); + } + if (obj) { + this.set(obj); + } +}; - var prefix; - if (!this.compressed) { - prefix = new Buffer([0x04]); - return Buffer.concat([prefix, xbuf, ybuf]); - } else { - var odd = ybuf[ybuf.length - 1] % 2; - if (odd) { - prefix = new Buffer([0x03]); - } else { - prefix = new Buffer([0x02]); +/* jshint maxcomplexity: 9 */ +ECDSA.prototype.set = function(obj) { + this.hashbuf = obj.hashbuf || this.hashbuf; + this.endian = obj.endian || this.endian; //the endianness of hashbuf + this.privkey = obj.privkey || this.privkey; + this.pubkey = obj.pubkey || (this.privkey ? this.privkey.publicKey : this.pubkey); + this.sig = obj.sig || this.sig; + this.k = obj.k || this.k; + this.verified = obj.verified || this.verified; + return this; +}; + +ECDSA.prototype.privkey2pubkey = function() { + this.pubkey = this.privkey.toPublicKey(); +}; + +ECDSA.prototype.calci = function() { + for (var i = 0; i < 4; i++) { + this.sig.i = i; + var Qprime; + try { + Qprime = this.toPublicKey(); + } catch (e) { + console.error(e); + continue; + } + + if (Qprime.point.eq(this.pubkey.point)) { + this.sig.compressed = this.pubkey.compressed; + return this; } - return Buffer.concat([prefix, xbuf]); } -}; -/** - * Will return a sha256 + ripemd160 hash of the serialized public key - * @see https://github.com/bitcoin/bitcoin/blob/master/src/pubkey.h#L141 - * @returns {Buffer} - */ -PublicKey.prototype._getID = function _getID() { - return Hash.sha256ripemd160(this.toBuffer()); + this.sig.i = undefined; + throw new Error('Unable to find valid recovery factor'); }; -/** - * Will return an address for the public key - * - * @param {String|Network=} network - Which network should the address be for - * @returns {Address} An address generated from the public key - */ -PublicKey.prototype.toAddress = function(network) { - return Address.fromPublicKey(this, network || this.network); +ECDSA.fromString = function(str) { + var obj = JSON.parse(str); + return new ECDSA(obj); }; -/** - * Will output the PublicKey to a DER encoded hex string - * - * @returns {string} A DER hex encoded string - */ -PublicKey.prototype.toString = function() { - return this.toDER().toString('hex'); +ECDSA.prototype.randomK = function() { + var N = Point.getN(); + var k; + do { + k = BN.fromBuffer(Random.getRandomBuffer(32)); + } while (!(k.lt(N) && k.gt(BN.Zero))); + this.k = k; + return this; }; -/** - * Will return a string formatted for the console - * - * @returns {string} Public key - */ -PublicKey.prototype.inspect = function() { - return ''; + +// https://tools.ietf.org/html/rfc6979#section-3.2 +ECDSA.prototype.deterministicK = function(badrs) { + /* jshint maxstatements: 25 */ + // if r or s were invalid when this function was used in signing, + // we do not want to actually compute r, s here for efficiency, so, + // we can increment badrs. explained at end of RFC 6979 section 3.2 + if (_.isUndefined(badrs)) { + badrs = 0; + } + var v = new Buffer(32); + v.fill(0x01); + var k = new Buffer(32); + k.fill(0x00); + var x = this.privkey.bn.toBuffer({ + size: 32 + }); + k = Hash.sha256hmac(Buffer.concat([v, new Buffer([0x00]), x, this.hashbuf]), k); + v = Hash.sha256hmac(v, k); + k = Hash.sha256hmac(Buffer.concat([v, new Buffer([0x01]), x, this.hashbuf]), k); + v = Hash.sha256hmac(v, k); + v = Hash.sha256hmac(v, k); + var T = BN.fromBuffer(v); + var N = Point.getN(); + + // also explained in 3.2, we must ensure T is in the proper range (0, N) + for (var i = 0; i < badrs || !(T.lt(N) && T.gt(BN.Zero)); i++) { + k = Hash.sha256hmac(Buffer.concat([v, new Buffer([0x00])]), k); + v = Hash.sha256hmac(v, k); + v = Hash.sha256hmac(v, k); + T = BN.fromBuffer(v); + } + + this.k = T; + return this; }; +// Information about public key recovery: +// https://bitcointalk.org/index.php?topic=6430.0 +// http://stackoverflow.com/questions/19665491/how-do-i-get-an-ecdsa-public-key-from-just-a-bitcoin-signature-sec1-4-1-6-k +ECDSA.prototype.toPublicKey = function() { + /* jshint maxstatements: 25 */ + var i = this.sig.i; + $.checkArgument(i === 0 || i === 1 || i === 2 || i === 3, new Error('i must be equal to 0, 1, 2, or 3')); -module.exports = PublicKey; + var e = BN.fromBuffer(this.hashbuf); + var r = this.sig.r; + var s = this.sig.s; -}).call(this,require("buffer").Buffer) -},{"./address":13,"./crypto/bn":18,"./crypto/hash":20,"./crypto/point":21,"./networks":34,"./privatekey":36,"./util/js":54,"./util/preconditions":55,"buffer":104,"lodash":79}],38:[function(require,module,exports){ -module.exports = require('./script'); + // A set LSB signifies that the y-coordinate is odd + var isYOdd = i & 1; -module.exports.Interpreter = require('./interpreter'); + // The more significant bit specifies whether we should use the + // first or second candidate key. + var isSecondKey = i >> 1; -},{"./interpreter":39,"./script":40}],39:[function(require,module,exports){ -(function (Buffer){ -'use strict'; + var n = Point.getN(); + var G = Point.getG(); -var _ = require('lodash'); + // 1.1 Let x = r + jn + var x = isSecondKey ? r.add(n) : r; + var R = Point.fromX(isYOdd, x); -var Script = require('./script'); -var Opcode = require('../opcode'); -var BN = require('../crypto/bn'); -var Hash = require('../crypto/hash'); -var Signature = require('../crypto/signature'); -var PublicKey = require('../publickey'); + // 1.4 Check that nR is at infinity + var nR = R.mul(n); -/** - * Bitcoin transactions contain scripts. Each input has a script called the - * scriptSig, and each output has a script called the scriptPubkey. To validate - * an input, the input's script is concatenated with the referenced output script, - * and the result is executed. If at the end of execution the stack contains a - * "true" value, then the transaction is valid. - * - * The primary way to use this class is via the verify function. - * e.g., Interpreter().verify( ... ); - */ -var Interpreter = function Interpreter(obj) { - if (!(this instanceof Interpreter)) { - return new Interpreter(obj); - } - if (obj) { - this.initialize(); - this.set(obj); - } else { - this.initialize(); + if (!nR.isInfinity()) { + throw new Error('nR is not a valid curve point'); } -}; -/** - * Verifies a Script by executing it and returns true if it is valid. - * This function needs to be provided with the scriptSig and the scriptPubkey - * separately. - * @param {Script} scriptSig - the script's first part (corresponding to the tx input) - * @param {Script} scriptPubkey - the script's last part (corresponding to the tx output) - * @param {Transaction=} tx - the Transaction containing the scriptSig in one input (used - * to check signature validity for some opcodes like OP_CHECKSIG) - * @param {number} nin - index of the transaction input containing the scriptSig verified. - * @param {number} flags - evaluation flags. See Interpreter.SCRIPT_* constants - * - * Translated from bitcoind's VerifyScript - */ -Interpreter.prototype.verify = function(scriptSig, scriptPubkey, tx, nin, flags) { - var Transaction = require('../transaction'); - if (_.isUndefined(tx)) { - tx = new Transaction(); - } - if (_.isUndefined(nin)) { - nin = 0; - } - if (_.isUndefined(flags)) { - flags = 0; - } - this.set({ - script: scriptSig, - tx: tx, - nin: nin, - flags: flags - }); - var stackCopy; + // Compute -e from e + var eNeg = e.neg().mod(n); - if ((flags & Interpreter.SCRIPT_VERIFY_SIGPUSHONLY) !== 0 && !scriptSig.isPushOnly()) { - this.errstr = 'SCRIPT_ERR_SIG_PUSHONLY'; - return false; - } + // 1.6.1 Compute Q = r^-1 (sR - eG) + // Q = r^-1 (sR + -eG) + var rInv = r.invm(n); - // evaluate scriptSig - if (!this.evaluate()) { - return false; + //var Q = R.multiplyTwo(s, G, eNeg).mul(rInv); + var Q = R.mul(s).add(G.mul(eNeg)).mul(rInv); + + var pubkey = PublicKey.fromPoint(Q, this.sig.compressed); + + return pubkey; +}; + +ECDSA.prototype.sigError = function() { + /* jshint maxstatements: 25 */ + if (!BufferUtil.isBuffer(this.hashbuf) || this.hashbuf.length !== 32) { + return 'hashbuf must be a 32 byte buffer'; } - if (flags & Interpreter.SCRIPT_VERIFY_P2SH) { - stackCopy = this.stack.slice(); + var r = this.sig.r; + var s = this.sig.s; + if (!(r.gt(BN.Zero) && r.lt(Point.getN())) || !(s.gt(BN.Zero) && s.lt(Point.getN()))) { + return 'r and s not in range'; } - var stack = this.stack; - this.initialize(); - this.set({ - script: scriptPubkey, - stack: stack, - tx: tx, - nin: nin, - flags: flags - }); + var e = BN.fromBuffer(this.hashbuf, this.endian ? { + endian: this.endian + } : undefined); + var n = Point.getN(); + var sinv = s.invm(n); + var u1 = sinv.mul(e).mod(n); + var u2 = sinv.mul(r).mod(n); - // evaluate scriptPubkey - if (!this.evaluate()) { - return false; + var p = Point.getG().mulAdd(u1, this.pubkey.point, u2); + if (p.isInfinity()) { + return 'p is infinity'; } - if (this.stack.length === 0) { - this.errstr = 'SCRIPT_ERR_EVAL_FALSE_NO_RESULT'; + if (p.getX().mod(n).cmp(r) !== 0) { + return 'Invalid signature'; + } else { return false; } +}; - var buf = this.stack[this.stack.length - 1]; - if (!Interpreter.castToBool(buf)) { - this.errstr = 'SCRIPT_ERR_EVAL_FALSE_IN_STACK'; - return false; +ECDSA.toLowS = function(s) { + //enforce low s + //see BIP 62, "low S values in signatures" + if (s.gt(BN.fromBuffer(new Buffer('7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0', 'hex')))) { + s = Point.getN().sub(s); } + return s; +}; - // Additional validation for spend-to-script-hash transactions: - if ((flags & Interpreter.SCRIPT_VERIFY_P2SH) && scriptPubkey.isScriptHashOut()) { - // scriptSig must be literals-only or validation fails - if (!scriptSig.isPushOnly()) { - this.errstr = 'SCRIPT_ERR_SIG_PUSHONLY'; - return false; +ECDSA.prototype._findSignature = function(d, e) { + var N = Point.getN(); + var G = Point.getG(); + // try different values of k until r, s are valid + var badrs = 0; + var k, Q, r, s; + do { + if (!this.k || badrs > 0) { + this.deterministicK(badrs); } + badrs++; + k = this.k; + Q = G.mul(k); + r = Q.x.mod(N); + s = k.invm(N).mul(e.add(d.mul(r))).mod(N); + } while (r.cmp(BN.Zero) <= 0 || s.cmp(BN.Zero) <= 0); - // stackCopy cannot be empty here, because if it was the - // P2SH HASH <> EQUAL scriptPubKey would be evaluated with - // an empty stack and the EvalScript above would return false. - if (stackCopy.length === 0) { - throw new Error('internal error - stack copy empty'); - } + s = ECDSA.toLowS(s); + return { + s: s, + r: r + }; - var redeemScriptSerialized = stackCopy[stackCopy.length - 1]; - var redeemScript = Script.fromBuffer(redeemScriptSerialized); - stackCopy.pop(); +}; - this.initialize(); - this.set({ - script: redeemScript, - stack: stackCopy, - tx: tx, - nin: nin, - flags: flags - }); +ECDSA.prototype.sign = function() { + var hashbuf = this.hashbuf; + var privkey = this.privkey; + var d = privkey.bn; - // evaluate redeemScript - if (!this.evaluate()) { - return false; - } + $.checkState(hashbuf && privkey && d, new Error('invalid parameters')); + $.checkState(BufferUtil.isBuffer(hashbuf) && hashbuf.length === 32, new Error('hashbuf must be a 32 byte buffer')); - if (stackCopy.length === 0) { - this.errstr = 'SCRIPT_ERR_EVAL_FALSE_NO_P2SH_STACK'; - return false; - } + var e = BN.fromBuffer(hashbuf, this.endian ? { + endian: this.endian + } : undefined); - if (!Interpreter.castToBool(stackCopy[stackCopy.length - 1])) { - this.errstr = 'SCRIPT_ERR_EVAL_FALSE_IN_P2SH_STACK'; - return false; - } else { - return true; - } - } + var obj = this._findSignature(d, e); + obj.compressed = this.pubkey.compressed; - return true; + this.sig = new Signature(obj); + return this; }; -module.exports = Interpreter; +ECDSA.prototype.signRandomK = function() { + this.randomK(); + return this.sign(); +}; -Interpreter.prototype.initialize = function(obj) { - this.stack = []; - this.altstack = []; - this.pc = 0; - this.pbegincodehash = 0; - this.nOpCount = 0; - this.vfExec = []; - this.errstr = ''; - this.flags = 0; +ECDSA.prototype.toString = function() { + var obj = {}; + if (this.hashbuf) { + obj.hashbuf = this.hashbuf.toString('hex'); + } + if (this.privkey) { + obj.privkey = this.privkey.toString(); + } + if (this.pubkey) { + obj.pubkey = this.pubkey.toString(); + } + if (this.sig) { + obj.sig = this.sig.toString(); + } + if (this.k) { + obj.k = this.k.toString(); + } + return JSON.stringify(obj); }; -Interpreter.prototype.set = function(obj) { - this.script = obj.script || this.script; - this.tx = obj.tx || this.tx; - this.nin = typeof obj.nin !== 'undefined' ? obj.nin : this.nin; - this.stack = obj.stack || this.stack; - this.altstack = obj.altack || this.altstack; - this.pc = typeof obj.pc !== 'undefined' ? obj.pc : this.pc; - this.pbegincodehash = typeof obj.pbegincodehash !== 'undefined' ? obj.pbegincodehash : this.pbegincodehash; - this.nOpCount = typeof obj.nOpCount !== 'undefined' ? obj.nOpCount : this.nOpCount; - this.vfExec = obj.vfExec || this.vfExec; - this.errstr = obj.errstr || this.errstr; - this.flags = typeof obj.flags !== 'undefined' ? obj.flags : this.flags; +ECDSA.prototype.verify = function() { + if (!this.sigError()) { + this.verified = true; + } else { + this.verified = false; + } + return this; }; -Interpreter.true = new Buffer([1]); -Interpreter.false = new Buffer([]); +ECDSA.sign = function(hashbuf, privkey, endian) { + return ECDSA().set({ + hashbuf: hashbuf, + endian: endian, + privkey: privkey + }).sign().sig; +}; -Interpreter.MAX_SCRIPT_ELEMENT_SIZE = 520; +ECDSA.verify = function(hashbuf, sig, pubkey, endian) { + return ECDSA().set({ + hashbuf: hashbuf, + endian: endian, + sig: sig, + pubkey: pubkey + }).verify().verified; +}; -// flags taken from bitcoind -// bitcoind commit: b5d1b1092998bc95313856d535c632ea5a8f9104 -Interpreter.SCRIPT_VERIFY_NONE = 0; +module.exports = ECDSA; -// Evaluate P2SH subscripts (softfork safe, BIP16). -Interpreter.SCRIPT_VERIFY_P2SH = (1 << 0); +}).call(this,require("buffer").Buffer) +},{"../publickey":53,"../util/buffer":69,"../util/preconditions":71,"./bn":34,"./hash":36,"./point":37,"./random":38,"./signature":39,"buffer":209,"lodash":95}],36:[function(require,module,exports){ +(function (Buffer){ +'use strict'; -// Passing a non-strict-DER signature or one with undefined hashtype to a checksig operation causes script failure. -// Passing a pubkey that is not (0x04 + 64 bytes) or (0x02 or 0x03 + 32 bytes) to checksig causes that pubkey to be -// skipped (not softfork safe: this flag can widen the validity of OP_CHECKSIG OP_NOT). -Interpreter.SCRIPT_VERIFY_STRICTENC = (1 << 1); +var hashjs = require('hash.js'); +var sha512 = require('sha512'); +var crypto = require('crypto'); +var BufferUtil = require('../util/buffer'); +var $ = require('../util/preconditions'); -// Passing a non-strict-DER signature to a checksig operation causes script failure (softfork safe, BIP62 rule 1) -Interpreter.SCRIPT_VERIFY_DERSIG = (1 << 2); +var Hash = module.exports; -// Passing a non-strict-DER signature or one with S > order/2 to a checksig operation causes script failure -// (softfork safe, BIP62 rule 5). -Interpreter.SCRIPT_VERIFY_LOW_S = (1 << 3); +Hash.sha1 = function(buf) { + $.checkArgument(BufferUtil.isBuffer(buf)); + return crypto.createHash('sha1').update(buf).digest(); +}; -// verify dummy stack item consumed by CHECKMULTISIG is of zero-length (softfork safe, BIP62 rule 7). -Interpreter.SCRIPT_VERIFY_NULLDUMMY = (1 << 4); +Hash.sha1.blocksize = 512; -// Using a non-push operator in the scriptSig causes script failure (softfork safe, BIP62 rule 2). -Interpreter.SCRIPT_VERIFY_SIGPUSHONLY = (1 << 5); +Hash.sha256 = function(buf) { + $.checkArgument(BufferUtil.isBuffer(buf)); + return crypto.createHash('sha256').update(buf).digest(); +}; -// Require minimal encodings for all push operations (OP_0... OP_16, OP_1NEGATE where possible, direct -// pushes up to 75 bytes, OP_PUSHDATA up to 255 bytes, OP_PUSHDATA2 for anything larger). Evaluating -// any other push causes the script to fail (BIP62 rule 3). -// In addition, whenever a stack element is interpreted as a number, it must be of minimal length (BIP62 rule 4). -// (softfork safe) -Interpreter.SCRIPT_VERIFY_MINIMALDATA = (1 << 6); +Hash.sha256.blocksize = 512; -// Discourage use of NOPs reserved for upgrades (NOP1-10) -// -// Provided so that nodes can avoid accepting or mining transactions -// containing executed NOP's whose meaning may change after a soft-fork, -// thus rendering the script invalid; with this flag set executing -// discouraged NOPs fails the script. This verification flag will never be -// a mandatory flag applied to scripts in a block. NOPs that are not -// executed, e.g. within an unexecuted IF ENDIF block, are *not* rejected. -Interpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS = (1 << 7); +Hash.sha256sha256 = function(buf) { + $.checkArgument(BufferUtil.isBuffer(buf)); + return Hash.sha256(Hash.sha256(buf)); +}; -Interpreter.castToBool = function(buf) { - for (var i = 0; i < buf.length; i++) { - if (buf[i] !== 0) { - // can be negative zero - if (i === buf.length - 1 && buf[i] === 0x80) { - return false; - } - return true; - } +Hash.ripemd160 = function(buf) { + $.checkArgument(BufferUtil.isBuffer(buf)); + var hash = (new hashjs.ripemd160()).update(buf).digest(); + return new Buffer(hash); +}; + +Hash.sha256ripemd160 = function(buf) { + $.checkArgument(BufferUtil.isBuffer(buf)); + return Hash.ripemd160(Hash.sha256(buf)); +}; + +Hash.sha512 = function(buf) { + $.checkArgument(BufferUtil.isBuffer(buf)); + var hash = sha512(buf); + return new Buffer(hash); +}; + +Hash.sha512.blocksize = 1024; + +Hash.hmac = function(hashf, data, key) { + //http://en.wikipedia.org/wiki/Hash-based_message_authentication_code + //http://tools.ietf.org/html/rfc4868#section-2 + $.checkArgument(BufferUtil.isBuffer(data)); + $.checkArgument(BufferUtil.isBuffer(key)); + $.checkArgument(hashf.blocksize); + + var blocksize = hashf.blocksize / 8; + + if (key.length > blocksize) { + key = hashf(key); + } else if (key < blocksize) { + var fill = new Buffer(blocksize); + fill.fill(0); + key.copy(fill); + key = fill; } - return false; + + var o_key = new Buffer(blocksize); + o_key.fill(0x5c); + + var i_key = new Buffer(blocksize); + i_key.fill(0x36); + + var o_key_pad = new Buffer(blocksize); + var i_key_pad = new Buffer(blocksize); + for (var i = 0; i < blocksize; i++) { + o_key_pad[i] = o_key[i] ^ key[i]; + i_key_pad[i] = i_key[i] ^ key[i]; + } + + return hashf(Buffer.concat([o_key_pad, hashf(Buffer.concat([i_key_pad, data]))])); +}; + +Hash.sha256hmac = function(data, key) { + return Hash.hmac(Hash.sha256, data, key); +}; + +Hash.sha512hmac = function(data, key) { + return Hash.hmac(Hash.sha512, data, key); }; +}).call(this,require("buffer").Buffer) +},{"../util/buffer":69,"../util/preconditions":71,"buffer":209,"crypto":213,"hash.js":88,"sha512":98}],37:[function(require,module,exports){ +(function (Buffer){ +'use strict'; + +var BN = require('./bn'); +var BufferUtil = require('../util/buffer'); +var ec = require('elliptic').curves.secp256k1; +var ecPoint = ec.curve.point.bind(ec.curve); +var ecPointFromX = ec.curve.pointFromX.bind(ec.curve); + /** - * Translated from bitcoind's CheckSignatureEncoding + * + * Instantiate a valid secp256k1 Point from the X and Y coordinates. + * + * @param {BN|String} x - The X coordinate + * @param {BN|String} y - The Y coordinate + * @link https://github.com/indutny/elliptic + * @augments elliptic.curve.point + * @throws {Error} A validation error if exists + * @returns {Point} An instance of Point + * @constructor */ -Interpreter.prototype.checkSignatureEncoding = function(buf) { - var sig; - if ((this.flags & (Interpreter.SCRIPT_VERIFY_DERSIG | Interpreter.SCRIPT_VERIFY_LOW_S | Interpreter.SCRIPT_VERIFY_STRICTENC)) !== 0 && !Signature.isTxDER(buf)) { - this.errstr = 'SCRIPT_ERR_SIG_DER_INVALID_FORMAT'; - return false; - } else if ((this.flags & Interpreter.SCRIPT_VERIFY_LOW_S) !== 0) { - sig = Signature.fromTxFormat(buf); - if (!sig.hasLowS()) { - this.errstr = 'SCRIPT_ERR_SIG_DER_HIGH_S'; - return false; - } - } else if ((this.flags & Interpreter.SCRIPT_VERIFY_STRICTENC) !== 0) { - sig = Signature.fromTxFormat(buf); - if (!sig.hasDefinedHashtype()) { - this.errstr = 'SCRIPT_ERR_SIG_HASHTYPE'; - return false; - } - } - return true; +var Point = function Point(x, y, isRed) { + var point = ecPoint(x, y, isRed); + point.validate(); + return point; }; +Point.prototype = Object.getPrototypeOf(ec.curve.point()); + /** - * Translated from bitcoind's CheckPubKeyEncoding + * + * Instantiate a valid secp256k1 Point from only the X coordinate + * + * @param {boolean} odd - If the Y coordinate is odd + * @param {BN|String} x - The X coordinate + * @throws {Error} A validation error if exists + * @returns {Point} An instance of Point */ -Interpreter.prototype.checkPubkeyEncoding = function(buf) { - if ((this.flags & Interpreter.SCRIPT_VERIFY_STRICTENC) !== 0 && !PublicKey.isValid(buf)) { - this.errstr = 'SCRIPT_ERR_PUBKEYTYPE'; - return false; - } - return true; +Point.fromX = function fromX(odd, x){ + var point = ecPointFromX(odd, x); + point.validate(); + return point; }; /** - * Based on bitcoind's EvalScript function, with the inner loop moved to - * Interpreter.prototype.step() - * bitcoind commit: b5d1b1092998bc95313856d535c632ea5a8f9104 + * + * Will return a secp256k1 ECDSA base point. + * + * @link https://en.bitcoin.it/wiki/Secp256k1 + * @returns {Point} An instance of the base point. */ -Interpreter.prototype.evaluate = function() { - if (this.script.toBuffer().length > 10000) { - this.errstr = 'SCRIPT_ERR_SCRIPT_SIZE'; - return false; - } +Point.getG = function getG() { + return ec.curve.g; +}; - try { - while (this.pc < this.script.chunks.length) { - var fSuccess = this.step(); - if (!fSuccess) { - return false; - } - } +/** + * + * Will return the max of range of valid private keys as governed by the secp256k1 ECDSA standard. + * + * @link https://en.bitcoin.it/wiki/Private_key#Range_of_valid_ECDSA_private_keys + * @returns {BN} A BN instance of the number of points on the curve + */ +Point.getN = function getN() { + return new BN(ec.curve.n.toArray()); +}; - // Size limits - if (this.stack.length + this.altstack.length > 1000) { - this.errstr = 'SCRIPT_ERR_STACK_SIZE'; - return false; - } - } catch (e) { - this.errstr = 'SCRIPT_ERR_UNKNOWN_ERROR: ' + e; - return false; - } +Point.prototype._getX = Point.prototype.getX; - if (this.vfExec.length > 0) { - this.errstr = 'SCRIPT_ERR_UNBALANCED_CONDITIONAL'; - return false; - } +/** + * + * Will return the X coordinate of the Point + * + * @returns {BN} A BN instance of the X coordinate + */ +Point.prototype.getX = function getX() { + return new BN(this._getX().toArray()); +}; - return true; +Point.prototype._getY = Point.prototype.getY; + +/** + * + * Will return the Y coordinate of the Point + * + * @returns {BN} A BN instance of the Y coordinate + */ +Point.prototype.getY = function getY() { + return new BN(this._getY().toArray()); }; -/** - * Based on the inner loop of bitcoind's EvalScript function - * bitcoind commit: b5d1b1092998bc95313856d535c632ea5a8f9104 +/** + * + * Will determine if the point is valid + * + * @link https://www.iacr.org/archive/pkc2003/25670211/25670211.pdf + * @param {Point} An instance of Point + * @throws {Error} A validation error if exists + * @returns {Point} An instance of the same Point */ -Interpreter.prototype.step = function() { +Point.prototype.validate = function validate() { - var fRequireMinimal = (this.flags & Interpreter.SCRIPT_VERIFY_MINIMALDATA) !== 0; + if (this.isInfinity()){ + throw new Error('Point cannot be equal to Infinity'); + } - //bool fExec = !count(vfExec.begin(), vfExec.end(), false); - var fExec = (this.vfExec.indexOf(false) === -1); - var buf, buf1, buf2, spliced, n, x1, x2, bn, bn1, bn2, bufSig, bufPubkey, subscript; - var sig, pubkey; - var fValue, fSuccess; + if (this.getX().cmp(BN.Zero) === 0 || this.getY().cmp(BN.Zero) === 0){ + throw new Error('Invalid x,y value for curve, cannot equal 0.'); + } - // Read instruction - var chunk = this.script.chunks[this.pc]; - this.pc++; - var opcodenum = chunk.opcodenum; - if (_.isUndefined(opcodenum)) { - this.errstr = 'SCRIPT_ERR_UNDEFINED_OPCODE'; - return false; + var p2 = ecPointFromX(this.getY().isOdd(), this.getX()); + + if (p2.y.cmp(this.y) !== 0) { + throw new Error('Invalid y value for curve.'); } - if (chunk.buf && chunk.buf.length > Interpreter.MAX_SCRIPT_ELEMENT_SIZE) { - this.errstr = 'SCRIPT_ERR_PUSH_SIZE'; - return false; + + var xValidRange = (this.getX().gt(BN.Minus1) && this.getX().lt(Point.getN())); + var yValidRange = (this.getY().gt(BN.Minus1) && this.getY().lt(Point.getN())); + + if ( !xValidRange || !yValidRange ) { + throw new Error('Point does not lie on the curve'); } - // Note how Opcode.OP_RESERVED does not count towards the opcode limit. - if (opcodenum > Opcode.OP_16 && ++(this.nOpCount) > 201) { - this.errstr = 'SCRIPT_ERR_OP_COUNT'; - return false; + //todo: needs test case + if (!(this.mul(Point.getN()).isInfinity())) { + throw new Error('Point times N must be infinity'); } + return this; - if (opcodenum === Opcode.OP_CAT || - opcodenum === Opcode.OP_SUBSTR || - opcodenum === Opcode.OP_LEFT || - opcodenum === Opcode.OP_RIGHT || - opcodenum === Opcode.OP_INVERT || - opcodenum === Opcode.OP_AND || - opcodenum === Opcode.OP_OR || - opcodenum === Opcode.OP_XOR || - opcodenum === Opcode.OP_2MUL || - opcodenum === Opcode.OP_2DIV || - opcodenum === Opcode.OP_MUL || - opcodenum === Opcode.OP_DIV || - opcodenum === Opcode.OP_MOD || - opcodenum === Opcode.OP_LSHIFT || - opcodenum === Opcode.OP_RSHIFT) { - this.errstr = 'SCRIPT_ERR_DISABLED_OPCODE'; - return false; - } +}; - if (fExec && 0 <= opcodenum && opcodenum <= Opcode.OP_PUSHDATA4) { - if (fRequireMinimal && !this.script.checkMinimalPush(this.pc - 1)) { - this.errstr = 'SCRIPT_ERR_MINIMALDATA'; - return false; - } - if (!chunk.buf) { - this.stack.push(Interpreter.false); - } else if (chunk.len !== chunk.buf.length) { - throw new Error('Length of push value not equal to length of data'); - } else { - this.stack.push(chunk.buf); - } - } else if (fExec || (Opcode.OP_IF <= opcodenum && opcodenum <= Opcode.OP_ENDIF)) { - switch (opcodenum) { - // Push value - case Opcode.OP_1NEGATE: - case Opcode.OP_1: - case Opcode.OP_2: - case Opcode.OP_3: - case Opcode.OP_4: - case Opcode.OP_5: - case Opcode.OP_6: - case Opcode.OP_7: - case Opcode.OP_8: - case Opcode.OP_9: - case Opcode.OP_10: - case Opcode.OP_11: - case Opcode.OP_12: - case Opcode.OP_13: - case Opcode.OP_14: - case Opcode.OP_15: - case Opcode.OP_16: - { - // ( -- value) - // ScriptNum bn((int)opcode - (int)(Opcode.OP_1 - 1)); - n = opcodenum - (Opcode.OP_1 - 1); - buf = new BN(n).toScriptNumBuffer(); - this.stack.push(buf); - // The result of these opcodes should always be the minimal way to push the data - // they push, so no need for a CheckMinimalPush here. - } - break; +Point.pointToCompressed = function pointToCompressed(point) { + var xbuf = point.getX().toBuffer({size: 32}); + var ybuf = point.getY().toBuffer({size: 32}); + var prefix; + var odd = ybuf[ybuf.length - 1] % 2; + if (odd) { + prefix = new Buffer([0x03]); + } else { + prefix = new Buffer([0x02]); + } + return BufferUtil.concat([prefix, xbuf]); +}; - // - // Control - // - case Opcode.OP_NOP: - break; +module.exports = Point; - case Opcode.OP_NOP1: - case Opcode.OP_NOP2: - case Opcode.OP_NOP3: - case Opcode.OP_NOP4: - case Opcode.OP_NOP5: - case Opcode.OP_NOP6: - case Opcode.OP_NOP7: - case Opcode.OP_NOP8: - case Opcode.OP_NOP9: - case Opcode.OP_NOP10: - { - if (this.flags & Interpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) { - this.errstr = 'SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS'; - return false; - } - } - break; +}).call(this,require("buffer").Buffer) +},{"../util/buffer":69,"./bn":34,"buffer":209,"elliptic":74}],38:[function(require,module,exports){ +(function (process,Buffer){ +'use strict'; - case Opcode.OP_IF: - case Opcode.OP_NOTIF: - { - // if [statements] [else [statements]] endif - // bool fValue = false; - fValue = false; - if (fExec) { - if (this.stack.length < 1) { - this.errstr = 'SCRIPT_ERR_UNBALANCED_CONDITIONAL'; - return false; - } - buf = this.stack.pop(); - fValue = Interpreter.castToBool(buf); - if (opcodenum === Opcode.OP_NOTIF) { - fValue = !fValue; - } - } - this.vfExec.push(fValue); - } - break; +function Random() { +} - case Opcode.OP_ELSE: - { - if (this.vfExec.length === 0) { - this.errstr = 'SCRIPT_ERR_UNBALANCED_CONDITIONAL'; - return false; - } - this.vfExec[this.vfExec.length - 1] = !this.vfExec[this.vfExec.length - 1]; - } - break; +/* secure random bytes that sometimes throws an error due to lack of entropy */ +Random.getRandomBuffer = function(size) { + if (process.browser) + return Random.getRandomBufferBrowser(size); + else + return Random.getRandomBufferNode(size); +}; - case Opcode.OP_ENDIF: - { - if (this.vfExec.length === 0) { - this.errstr = 'SCRIPT_ERR_UNBALANCED_CONDITIONAL'; - return false; - } - this.vfExec.pop(); - } - break; +Random.getRandomBufferNode = function(size) { + var crypto = require('crypto'); + return crypto.randomBytes(size); +}; - case Opcode.OP_VERIFY: - { - // (true -- ) or - // (false -- false) and return - if (this.stack.length < 1) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - buf = this.stack[this.stack.length - 1]; - fValue = Interpreter.castToBool(buf); - if (fValue) { - this.stack.pop(); - } else { - this.errstr = 'SCRIPT_ERR_VERIFY'; - return false; - } - } - break; +Random.getRandomBufferBrowser = function(size) { + if (!window.crypto && !window.msCrypto) + throw new Error('window.crypto not available'); - case Opcode.OP_RETURN: - { - this.errstr = 'SCRIPT_ERR_OP_RETURN'; - return false; - } - break; + if (window.crypto && window.crypto.getRandomValues) + var crypto = window.crypto; + else if (window.msCrypto && window.msCrypto.getRandomValues) //internet explorer + var crypto = window.msCrypto; + else + throw new Error('window.crypto.getRandomValues not available'); + var bbuf = new Uint8Array(size); + crypto.getRandomValues(bbuf); + var buf = new Buffer(bbuf); - // - // Stack ops - // - case Opcode.OP_TOALTSTACK: - { - if (this.stack.length < 1) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - this.altstack.push(this.stack.pop()); - } - break; + return buf; +}; - case Opcode.OP_FROMALTSTACK: - { - if (this.altstack.length < 1) { - this.errstr = 'SCRIPT_ERR_INVALID_ALTSTACK_OPERATION'; - return false; - } - this.stack.push(this.altstack.pop()); - } - break; +/* insecure random bytes, but it never fails */ +Random.getPseudoRandomBuffer = function(size) { + var b32 = 0x100000000; + var b = new Buffer(size); + var r; - case Opcode.OP_2DROP: - { - // (x1 x2 -- ) - if (this.stack.length < 2) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - this.stack.pop(); - this.stack.pop(); - } - break; + for (var i = 0; i <= size; i++) { + var j = Math.floor(i / 4); + var k = i - j * 4; + if (k === 0) { + r = Math.random() * b32; + b[i] = r & 0xff; + } else { + b[i] = (r = r >>> 8) & 0xff; + } + } - case Opcode.OP_2DUP: - { - // (x1 x2 -- x1 x2 x1 x2) - if (this.stack.length < 2) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - buf1 = this.stack[this.stack.length - 2]; - buf2 = this.stack[this.stack.length - 1]; - this.stack.push(buf1); - this.stack.push(buf2); - } - break; + return b; +}; - case Opcode.OP_3DUP: - { - // (x1 x2 x3 -- x1 x2 x3 x1 x2 x3) - if (this.stack.length < 3) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - buf1 = this.stack[this.stack.length - 3]; - buf2 = this.stack[this.stack.length - 2]; - var buf3 = this.stack[this.stack.length - 1]; - this.stack.push(buf1); - this.stack.push(buf2); - this.stack.push(buf3); - } - break; +module.exports = Random; - case Opcode.OP_2OVER: - { - // (x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2) - if (this.stack.length < 4) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - buf1 = this.stack[this.stack.length - 4]; - buf2 = this.stack[this.stack.length - 3]; - this.stack.push(buf1); - this.stack.push(buf2); - } - break; +}).call(this,require('_process'),require("buffer").Buffer) +},{"_process":357,"buffer":209,"crypto":213}],39:[function(require,module,exports){ +(function (Buffer){ +'use strict'; - case Opcode.OP_2ROT: - { - // (x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2) - if (this.stack.length < 6) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - spliced = this.stack.splice(this.stack.length - 6, 2); - this.stack.push(spliced[0]); - this.stack.push(spliced[1]); - } - break; +var BN = require('./bn'); +var _ = require('lodash'); +var $ = require('../util/preconditions'); +var BufferUtil = require('../util/buffer'); - case Opcode.OP_2SWAP: - { - // (x1 x2 x3 x4 -- x3 x4 x1 x2) - if (this.stack.length < 4) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - spliced = this.stack.splice(this.stack.length - 4, 2); - this.stack.push(spliced[0]); - this.stack.push(spliced[1]); - } - break; +var Signature = function Signature(r, s) { + if (!(this instanceof Signature)) { + return new Signature(r, s); + } + if (r instanceof BN) { + this.set({ + r: r, + s: s + }); + } else if (r) { + var obj = r; + this.set(obj); + } +}; - case Opcode.OP_IFDUP: - { - // (x - 0 | x x) - if (this.stack.length < 1) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - buf = this.stack[this.stack.length - 1]; - fValue = Interpreter.castToBool(buf); - if (fValue) { - this.stack.push(buf); - } - } - break; +/* jshint maxcomplexity: 7 */ +Signature.prototype.set = function(obj) { + this.r = obj.r || this.r || undefined; + this.s = obj.s || this.s || undefined; + this.i = typeof obj.i !== 'undefined' ? obj.i : this.i; //public key recovery parameter in range [0, 3] + this.compressed = typeof obj.compressed !== 'undefined' ? + obj.compressed : this.compressed; //whether the recovered pubkey is compressed + return this; +}; - case Opcode.OP_DEPTH: - { - // -- stacksize - buf = new BN(this.stack.length).toScriptNumBuffer(); - this.stack.push(buf); - } - break; +Signature.fromCompact = function(buf) { + var sig = new Signature(); + //TODO: handle uncompressed pubkeys + var compressed = true; + var i = buf.slice(0, 1)[0] - 27 - 4; + var b2 = buf.slice(1, 33); + var b3 = buf.slice(33, 65); - case Opcode.OP_DROP: - { - // (x -- ) - if (this.stack.length < 1) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - this.stack.pop(); - } - break; + $.checkArgument(i === 0 || i === 1 || i === 2 || i === 3, new Error('i must be 0, 1, 2, or 3')); + $.checkArgument(b2.length === 32, new Error('r must be 32 bytes')); + $.checkArgument(b3.length === 32, new Error('s must be 32 bytes')); - case Opcode.OP_DUP: - { - // (x -- x x) - if (this.stack.length < 1) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - this.stack.push(this.stack[this.stack.length - 1]); - } - break; + sig.compressed = compressed; + sig.i = i; + sig.r = BN.fromBuffer(b2); + sig.s = BN.fromBuffer(b3); - case Opcode.OP_NIP: - { - // (x1 x2 -- x2) - if (this.stack.length < 2) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - this.stack.splice(this.stack.length - 2, 1); - } - break; + return sig; +}; - case Opcode.OP_OVER: - { - // (x1 x2 -- x1 x2 x1) - if (this.stack.length < 2) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - this.stack.push(this.stack[this.stack.length - 2]); - } - break; +Signature.fromDER = Signature.fromBuffer = function(buf, strict) { + var obj = Signature.parseDER(buf, strict); + var sig = new Signature(); - case Opcode.OP_PICK: - case Opcode.OP_ROLL: - { - // (xn ... x2 x1 x0 n - xn ... x2 x1 x0 xn) - // (xn ... x2 x1 x0 n - ... x2 x1 x0 xn) - if (this.stack.length < 2) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - buf = this.stack[this.stack.length - 1]; - bn = BN.fromScriptNumBuffer(buf, fRequireMinimal); - n = bn.toNumber(); - this.stack.pop(); - if (n < 0 || n >= this.stack.length) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - buf = this.stack[this.stack.length - n - 1]; - if (opcodenum === Opcode.OP_ROLL) { - this.stack.splice(this.stack.length - n - 1, 1); - } - this.stack.push(buf); - } - break; + sig.r = obj.r; + sig.s = obj.s; - case Opcode.OP_ROT: - { - // (x1 x2 x3 -- x2 x3 x1) - // x2 x1 x3 after first swap - // x2 x3 x1 after second swap - if (this.stack.length < 3) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - x1 = this.stack[this.stack.length - 3]; - x2 = this.stack[this.stack.length - 2]; - var x3 = this.stack[this.stack.length - 1]; - this.stack[this.stack.length - 3] = x2; - this.stack[this.stack.length - 2] = x3; - this.stack[this.stack.length - 1] = x1; - } - break; + return sig; +}; - case Opcode.OP_SWAP: - { - // (x1 x2 -- x2 x1) - if (this.stack.length < 2) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - x1 = this.stack[this.stack.length - 2]; - x2 = this.stack[this.stack.length - 1]; - this.stack[this.stack.length - 2] = x2; - this.stack[this.stack.length - 1] = x1; - } - break; +// The format used in a tx +Signature.fromTxFormat = function(buf) { + var nhashtype = buf.readUInt8(buf.length - 1); + var derbuf = buf.slice(0, buf.length - 1); + var sig = new Signature.fromDER(derbuf, false); + sig.nhashtype = nhashtype; + return sig; +}; - case Opcode.OP_TUCK: - { - // (x1 x2 -- x2 x1 x2) - if (this.stack.length < 2) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - this.stack.splice(this.stack.length - 2, 0, this.stack[this.stack.length - 1]); - } - break; +Signature.fromString = function(str) { + var buf = new Buffer(str, 'hex'); + return Signature.fromDER(buf); +}; - case Opcode.OP_SIZE: - { - // (in -- in size) - if (this.stack.length < 1) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - bn = new BN(this.stack[this.stack.length - 1].length); - this.stack.push(bn.toScriptNumBuffer()); - } - break; +/** + * In order to mimic the non-strict DER encoding of OpenSSL, set strict = false. + */ +Signature.parseDER = function(buf, strict) { + $.checkArgument(BufferUtil.isBuffer(buf), new Error('DER formatted signature should be a buffer')); + if (_.isUndefined(strict)) { + strict = true; + } + var header = buf[0]; + $.checkArgument(header === 0x30, new Error('Header byte should be 0x30')); - // - // Bitwise logic - // - case Opcode.OP_EQUAL: - case Opcode.OP_EQUALVERIFY: - //case Opcode.OP_NOTEQUAL: // use Opcode.OP_NUMNOTEQUAL - { - // (x1 x2 - bool) - if (this.stack.length < 2) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - buf1 = this.stack[this.stack.length - 2]; - buf2 = this.stack[this.stack.length - 1]; - var fEqual = buf1.toString('hex') === buf2.toString('hex'); - this.stack.pop(); - this.stack.pop(); - this.stack.push(fEqual ? Interpreter.true : Interpreter.false); - if (opcodenum === Opcode.OP_EQUALVERIFY) { - if (fEqual) { - this.stack.pop(); - } else { - this.errstr = 'SCRIPT_ERR_EQUALVERIFY'; - return false; - } - } - } - break; + var length = buf[1]; + var buflength = buf.slice(2).length; + $.checkArgument(!strict || length === buflength, new Error('Length byte should length of what follows')); + length = length < buflength ? length : buflength; - // - // Numeric - // - case Opcode.OP_1ADD: - case Opcode.OP_1SUB: - case Opcode.OP_NEGATE: - case Opcode.OP_ABS: - case Opcode.OP_NOT: - case Opcode.OP_0NOTEQUAL: - { - // (in -- out) - if (this.stack.length < 1) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - buf = this.stack[this.stack.length - 1]; - bn = BN.fromScriptNumBuffer(buf, fRequireMinimal); - switch (opcodenum) { - case Opcode.OP_1ADD: - bn = bn.add(BN.One); - break; - case Opcode.OP_1SUB: - bn = bn.sub(BN.One); - break; - case Opcode.OP_NEGATE: - bn = bn.neg(); - break; - case Opcode.OP_ABS: - if (bn.cmp(BN.Zero) < 0) { - bn = bn.neg(); - } - break; - case Opcode.OP_NOT: - bn = new BN((bn.cmp(BN.Zero) === 0) + 0); - break; - case Opcode.OP_0NOTEQUAL: - bn = new BN((bn.cmp(BN.Zero) !== 0) + 0); - break; - //default: assert(!'invalid opcode'); break; // TODO: does this ever occur? - } - this.stack.pop(); - this.stack.push(bn.toScriptNumBuffer()); - } - break; + var rheader = buf[2 + 0]; + $.checkArgument(rheader === 0x02, new Error('Integer byte for r should be 0x02')); - case Opcode.OP_ADD: - case Opcode.OP_SUB: - case Opcode.OP_BOOLAND: - case Opcode.OP_BOOLOR: - case Opcode.OP_NUMEQUAL: - case Opcode.OP_NUMEQUALVERIFY: - case Opcode.OP_NUMNOTEQUAL: - case Opcode.OP_LESSTHAN: - case Opcode.OP_GREATERTHAN: - case Opcode.OP_LESSTHANOREQUAL: - case Opcode.OP_GREATERTHANOREQUAL: - case Opcode.OP_MIN: - case Opcode.OP_MAX: - { - // (x1 x2 -- out) - if (this.stack.length < 2) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - bn1 = BN.fromScriptNumBuffer(this.stack[this.stack.length - 2], fRequireMinimal); - bn2 = BN.fromScriptNumBuffer(this.stack[this.stack.length - 1], fRequireMinimal); - bn = new BN(0); + var rlength = buf[2 + 1]; + var rbuf = buf.slice(2 + 2, 2 + 2 + rlength); + var r = BN.fromBuffer(rbuf); + var rneg = buf[2 + 1 + 1] === 0x00 ? true : false; + $.checkArgument(rlength === rbuf.length, new Error('Length of r incorrect')); - switch (opcodenum) { - case Opcode.OP_ADD: - bn = bn1.add(bn2); - break; + var sheader = buf[2 + 2 + rlength + 0]; + $.checkArgument(sheader === 0x02, new Error('Integer byte for s should be 0x02')); - case Opcode.OP_SUB: - bn = bn1.sub(bn2); - break; + var slength = buf[2 + 2 + rlength + 1]; + var sbuf = buf.slice(2 + 2 + rlength + 2, 2 + 2 + rlength + 2 + slength); + var s = BN.fromBuffer(sbuf); + var sneg = buf[2 + 2 + rlength + 2 + 2] === 0x00 ? true : false; + $.checkArgument(slength === sbuf.length, new Error('Length of s incorrect')); - // case Opcode.OP_BOOLAND: bn = (bn1 != bnZero && bn2 != bnZero); break; - case Opcode.OP_BOOLAND: - bn = new BN(((bn1.cmp(BN.Zero) !== 0) && (bn2.cmp(BN.Zero) !== 0)) + 0); - break; - // case Opcode.OP_BOOLOR: bn = (bn1 != bnZero || bn2 != bnZero); break; - case Opcode.OP_BOOLOR: - bn = new BN(((bn1.cmp(BN.Zero) !== 0) || (bn2.cmp(BN.Zero) !== 0)) + 0); - break; - // case Opcode.OP_NUMEQUAL: bn = (bn1 == bn2); break; - case Opcode.OP_NUMEQUAL: - bn = new BN((bn1.cmp(bn2) === 0) + 0); - break; - // case Opcode.OP_NUMEQUALVERIFY: bn = (bn1 == bn2); break; - case Opcode.OP_NUMEQUALVERIFY: - bn = new BN((bn1.cmp(bn2) === 0) + 0); - break; - // case Opcode.OP_NUMNOTEQUAL: bn = (bn1 != bn2); break; - case Opcode.OP_NUMNOTEQUAL: - bn = new BN((bn1.cmp(bn2) !== 0) + 0); - break; - // case Opcode.OP_LESSTHAN: bn = (bn1 < bn2); break; - case Opcode.OP_LESSTHAN: - bn = new BN((bn1.cmp(bn2) < 0) + 0); - break; - // case Opcode.OP_GREATERTHAN: bn = (bn1 > bn2); break; - case Opcode.OP_GREATERTHAN: - bn = new BN((bn1.cmp(bn2) > 0) + 0); - break; - // case Opcode.OP_LESSTHANOREQUAL: bn = (bn1 <= bn2); break; - case Opcode.OP_LESSTHANOREQUAL: - bn = new BN((bn1.cmp(bn2) <= 0) + 0); - break; - // case Opcode.OP_GREATERTHANOREQUAL: bn = (bn1 >= bn2); break; - case Opcode.OP_GREATERTHANOREQUAL: - bn = new BN((bn1.cmp(bn2) >= 0) + 0); - break; - case Opcode.OP_MIN: - bn = (bn1.cmp(bn2) < 0 ? bn1 : bn2); - break; - case Opcode.OP_MAX: - bn = (bn1.cmp(bn2) > 0 ? bn1 : bn2); - break; - // default: assert(!'invalid opcode'); break; //TODO: does this ever occur? - } - this.stack.pop(); - this.stack.pop(); - this.stack.push(bn.toScriptNumBuffer()); + var sumlength = 2 + 2 + rlength + 2 + slength; + $.checkArgument(length === sumlength - 2, new Error('Length of signature incorrect')); - if (opcodenum === Opcode.OP_NUMEQUALVERIFY) { - // if (CastToBool(stacktop(-1))) - if (Interpreter.castToBool(this.stack[this.stack.length - 1])) { - this.stack.pop(); - } else { - this.errstr = 'SCRIPT_ERR_NUMEQUALVERIFY'; - return false; - } - } - } - break; + var obj = { + header: header, + length: length, + rheader: rheader, + rlength: rlength, + rneg: rneg, + rbuf: rbuf, + r: r, + sheader: sheader, + slength: slength, + sneg: sneg, + sbuf: sbuf, + s: s + }; - case Opcode.OP_WITHIN: - { - // (x min max -- out) - if (this.stack.length < 3) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - bn1 = BN.fromScriptNumBuffer(this.stack[this.stack.length - 3], fRequireMinimal); - bn2 = BN.fromScriptNumBuffer(this.stack[this.stack.length - 2], fRequireMinimal); - var bn3 = BN.fromScriptNumBuffer(this.stack[this.stack.length - 1], fRequireMinimal); - //bool fValue = (bn2 <= bn1 && bn1 < bn3); - fValue = (bn2.cmp(bn1) <= 0) && (bn1.cmp(bn3) < 0); - this.stack.pop(); - this.stack.pop(); - this.stack.pop(); - this.stack.push(fValue ? Interpreter.true : Interpreter.false); - } - break; + return obj; +}; - // - // Crypto - // - case Opcode.OP_RIPEMD160: - case Opcode.OP_SHA1: - case Opcode.OP_SHA256: - case Opcode.OP_HASH160: - case Opcode.OP_HASH256: - { - // (in -- hash) - if (this.stack.length < 1) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - buf = this.stack[this.stack.length - 1]; - //valtype vchHash((opcode == Opcode.OP_RIPEMD160 || - // opcode == Opcode.OP_SHA1 || opcode == Opcode.OP_HASH160) ? 20 : 32); - var bufHash; - if (opcodenum === Opcode.OP_RIPEMD160) { - bufHash = Hash.ripemd160(buf); - } else if (opcodenum === Opcode.OP_SHA1) { - bufHash = Hash.sha1(buf); - } else if (opcodenum === Opcode.OP_SHA256) { - bufHash = Hash.sha256(buf); - } else if (opcodenum === Opcode.OP_HASH160) { - bufHash = Hash.sha256ripemd160(buf); - } else if (opcodenum === Opcode.OP_HASH256) { - bufHash = Hash.sha256sha256(buf); - } - this.stack.pop(); - this.stack.push(bufHash); - } - break; +Signature.prototype.toCompact = function(i, compressed) { + i = typeof i === 'number' ? i : this.i; + compressed = typeof compressed === 'boolean' ? compressed : this.compressed; - case Opcode.OP_CODESEPARATOR: - { - // Hash starts after the code separator - this.pbegincodehash = this.pc; - } - break; + if (!(i === 0 || i === 1 || i === 2 || i === 3)) { + throw new Error('i must be equal to 0, 1, 2, or 3'); + } - case Opcode.OP_CHECKSIG: - case Opcode.OP_CHECKSIGVERIFY: - { - // (sig pubkey -- bool) - if (this.stack.length < 2) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } + var val = i + 27 + 4; + if (compressed === false) + val = val - 4; + var b1 = new Buffer([val]); + var b2 = this.r.toBuffer({ + size: 32 + }); + var b3 = this.s.toBuffer({ + size: 32 + }); + return Buffer.concat([b1, b2, b3]); +}; - bufSig = this.stack[this.stack.length - 2]; - bufPubkey = this.stack[this.stack.length - 1]; +Signature.prototype.toBuffer = Signature.prototype.toDER = function() { + var rnbuf = this.r.toBuffer(); + var snbuf = this.s.toBuffer(); - // Subset of script starting at the most recent codeseparator - // CScript scriptCode(pbegincodehash, pend); - subscript = new Script().set({ - chunks: this.script.chunks.slice(this.pbegincodehash) - }); + var rneg = rnbuf[0] & 0x80 ? true : false; + var sneg = snbuf[0] & 0x80 ? true : false; - // Drop the signature, since there's no way for a signature to sign itself - var tmpScript = new Script().add(bufSig); - subscript.findAndDelete(tmpScript); + var rbuf = rneg ? Buffer.concat([new Buffer([0x00]), rnbuf]) : rnbuf; + var sbuf = sneg ? Buffer.concat([new Buffer([0x00]), snbuf]) : snbuf; - if (!this.checkSignatureEncoding(bufSig) || !this.checkPubkeyEncoding(bufPubkey)) { - return false; - } + var rlength = rbuf.length; + var slength = sbuf.length; + var length = 2 + rlength + 2 + slength; + var rheader = 0x02; + var sheader = 0x02; + var header = 0x30; - try { - sig = Signature.fromTxFormat(bufSig); - pubkey = PublicKey.fromBuffer(bufPubkey, false); - fSuccess = this.tx.verifySignature(sig, pubkey, this.nin, subscript); - } catch (e) { - //invalid sig or pubkey - fSuccess = false; - } + var der = Buffer.concat([new Buffer([header, length, rheader, rlength]), rbuf, new Buffer([sheader, slength]), sbuf]); + return der; +}; - this.stack.pop(); - this.stack.pop(); - // stack.push_back(fSuccess ? vchTrue : vchFalse); - this.stack.push(fSuccess ? Interpreter.true : Interpreter.false); - if (opcodenum === Opcode.OP_CHECKSIGVERIFY) { - if (fSuccess) { - this.stack.pop(); - } else { - this.errstr = 'SCRIPT_ERR_CHECKSIGVERIFY'; - return false; - } - } - } - break; +Signature.prototype.toString = function() { + var buf = this.toDER(); + return buf.toString('hex'); +}; - case Opcode.OP_CHECKMULTISIG: - case Opcode.OP_CHECKMULTISIGVERIFY: - { - // ([sig ...] num_of_signatures [pubkey ...] num_of_pubkeys -- bool) +/** + * This function is translated from bitcoind's IsDERSignature and is used in + * the script interpreter. This "DER" format actually includes an extra byte, + * the nhashtype, at the end. It is really the tx format, not DER format. + * + * A canonical signature exists of: [30] [total len] [02] [len R] [R] [02] [len S] [S] [hashtype] + * Where R and S are not negative (their first byte has its highest bit not set), and not + * excessively padded (do not start with a 0 byte, unless an otherwise negative number follows, + * in which case a single 0 byte is necessary and even required). + * + * See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623 + */ +Signature.isTxDER = function(buf) { + if (buf.length < 9) { + // Non-canonical signature: too short + return false; + } + if (buf.length > 73) { + // Non-canonical signature: too long + return false; + } + if (buf[0] !== 0x30) { + // Non-canonical signature: wrong type + return false; + } + if (buf[1] !== buf.length - 3) { + // Non-canonical signature: wrong length marker + return false; + } + var nLenR = buf[3]; + if (5 + nLenR >= buf.length) { + // Non-canonical signature: S length misplaced + return false; + } + var nLenS = buf[5 + nLenR]; + if ((nLenR + nLenS + 7) !== buf.length) { + // Non-canonical signature: R+S length mismatch + return false; + } - var i = 1; - if (this.stack.length < i) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } + var R = buf.slice(4); + if (buf[4 - 2] !== 0x02) { + // Non-canonical signature: R value type mismatch + return false; + } + if (nLenR === 0) { + // Non-canonical signature: R length is zero + return false; + } + if (R[0] & 0x80) { + // Non-canonical signature: R value negative + return false; + } + if (nLenR > 1 && (R[0] === 0x00) && !(R[1] & 0x80)) { + // Non-canonical signature: R value excessively padded + return false; + } - var nKeysCount = BN.fromScriptNumBuffer(this.stack[this.stack.length - i], fRequireMinimal).toNumber(); - if (nKeysCount < 0 || nKeysCount > 20) { - this.errstr = 'SCRIPT_ERR_PUBKEY_COUNT'; - return false; - } - this.nOpCount += nKeysCount; - if (this.nOpCount > 201) { - this.errstr = 'SCRIPT_ERR_OP_COUNT'; - return false; - } - // int ikey = ++i; - var ikey = ++i; - i += nKeysCount; - if (this.stack.length < i) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } + var S = buf.slice(6 + nLenR); + if (buf[6 + nLenR - 2] !== 0x02) { + // Non-canonical signature: S value type mismatch + return false; + } + if (nLenS === 0) { + // Non-canonical signature: S length is zero + return false; + } + if (S[0] & 0x80) { + // Non-canonical signature: S value negative + return false; + } + if (nLenS > 1 && (S[0] === 0x00) && !(S[1] & 0x80)) { + // Non-canonical signature: S value excessively padded + return false; + } + return true; +}; - var nSigsCount = BN.fromScriptNumBuffer(this.stack[this.stack.length - i], fRequireMinimal).toNumber(); - if (nSigsCount < 0 || nSigsCount > nKeysCount) { - this.errstr = 'SCRIPT_ERR_SIG_COUNT'; - return false; - } - // int isig = ++i; - var isig = ++i; - i += nSigsCount; - if (this.stack.length < i) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } +/** + * Compares to bitcoind's IsLowDERSignature + * See also ECDSA signature algorithm which enforces this. + * See also BIP 62, "low S values in signatures" + */ +Signature.prototype.hasLowS = function() { + if (this.s.lt(new BN(1)) || + this.s.gt(new BN('7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0'))) { + return false; + } + return true; +}; - // Subset of script starting at the most recent codeseparator - subscript = new Script().set({ - chunks: this.script.chunks.slice(this.pbegincodehash) - }); +/** + * @returns true if the nhashtype is exactly equal to one of the standard options or combinations thereof. + * Translated from bitcoind's IsDefinedHashtypeSignature + */ +Signature.prototype.hasDefinedHashtype = function() { + if (this.nhashtype < Signature.SIGHASH_ALL || this.nhashtype > Signature.SIGHASH_SINGLE) { + return false; + } + return true; +}; - // Drop the signatures, since there's no way for a signature to sign itself - for (var k = 0; k < nSigsCount; k++) { - bufSig = this.stack[this.stack.length - isig - k]; - subscript.findAndDelete(new Script().add(bufSig)); - } +Signature.prototype.toTxFormat = function() { + var derbuf = this.toDER(); + var buf = new Buffer(1); + buf.writeUInt8(this.nhashtype, 0); + return Buffer.concat([derbuf, buf]); +}; - fSuccess = true; - while (fSuccess && nSigsCount > 0) { - // valtype& vchSig = stacktop(-isig); - bufSig = this.stack[this.stack.length - isig]; - // valtype& vchPubKey = stacktop(-ikey); - bufPubkey = this.stack[this.stack.length - ikey]; +Signature.SIGHASH_ALL = 0x01; +Signature.SIGHASH_NONE = 0x02; +Signature.SIGHASH_SINGLE = 0x03; +Signature.SIGHASH_ANYONECANPAY = 0x80; - if (!this.checkSignatureEncoding(bufSig) || !this.checkPubkeyEncoding(bufPubkey)) { - return false; - } +module.exports = Signature; - var fOk; - try { - sig = Signature.fromTxFormat(bufSig); - pubkey = PublicKey.fromBuffer(bufPubkey, false); - fOk = this.tx.verifySignature(sig, pubkey, this.nin, subscript); - } catch (e) { - //invalid sig or pubkey - fOk = false; - } +}).call(this,require("buffer").Buffer) +},{"../util/buffer":69,"../util/preconditions":71,"./bn":34,"buffer":209,"lodash":95}],40:[function(require,module,exports){ +(function (Buffer){ +'use strict'; - if (fOk) { - isig++; - nSigsCount--; - } - ikey++; - nKeysCount--; +var _ = require('lodash'); +var bs58 = require('bs58'); +var buffer = require('buffer'); - // If there are more signatures left than keys left, - // then too many signatures have failed - if (nSigsCount > nKeysCount) { - fSuccess = false; - } - } +var ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'.split(''); - // Clean up stack of actual arguments - while (i-- > 1) { - this.stack.pop(); - } +var Base58 = function Base58(obj) { + /* jshint maxcomplexity: 8 */ + if (!(this instanceof Base58)) { + return new Base58(obj); + } + if (Buffer.isBuffer(obj)) { + var buf = obj; + this.fromBuffer(buf); + } else if (typeof obj === 'string') { + var str = obj; + this.fromString(str); + } else if (obj) { + this.set(obj); + } +}; - // A bug causes CHECKMULTISIG to consume one extra argument - // whose contents were not checked in any way. - // - // Unfortunately this is a potential source of mutability, - // so optionally verify it is exactly equal to zero prior - // to removing it from the stack. - if (this.stack.length < 1) { - this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; - return false; - } - if ((this.flags & Interpreter.SCRIPT_VERIFY_NULLDUMMY) && this.stack[this.stack.length - 1].length) { - this.errstr = 'SCRIPT_ERR_SIG_NULLDUMMY'; - return false; - } - this.stack.pop(); +Base58.validCharacters = function validCharacters(chars) { + if (buffer.Buffer.isBuffer(chars)) { + chars = chars.toString(); + } + return _.all(_.map(chars, function(char) { return _.contains(ALPHABET, char); })); +}; - this.stack.push(fSuccess ? Interpreter.true : Interpreter.false); +Base58.prototype.set = function(obj) { + this.buf = obj.buf || this.buf || undefined; + return this; +}; - if (opcodenum === Opcode.OP_CHECKMULTISIGVERIFY) { - if (fSuccess) { - this.stack.pop(); - } else { - this.errstr = 'SCRIPT_ERR_CHECKMULTISIGVERIFY'; - return false; - } - } - } - break; +Base58.encode = function(buf) { + if (!buffer.Buffer.isBuffer(buf)) { + throw new Error('Input should be a buffer'); + } + return bs58.encode(buf); +}; - default: - this.errstr = 'SCRIPT_ERR_BAD_OPCODE'; - return false; - } +Base58.decode = function(str) { + if (typeof str !== 'string') { + throw new Error('Input should be a string'); } + return new Buffer(bs58.decode(str)); +}; - return true; +Base58.prototype.fromBuffer = function(buf) { + this.buf = buf; + return this; +}; + +Base58.prototype.fromString = function(str) { + var buf = Base58.decode(str); + this.buf = buf; + return this; +}; + +Base58.prototype.toBuffer = function() { + return this.buf; +}; + +Base58.prototype.toString = function() { + return Base58.encode(this.buf); }; +module.exports = Base58; }).call(this,require("buffer").Buffer) -},{"../crypto/bn":18,"../crypto/hash":20,"../crypto/signature":23,"../opcode":35,"../publickey":37,"../transaction":41,"./script":40,"buffer":104,"lodash":79}],40:[function(require,module,exports){ +},{"bs58":73,"buffer":209,"lodash":95}],41:[function(require,module,exports){ (function (Buffer){ 'use strict'; - -var Address = require('../address'); -var BufferReader = require('../encoding/bufferreader'); -var BufferWriter = require('../encoding/bufferwriter'); -var Hash = require('../crypto/hash'); -var Opcode = require('../opcode'); -var PublicKey = require('../publickey'); -var Signature = require('../crypto/signature'); -var Networks = require('../networks'); - -var $ = require('../util/preconditions'); var _ = require('lodash'); -var errors = require('../errors'); +var Base58 = require('./base58'); var buffer = require('buffer'); -var BufferUtil = require('../util/buffer'); -var JSUtil = require('../util/js'); - -/** - * A bitcoin transaction script. Each transaction's inputs and outputs - * has a script that is evaluated to validate it's spending. - * - * See https://en.bitcoin.it/wiki/Script - * - * @constructor - * @param {Object|string|Buffer=} from optional data to populate script - */ -var Script = function Script(from) { - if (!(this instanceof Script)) { - return new Script(from); - } - - this.chunks = []; +var sha256sha256 = require('../crypto/hash').sha256sha256; - if (BufferUtil.isBuffer(from)) { - return Script.fromBuffer(from); - } else if (from instanceof Address) { - return Script.fromAddress(from); - } else if (from instanceof Script) { - return Script.fromBuffer(from.toBuffer()); - } else if (typeof from === 'string') { - return Script.fromString(from); - } else if (typeof from !== 'undefined') { - this.set(from); +var Base58Check = function Base58Check(obj) { + if (!(this instanceof Base58Check)) + return new Base58Check(obj); + if (Buffer.isBuffer(obj)) { + var buf = obj; + this.fromBuffer(buf); + } else if (typeof obj === 'string') { + var str = obj; + this.fromString(str); + } else if (obj) { + this.set(obj); } }; -Script.prototype.set = function(obj) { - this.chunks = obj.chunks || this.chunks; +Base58Check.prototype.set = function(obj) { + this.buf = obj.buf || this.buf || undefined; return this; }; -Script.fromBuffer = function(buffer) { - var script = new Script(); - script.chunks = []; +Base58Check.validChecksum = function validChecksum(data, checksum) { + if (_.isString(data)) { + data = new buffer.Buffer(Base58.decode(data)); + } + if (_.isString(checksum)) { + checksum = new buffer.Buffer(Base58.decode(checksum)); + } + if (!checksum) { + checksum = data.slice(-4); + data = data.slice(0, -4); + } + return Base58Check.checksum(data).toString('hex') === checksum.toString('hex'); +}; - var br = new BufferReader(buffer); - while (!br.finished()) { - var opcodenum = br.readUInt8(); +Base58Check.decode = function(s) { + if (typeof s !== 'string') + throw new Error('Input must be a string'); - var len, buf; - if (opcodenum > 0 && opcodenum < Opcode.OP_PUSHDATA1) { - len = opcodenum; - script.chunks.push({ - buf: br.read(len), - len: len, - opcodenum: opcodenum - }); - } else if (opcodenum === Opcode.OP_PUSHDATA1) { - len = br.readUInt8(); - buf = br.read(len); - script.chunks.push({ - buf: buf, - len: len, - opcodenum: opcodenum - }); - } else if (opcodenum === Opcode.OP_PUSHDATA2) { - len = br.readUInt16LE(); - buf = br.read(len); - script.chunks.push({ - buf: buf, - len: len, - opcodenum: opcodenum - }); - } else if (opcodenum === Opcode.OP_PUSHDATA4) { - len = br.readUInt32LE(); - buf = br.read(len); - script.chunks.push({ - buf: buf, - len: len, - opcodenum: opcodenum - }); - } else { - script.chunks.push({ - opcodenum: opcodenum - }); - } - } + var buf = new Buffer(Base58.decode(s)); - return script; -}; + if (buf.length < 4) + throw new Error("Input string too short"); -Script.prototype.toBuffer = function() { - var bw = new BufferWriter(); + var data = buf.slice(0, -4); + var csum = buf.slice(-4); - for (var i = 0; i < this.chunks.length; i++) { - var chunk = this.chunks[i]; - var opcodenum = chunk.opcodenum; - bw.writeUInt8(chunk.opcodenum); - if (chunk.buf) { - if (opcodenum < Opcode.OP_PUSHDATA1) { - bw.write(chunk.buf); - } else if (opcodenum === Opcode.OP_PUSHDATA1) { - bw.writeUInt8(chunk.len); - bw.write(chunk.buf); - } else if (opcodenum === Opcode.OP_PUSHDATA2) { - bw.writeUInt16LE(chunk.len); - bw.write(chunk.buf); - } else if (opcodenum === Opcode.OP_PUSHDATA4) { - bw.writeUInt32LE(chunk.len); - bw.write(chunk.buf); - } - } - } + var hash = sha256sha256(data); + var hash4 = hash.slice(0, 4); - return bw.concat(); + if (csum.toString('hex') !== hash4.toString('hex')) + throw new Error("Checksum mismatch"); + + return data; }; -Script.fromString = function(str) { - if (JSUtil.isHexa(str) || str.length === 0) { - return new Script(new buffer.Buffer(str, 'hex')); - } - var script = new Script(); - script.chunks = []; +Base58Check.checksum = function(buffer) { + return sha256sha256(buffer).slice(0, 4); +}; - var tokens = str.split(' '); - var i = 0; - while (i < tokens.length) { - var token = tokens[i]; - var opcode = Opcode(token); - var opcodenum = opcode.toNumber(); +Base58Check.encode = function(buf) { + if (!Buffer.isBuffer(buf)) + throw new Error('Input must be a buffer'); + var checkedBuf = new Buffer(buf.length + 4); + var hash = Base58Check.checksum(buf); + buf.copy(checkedBuf); + hash.copy(checkedBuf, buf.length); + return Base58.encode(checkedBuf); +}; - if (_.isUndefined(opcodenum)) { - opcodenum = parseInt(token); - if (opcodenum > 0 && opcodenum < Opcode.OP_PUSHDATA1) { - script.chunks.push({ - buf: new Buffer(tokens[i + 1].slice(2), 'hex'), - len: opcodenum, - opcodenum: opcodenum - }); - i = i + 2; - } else { - throw new Error('Invalid script: ' + JSON.stringify(str)); - } - } else if (opcodenum === Opcode.OP_PUSHDATA1 || - opcodenum === Opcode.OP_PUSHDATA2 || - opcodenum === Opcode.OP_PUSHDATA4) { - if (tokens[i + 2].slice(0, 2) !== '0x') { - throw new Error('Pushdata data must start with 0x'); - } - script.chunks.push({ - buf: new Buffer(tokens[i + 2].slice(2), 'hex'), - len: parseInt(tokens[i + 1]), - opcodenum: opcodenum - }); - i = i + 3; - } else { - script.chunks.push({ - opcodenum: opcodenum - }); - i = i + 1; - } - } - return script; +Base58Check.prototype.fromBuffer = function(buf) { + this.buf = buf; + return this; }; -Script.prototype.toString = function() { - var str = ''; - for (var i = 0; i < this.chunks.length; i++) { - var chunk = this.chunks[i]; - var opcodenum = chunk.opcodenum; - if (!chunk.buf) { - if (typeof Opcode.reverseMap[opcodenum] !== 'undefined') { - str = str + ' ' + Opcode(opcodenum).toString(); - } else { - var numstr = opcodenum.toString(16); - if (numstr.length % 2 !== 0) { - numstr = '0' + numstr; - } - str = str + ' ' + '0x' + numstr; - } - } else { - if (opcodenum === Opcode.OP_PUSHDATA1 || - opcodenum === Opcode.OP_PUSHDATA2 || - opcodenum === Opcode.OP_PUSHDATA4) { - str = str + ' ' + Opcode(opcodenum).toString(); - } - str = str + ' ' + chunk.len; - if (chunk.len > 0) { - str = str + ' ' + '0x' + chunk.buf.toString('hex'); - } - } - } +Base58Check.prototype.fromString = function(str) { + var buf = Base58Check.decode(str); + this.buf = buf; + return this; +}; - return str.substr(1); +Base58Check.prototype.toBuffer = function() { + return this.buf; }; -Script.prototype.toHex = function() { - return this.toBuffer().toString('hex'); +Base58Check.prototype.toString = function() { + return Base58Check.encode(this.buf); }; -Script.prototype.inspect = function() { - return ''; +module.exports = Base58Check; + +}).call(this,require("buffer").Buffer) +},{"../crypto/hash":36,"./base58":40,"buffer":209,"lodash":95}],42:[function(require,module,exports){ +(function (Buffer){ +'use strict'; + +var _ = require('lodash'); +var $ = require('../util/preconditions'); +var BufferUtil = require('../util/buffer'); +var BN = require('../crypto/bn'); + +var BufferReader = function BufferReader(buf) { + if (!(this instanceof BufferReader)) { + return new BufferReader(buf); + } + if (Buffer.isBuffer(buf)) { + this.set({ + buf: buf + }); + } else if (buf) { + var obj = buf; + this.set(obj); + } }; -// script classification methods +BufferReader.prototype.set = function(obj) { + this.buf = obj.buf || this.buf || undefined; + this.pos = obj.pos || this.pos || 0; + return this; +}; -/** - * @returns {boolean} if this is a pay to pubkey hash output script - */ -Script.prototype.isPublicKeyHashOut = function() { - return !!(this.chunks.length === 5 && - this.chunks[0].opcodenum === Opcode.OP_DUP && - this.chunks[1].opcodenum === Opcode.OP_HASH160 && - this.chunks[2].buf && - this.chunks[3].opcodenum === Opcode.OP_EQUALVERIFY && - this.chunks[4].opcodenum === Opcode.OP_CHECKSIG); +BufferReader.prototype.eof = function() { + return this.pos >= this.buf.length; }; -/** - * @returns {boolean} if this is a pay to public key hash input script - */ -Script.prototype.isPublicKeyHashIn = function() { - return this.chunks.length === 2 && - this.chunks[0].buf && - this.chunks[0].buf.length >= 0x47 && - this.chunks[0].buf.length <= 0x49 && - PublicKey.isValid(this.chunks[1].buf); +BufferReader.prototype.finished = BufferReader.prototype.eof; + +BufferReader.prototype.read = function(len) { + $.checkArgument(!_.isUndefined(len), 'Must specify a length'); + var buf = this.buf.slice(this.pos, this.pos + len); + this.pos = this.pos + len; + return buf; }; -Script.prototype.getPublicKeyHash = function() { - $.checkState(this.isPublicKeyHashOut(), 'Can\'t retrieve PublicKeyHash from a non-PKH output'); - return this.chunks[2].buf; +BufferReader.prototype.readAll = function() { + var buf = this.buf.slice(this.pos, this.buf.length); + this.pos = this.buf.length; + return buf; }; -/** - * @returns {boolean} if this is a public key output script - */ -Script.prototype.isPublicKeyOut = function() { - return this.chunks.length === 2 && - BufferUtil.isBuffer(this.chunks[0].buf) && - PublicKey.isValid(this.chunks[0].buf) && - this.chunks[1].opcodenum === Opcode.OP_CHECKSIG; +BufferReader.prototype.readUInt8 = function() { + var val = this.buf.readUInt8(this.pos); + this.pos = this.pos + 1; + return val; }; -/** - * @returns {boolean} if this is a pay to public key input script - */ -Script.prototype.isPublicKeyIn = function() { - return this.chunks.length === 1 && - BufferUtil.isBuffer(this.chunks[0].buf) && - this.chunks[0].buf.length === 0x47; +BufferReader.prototype.readUInt16BE = function() { + var val = this.buf.readUInt16BE(this.pos); + this.pos = this.pos + 2; + return val; }; +BufferReader.prototype.readUInt16LE = function() { + var val = this.buf.readUInt16LE(this.pos); + this.pos = this.pos + 2; + return val; +}; -/** - * @returns {boolean} if this is a p2sh output script - */ -Script.prototype.isScriptHashOut = function() { - var buf = this.toBuffer(); - return (buf.length === 23 && - buf[0] === Opcode.OP_HASH160 && - buf[1] === 0x14 && - buf[buf.length - 1] === Opcode.OP_EQUAL); +BufferReader.prototype.readUInt32BE = function() { + var val = this.buf.readUInt32BE(this.pos); + this.pos = this.pos + 4; + return val; }; -/** - * @returns {boolean} if this is a p2sh input script - * Note that these are frequently indistinguishable from pubkeyhashin - */ -Script.prototype.isScriptHashIn = function() { - if (this.chunks.length === 0) { - return false; - } - var chunk = this.chunks[this.chunks.length - 1]; - if (!chunk) { - return false; - } - var scriptBuf = chunk.buf; - if (!scriptBuf) { - return false; - } - var redeemScript = new Script(scriptBuf); - var type = redeemScript.classify(); - return type !== Script.types.UNKNOWN; +BufferReader.prototype.readUInt32LE = function() { + var val = this.buf.readUInt32LE(this.pos); + this.pos = this.pos + 4; + return val; }; -/** - * @returns {boolean} if this is a mutlsig output script - */ -Script.prototype.isMultisigOut = function() { - return (this.chunks.length > 3 && - Opcode.isSmallIntOp(this.chunks[0].opcodenum) && - this.chunks.slice(1, this.chunks.length - 2).every(function(obj) { - return obj.buf && BufferUtil.isBuffer(obj.buf); - }) && - Opcode.isSmallIntOp(this.chunks[this.chunks.length - 2].opcodenum) && - this.chunks[this.chunks.length - 1].opcodenum === Opcode.OP_CHECKMULTISIG); +BufferReader.prototype.readUInt64BEBN = function() { + var buf = this.buf.slice(this.pos, this.pos + 8); + var bn = BN.fromBuffer(buf); + this.pos = this.pos + 8; + return bn; }; +BufferReader.prototype.readUInt64LEBN = function() { + var buf = this.buf.slice(this.pos, this.pos + 8); + var reversebuf = BufferReader({ + buf: buf + }).readReverse(); + var bn = BN.fromBuffer(reversebuf); + this.pos = this.pos + 8; + return bn; +}; -/** - * @returns {boolean} if this is a multisig input script - */ -Script.prototype.isMultisigIn = function() { - return this.chunks.length >= 2 && - this.chunks[0].opcodenum === 0 && - this.chunks.slice(1, this.chunks.length).every(function(obj) { - return obj.buf && - BufferUtil.isBuffer(obj.buf) && - obj.buf.length === 0x47; - }); +BufferReader.prototype.readVarintNum = function() { + var first = this.readUInt8(); + switch (first) { + case 0xFD: + return this.readUInt16LE(); + case 0xFE: + return this.readUInt32LE(); + case 0xFF: + var bn = this.readUInt64LEBN(); + var n = bn.toNumber(); + if (n <= Math.pow(2, 53)) { + return n; + } else { + throw new Error('number too large to retain precision - use readVarintBN'); + } + break; + default: + return first; + } }; /** - * @returns {boolean} true if this is a valid standard OP_RETURN output + * reads a length prepended buffer */ -Script.prototype.isDataOut = function() { - return this.chunks.length >= 1 && - this.chunks[0].opcodenum === Opcode.OP_RETURN && - (this.chunks.length === 1 || - (this.chunks.length === 2 && - this.chunks[1].buf && - this.chunks[1].buf.length <= Script.OP_RETURN_STANDARD_SIZE && - this.chunks[1].length === this.chunks.len)); +BufferReader.prototype.readVarLengthBuffer = function() { + var len = this.readVarintNum(); + var buf = this.read(len); + $.checkState(buf.length === len, 'Invalid length while reading varlength buffer. ' + + 'Expected to read: ' + len + ' and read ' + buf.length); + return buf; }; -/** - * Retrieve the associated data for this script. - * In the case of a pay to public key hash or P2SH, return the hash. - * In the case of a standard OP_RETURN, return the data - * @returns {Buffer} - */ -Script.prototype.getData = function() { - if (this.isDataOut() || this.isScriptHashOut()) { - return new Buffer(this.chunks[1].buf); +BufferReader.prototype.readVarintBuf = function() { + var first = this.buf.readUInt8(this.pos); + switch (first) { + case 0xFD: + return this.read(1 + 2); + case 0xFE: + return this.read(1 + 4); + case 0xFF: + return this.read(1 + 8); + default: + return this.read(1); } - if (this.isPublicKeyHashOut()) { - return new Buffer(this.chunks[2].buf); +}; + +BufferReader.prototype.readVarintBN = function() { + var first = this.readUInt8(); + switch (first) { + case 0xFD: + return new BN(this.readUInt16LE()); + case 0xFE: + return new BN(this.readUInt32LE()); + case 0xFF: + return this.readUInt64LEBN(); + default: + return new BN(first); } - throw new Error('Unrecognized script type to get data from'); }; -/** - * @returns {boolean} if the script is only composed of data pushing - * opcodes or small int opcodes (OP_0, OP_1, ..., OP_16) - */ -Script.prototype.isPushOnly = function() { - return _.every(this.chunks, function(chunk) { - return chunk.opcodenum <= Opcode.OP_16; - }); +BufferReader.prototype.reverse = function() { + var buf = new Buffer(this.buf.length); + for (var i = 0; i < buf.length; i++) { + buf[i] = this.buf[this.buf.length - 1 - i]; + } + this.buf = buf; + return this; }; +BufferReader.prototype.readReverse = function(len) { + if (_.isUndefined(len)) { + len = this.buf.length; + } + var buf = this.buf.slice(this.pos, this.pos + len); + this.pos = this.pos + len; + return BufferUtil.reverse(buf); +}; -Script.types = {}; -Script.types.UNKNOWN = 'Unknown'; -Script.types.PUBKEY_OUT = 'Pay to public key'; -Script.types.PUBKEY_IN = 'Spend from public key'; -Script.types.PUBKEYHASH_OUT = 'Pay to public key hash'; -Script.types.PUBKEYHASH_IN = 'Spend from public key hash'; -Script.types.SCRIPTHASH_OUT = 'Pay to script hash'; -Script.types.SCRIPTHASH_IN = 'Spend from script hash'; -Script.types.MULTISIG_OUT = 'Pay to multisig'; -Script.types.MULTISIG_IN = 'Spend from multisig'; -Script.types.DATA_OUT = 'Data push'; +module.exports = BufferReader; -Script.OP_RETURN_STANDARD_SIZE = 80; +}).call(this,require("buffer").Buffer) +},{"../crypto/bn":34,"../util/buffer":69,"../util/preconditions":71,"buffer":209,"lodash":95}],43:[function(require,module,exports){ +(function (Buffer){ +'use strict'; -Script.identifiers = {}; -Script.identifiers.PUBKEY_OUT = Script.prototype.isPublicKeyOut; -Script.identifiers.PUBKEY_IN = Script.prototype.isPublicKeyIn; -Script.identifiers.PUBKEYHASH_OUT = Script.prototype.isPublicKeyHashOut; -Script.identifiers.PUBKEYHASH_IN = Script.prototype.isPublicKeyHashIn; -Script.identifiers.MULTISIG_OUT = Script.prototype.isMultisigOut; -Script.identifiers.MULTISIG_IN = Script.prototype.isMultisigIn; -Script.identifiers.SCRIPTHASH_OUT = Script.prototype.isScriptHashOut; -Script.identifiers.SCRIPTHASH_IN = Script.prototype.isScriptHashIn; -Script.identifiers.DATA_OUT = Script.prototype.isDataOut; +var bufferUtil = require('../util/buffer'); +var assert = require('assert'); -/** - * @returns {object} The Script type if it is a known form, - * or Script.UNKNOWN if it isn't - */ -Script.prototype.classify = function() { - for (var type in Script.identifiers) { - if (Script.identifiers[type].bind(this)()) { - return Script.types[type]; - } - } - return Script.types.UNKNOWN; +var BufferWriter = function BufferWriter(obj) { + if (!(this instanceof BufferWriter)) + return new BufferWriter(obj); + if (obj) + this.set(obj); + else + this.bufs = []; }; - -/** - * @returns {boolean} if script is one of the known types - */ -Script.prototype.isStandard = function() { - // TODO: Add BIP62 compliance - return this.classify() !== Script.types.UNKNOWN; +BufferWriter.prototype.set = function(obj) { + this.bufs = obj.bufs || this.bufs || []; + return this; }; +BufferWriter.prototype.toBuffer = function() { + return this.concat(); +}; -// Script construction methods +BufferWriter.prototype.concat = function() { + return Buffer.concat(this.bufs); +}; -/** - * Adds a script element at the start of the script. - * @param {*} obj a string, number, Opcode, Bufer, or object to add - * @returns {Script} this script instance - */ -Script.prototype.prepend = function(obj) { - this._addByType(obj, true); +BufferWriter.prototype.write = function(buf) { + assert(bufferUtil.isBuffer(buf)); + this.bufs.push(buf); return this; }; -/** - * Compares a script with another script - */ -Script.prototype.equals = function(script) { - $.checkState(script instanceof Script, 'Must provide another script'); - if (this.chunks.length !== script.chunks.length) { - return false; - } - var i; - for (i = 0; i < this.chunks.length; i++) { - if (BufferUtil.isBuffer(this.chunks[i]) && !BufferUtil.isBuffer(script.chunks[i])) { - return false; - } else if (this.chunks[i] instanceof Opcode && !(script.chunks[i] instanceof Opcode)) { - return false; - } - if (BufferUtil.isBuffer(this.chunks[i]) && !BufferUtil.equals(this.chunks[i], script.chunks[i])) { - return false; - } else if (this.chunks[i].num !== script.chunks[i].num) { - return false; - } - } - return true; +BufferWriter.prototype.writeReverse = function(buf) { + assert(bufferUtil.isBuffer(buf)); + this.bufs.push(bufferUtil.reverse(buf)); + return this; }; -/** - * Adds a script element to the end of the script. - * - * @param {*} obj a string, number, Opcode, Bufer, or object to add - * @returns {Script} this script instance - * - */ -Script.prototype.add = function(obj) { - this._addByType(obj, false); +BufferWriter.prototype.writeUInt8 = function(n) { + var buf = new Buffer(1); + buf.writeUInt8(n, 0); + this.write(buf); return this; }; -Script.prototype._addByType = function(obj, prepend) { - if (typeof obj === 'string') { - this._addOpcode(obj, prepend); - } else if (typeof obj === 'number') { - this._addOpcode(obj, prepend); - } else if (obj instanceof Opcode) { - this._addOpcode(obj, prepend); - } else if (BufferUtil.isBuffer(obj)) { - this._addBuffer(obj, prepend); - } else if (typeof obj === 'object') { - this._insertAtPosition(obj, prepend); - } else if (obj instanceof Script) { - this.chunks = this.chunks.concat(obj.chunks); - } else { - throw new Error('Invalid script chunk'); - } +BufferWriter.prototype.writeUInt16BE = function(n) { + var buf = new Buffer(2); + buf.writeUInt16BE(n, 0); + this.write(buf); + return this; }; -Script.prototype._insertAtPosition = function(op, prepend) { - if (prepend) { - this.chunks.unshift(op); - } else { - this.chunks.push(op); - } +BufferWriter.prototype.writeUInt16LE = function(n) { + var buf = new Buffer(2); + buf.writeUInt16LE(n, 0); + this.write(buf); + return this; }; -Script.prototype._addOpcode = function(opcode, prepend) { - var op; - if (typeof opcode === 'number') { - op = opcode; - } else if (opcode instanceof Opcode) { - op = opcode.toNumber(); - } else { - op = Opcode(opcode).toNumber(); - } - this._insertAtPosition({ - opcodenum: op - }, prepend); +BufferWriter.prototype.writeUInt32BE = function(n) { + var buf = new Buffer(4); + buf.writeUInt32BE(n, 0); + this.write(buf); return this; }; -Script.prototype._addBuffer = function(buf, prepend) { - var opcodenum; - var len = buf.length; - if (len >= 0 && len < Opcode.OP_PUSHDATA1) { - opcodenum = len; - } else if (len < Math.pow(2, 8)) { - opcodenum = Opcode.OP_PUSHDATA1; - } else if (len < Math.pow(2, 16)) { - opcodenum = Opcode.OP_PUSHDATA2; - } else if (len < Math.pow(2, 32)) { - opcodenum = Opcode.OP_PUSHDATA4; - } else { - throw new Error('You can\'t push that much data'); - } - this._insertAtPosition({ - buf: buf, - len: len, - opcodenum: opcodenum - }, prepend); +BufferWriter.prototype.writeInt32LE = function(n) { + var buf = new Buffer(4); + buf.writeInt32LE(n, 0); + this.write(buf); return this; }; -Script.prototype.removeCodeseparators = function() { - var chunks = []; - for (var i = 0; i < this.chunks.length; i++) { - if (this.chunks[i].opcodenum !== Opcode.OP_CODESEPARATOR) { - chunks.push(this.chunks[i]); - } - } - this.chunks = chunks; +BufferWriter.prototype.writeUInt32LE = function(n) { + var buf = new Buffer(4); + buf.writeUInt32LE(n, 0); + this.write(buf); return this; }; -// high level script builder methods - -/** - * @returns {Script} a new Multisig output script for given public keys, - * requiring m of those public keys to spend - * @param {PublicKey[]} publicKeys - list of all public keys controlling the output - * @param {number} threshold - amount of required signatures to spend the output - * @param {Object=} opts - Several options: - * - noSorting: defaults to false, if true, don't sort the given - * public keys before creating the script - */ -Script.buildMultisigOut = function(publicKeys, threshold, opts) { - $.checkArgument(threshold <= publicKeys.length, - 'Number of required signatures must be less than or equal to the number of public keys'); - opts = opts || {}; - var script = new Script(); - script.add(Opcode.smallInt(threshold)); - publicKeys = _.map(publicKeys, PublicKey); - var sorted = publicKeys; - if (!opts.noSorting) { - sorted = _.sortBy(publicKeys, function(publicKey) { - return publicKey.toString('hex'); - }); - } - for (var i = 0; i < sorted.length; i++) { - var publicKey = sorted[i]; - script.add(publicKey.toBuffer()); - } - script.add(Opcode.smallInt(publicKeys.length)); - script.add(Opcode.OP_CHECKMULTISIG); - return script; +BufferWriter.prototype.writeUInt64BEBN = function(bn) { + var buf = bn.toBuffer({size: 8}); + this.write(buf); + return this; }; -/** - * A new P2SH Multisig input script for the given public keys, requiring m of those public keys to spend - * - * @param {PublicKey[]} pubkeys list of all public keys controlling the output - * @param {number} threshold amount of required signatures to spend the output - * @param {Array} signatures signatures to append to the script - * @param {Object=} opts - * @param {boolean=} opts.noSorting don't sort the given public keys before creating the script (false by default) - * @param {Script=} opts.cachedMultisig don't recalculate the redeemScript - * - * @returns {Script} - */ -Script.buildP2SHMultisigIn = function(pubkeys, threshold, signatures, opts) { - $.checkArgument(_.isArray(pubkeys)); - $.checkArgument(_.isNumber(threshold)); - $.checkArgument(_.isArray(signatures)); - opts = opts || {}; - var s = new Script(); - s.add(Opcode.OP_0); - _.each(signatures, function(signature) { - s.add(signature); - }); - s.add((opts.cachedMultisig || Script.buildMultisigOut(pubkeys, threshold, opts)).toBuffer()); - return s; +BufferWriter.prototype.writeUInt64LEBN = function(bn) { + var buf = bn.toBuffer({size: 8}); + var reversebuf = new Buffer(Array.apply(new Array(), buf).reverse()); + this.write(reversebuf); + return this; }; -/** - * @returns {Script} a new pay to public key hash output for the given - * address or public key - * @param {(Address|PublicKey)} to - destination address or public key - */ -Script.buildPublicKeyHashOut = function(to) { - $.checkArgument(!_.isUndefined(to)); - $.checkArgument(to instanceof PublicKey || to instanceof Address || _.isString(to)); - if (to instanceof PublicKey) { - to = to.toAddress(); - } else if (_.isString(to)) { - to = new Address(to); - } - var s = new Script(); - s.add(Opcode.OP_DUP) - .add(Opcode.OP_HASH160) - .add(to.hashBuffer) - .add(Opcode.OP_EQUALVERIFY) - .add(Opcode.OP_CHECKSIG); - s._network = to.network; - return s; +BufferWriter.prototype.writeVarintNum = function(n) { + var buf = BufferWriter.varintBufNum(n); + this.write(buf); + return this; }; -/** - * @returns {Script} a new pay to public key output for the given - * public key - */ -Script.buildPublicKeyOut = function(pubkey) { - $.checkArgument(pubkey instanceof PublicKey); - var s = new Script(); - s.add(pubkey.toBuffer()) - .add(Opcode.OP_CHECKSIG); - return s; +BufferWriter.prototype.writeVarintBN = function(bn) { + var buf = BufferWriter.varintBufBN(bn); + this.write(buf); + return this; }; -/** - * @returns {Script} a new OP_RETURN script with data - * @param {(string|Buffer)} to - the data to embed in the output - */ -Script.buildDataOut = function(data) { - $.checkArgument(_.isUndefined(data) || _.isString(data) || BufferUtil.isBuffer(data)); - if (typeof data === 'string') { - data = new Buffer(data); +BufferWriter.varintBufNum = function(n) { + var buf = undefined; + if (n < 253) { + buf = new Buffer(1); + buf.writeUInt8(n, 0); + } else if (n < 0x10000) { + buf = new Buffer(1 + 2); + buf.writeUInt8(253, 0); + buf.writeUInt16LE(n, 1); + } else if (n < 0x100000000) { + buf = new Buffer(1 + 4); + buf.writeUInt8(254, 0); + buf.writeUInt32LE(n, 1); + } else { + buf = new Buffer(1 + 8); + buf.writeUInt8(255, 0); + buf.writeInt32LE(n & -1, 1); + buf.writeUInt32LE(Math.floor(n / 0x100000000), 5); } - var s = new Script(); - s.add(Opcode.OP_RETURN); - if (!_.isUndefined(data)) { - s.add(data); + return buf; +}; + +BufferWriter.varintBufBN = function(bn) { + var buf = undefined; + var n = bn.toNumber(); + if (n < 253) { + buf = new Buffer(1); + buf.writeUInt8(n, 0); + } else if (n < 0x10000) { + buf = new Buffer(1 + 2); + buf.writeUInt8(253, 0); + buf.writeUInt16LE(n, 1); + } else if (n < 0x100000000) { + buf = new Buffer(1 + 4); + buf.writeUInt8(254, 0); + buf.writeUInt32LE(n, 1); + } else { + var bw = new BufferWriter(); + bw.writeUInt8(255); + bw.writeUInt64LEBN(bn); + var buf = bw.concat(); } - return s; + return buf; }; -/** - * @param {Script|Address} script - the redeemScript for the new p2sh output. - * It can also be a p2sh address - * @returns {Script} new pay to script hash script for given script - */ -Script.buildScriptHashOut = function(script) { - $.checkArgument(script instanceof Script || - (script instanceof Address && script.isPayToScriptHash())); - var s = new Script(); - s.add(Opcode.OP_HASH160) - .add(script instanceof Address ? script.hashBuffer : Hash.sha256ripemd160(script.toBuffer())) - .add(Opcode.OP_EQUAL); +module.exports = BufferWriter; - s._network = script._network || script.network; - return s; -}; +}).call(this,require("buffer").Buffer) +},{"../util/buffer":69,"assert":194,"buffer":209}],44:[function(require,module,exports){ +(function (Buffer){ +'use strict'; -/** - * Builds a scriptSig (a script for an input) that signs a public key hash - * output script. - * - * @param {Buffer|string|PublicKey} publicKey - * @param {Signature|Buffer} signature - a Signature object, or the signature in DER cannonical encoding - * @param {number=} sigtype - the type of the signature (defaults to SIGHASH_ALL) - */ -Script.buildPublicKeyHashIn = function(publicKey, signature, sigtype) { - $.checkArgument(signature instanceof Signature || BufferUtil.isBuffer(signature)); - $.checkArgument(_.isUndefined(sigtype) || _.isNumber(sigtype)); - if (signature instanceof Signature) { - signature = signature.toBuffer(); +var BufferWriter = require('./bufferwriter'); +var BufferReader = require('./bufferreader'); +var BN = require('../crypto/bn'); + +var Varint = function Varint(buf) { + if (!(this instanceof Varint)) + return new Varint(buf); + if (Buffer.isBuffer(buf)) { + this.buf = buf; + } else if (typeof buf === 'number') { + var num = buf; + this.fromNumber(num); + } else if (buf instanceof BN) { + var bn = buf; + this.fromBN(bn); + } else if (buf) { + var obj = buf; + this.set(obj); } - var script = new Script() - .add(BufferUtil.concat([ - signature, - BufferUtil.integerAsSingleByteBuffer(sigtype || Signature.SIGHASH_ALL) - ])) - .add(new PublicKey(publicKey).toBuffer()); - return script; }; -/** - * @returns {Script} an empty script - */ -Script.empty = function() { - return new Script(); +Varint.prototype.set = function(obj) { + this.buf = obj.buf || this.buf; + return this; }; -/** - * @returns {Script} a new pay to script hash script that pays to this script - */ -Script.prototype.toScriptHashOut = function() { - return Script.buildScriptHashOut(this); +Varint.prototype.fromString = function(str) { + this.set({ + buf: new Buffer(str, 'hex') + }); + return this; }; -/** - * @return {Script} a script built from the address - */ -Script.fromAddress = function(address) { - address = Address(address); - if (address.isPayToScriptHash()) { - return Script.buildScriptHashOut(address); - } else if (address.isPayToPublicKeyHash()) { - return Script.buildPublicKeyHashOut(address); - } - throw new errors.Script.UnrecognizedAddress(address); +Varint.prototype.toString = function() { + return this.buf.toString('hex'); }; -/** - * @param {Network=} network - * @return {Address} the associated address for this script - */ -Script.prototype.toAddress = function(network) { - network = Networks.get(network) || this._network || Networks.defaultNetwork; - if (this.isPublicKeyHashOut() || this.isScriptHashOut()) { - return new Address(this, network); - } - throw new Error('The script type needs to be PayToPublicKeyHash or PayToScriptHash'); +Varint.prototype.fromBuffer = function(buf) { + this.buf = buf; + return this; }; -/** - * @return {Script} - */ -Script.prototype.toScriptHashOut = function() { - return Script.buildScriptHashOut(this); +Varint.prototype.fromBufferReader = function(br) { + this.buf = br.readVarintBuf(); + return this; }; -/** - * Analagous to bitcoind's FindAndDelete. Find and delete equivalent chunks, - * typically used with push data chunks. Note that this will find and delete - * not just the same data, but the same data with the same push data op as - * produced by default. i.e., if a pushdata in a tx does not use the minimal - * pushdata op, then when you try to remove the data it is pushing, it will not - * be removed, because they do not use the same pushdata op. - */ -Script.prototype.findAndDelete = function(script) { - var buf = script.toBuffer(); - var hex = buf.toString('hex'); - for (var i = 0; i < this.chunks.length; i++) { - var script2 = Script({ - chunks: [this.chunks[i]] - }); - var buf2 = script2.toBuffer(); - var hex2 = buf2.toString('hex'); - if (hex === hex2) { - this.chunks.splice(i, 1); - } - } +Varint.prototype.fromBN = function(bn) { + this.buf = BufferWriter().writeVarintBN(bn).concat(); return this; }; -/** - * Comes from bitcoind's script interpreter CheckMinimalPush function - * @returns {boolean} if the chunk {i} is the smallest way to push that particular data. - */ -Script.prototype.checkMinimalPush = function(i) { - var chunk = this.chunks[i]; - var buf = chunk.buf; - var opcodenum = chunk.opcodenum; - if (!buf) { - return true; - } - if (buf.length === 0) { - // Could have used OP_0. - return opcodenum === Opcode.OP_0; - } else if (buf.length === 1 && buf[0] >= 1 && buf[0] <= 16) { - // Could have used OP_1 .. OP_16. - return opcodenum === Opcode.OP_1 + (buf[0] - 1); - } else if (buf.length === 1 && buf[0] === 0x81) { - // Could have used OP_1NEGATE - return opcodenum === Opcode.OP_1NEGATE; - } else if (buf.length <= 75) { - // Could have used a direct push (opcode indicating number of bytes pushed + those bytes). - return opcodenum === buf.length; - } else if (buf.length <= 255) { - // Could have used OP_PUSHDATA. - return opcodenum === Opcode.OP_PUSHDATA1; - } else if (buf.length <= 65535) { - // Could have used OP_PUSHDATA2. - return opcodenum === Opcode.OP_PUSHDATA2; - } - return true; +Varint.prototype.fromNumber = function(num) { + this.buf = BufferWriter().writeVarintNum(num).concat(); + return this; }; -module.exports = Script; - -}).call(this,require("buffer").Buffer) -},{"../address":13,"../crypto/hash":20,"../crypto/signature":23,"../encoding/bufferreader":26,"../encoding/bufferwriter":27,"../errors":29,"../networks":34,"../opcode":35,"../publickey":37,"../util/buffer":53,"../util/js":54,"../util/preconditions":55,"buffer":104,"lodash":79}],41:[function(require,module,exports){ -module.exports = require('./transaction'); +Varint.prototype.toBuffer = function() { + return this.buf; +}; -module.exports.Input = require('./input'); -module.exports.Output = require('./output'); -module.exports.UnspentOutput = require('./unspentoutput'); -module.exports.Signature = require('./signature'); +Varint.prototype.toBN = function() { + return BufferReader(this.buf).readVarintBN(); +}; -},{"./input":42,"./output":46,"./signature":48,"./transaction":49,"./unspentoutput":50}],42:[function(require,module,exports){ -module.exports = require('./input'); +Varint.prototype.toNumber = function() { + return BufferReader(this.buf).readVarintNum(); +}; -module.exports.PublicKeyHash = require('./publickeyhash'); -module.exports.MultiSigScriptHash = require('./multisigscripthash.js'); +module.exports = Varint; -},{"./input":43,"./multisigscripthash.js":44,"./publickeyhash":45}],43:[function(require,module,exports){ +}).call(this,require("buffer").Buffer) +},{"../crypto/bn":34,"./bufferreader":42,"./bufferwriter":43,"buffer":209}],45:[function(require,module,exports){ 'use strict'; var _ = require('lodash'); -var $ = require('../../util/preconditions'); -var errors = require('../../errors'); -var BufferWriter = require('../../encoding/bufferwriter'); -var buffer = require('buffer'); -var BufferUtil = require('../../util/buffer'); -var JSUtil = require('../../util/js'); -var Script = require('../../script'); -var Sighash = require('../sighash'); -var Output = require('../output'); - - -var DEFAULT_SEQNUMBER = 0xFFFFFFFF; -function Input(params) { - if (!(this instanceof Input)) { - return new Input(params); - } - if (params) { - return this._fromObject(params); - } +function format(message, args) { + return message + .replace('{0}', args[0]) + .replace('{1}', args[1]) + .replace('{2}', args[2]); } - -Input.DEFAULT_SEQNUMBER = DEFAULT_SEQNUMBER; - -Object.defineProperty(Input.prototype, 'script', { - configurable: false, - writeable: false, - enumerable: true, - get: function() { - if (!this._script) { - this._script = new Script(this._scriptBuffer); +var traverseNode = function(parent, errorDefinition) { + var NodeError = function() { + if (_.isString(errorDefinition.message)) { + this.message = format(errorDefinition.message, arguments); + } else if (_.isFunction(errorDefinition.message)) { + this.message = errorDefinition.message.apply(null, arguments); + } else { + throw new Error('Invalid error definition for ' + errorDefinition.name); } - return this._script; - } -}); - -Input.prototype._fromObject = function(params) { - if (_.isString(params.prevTxId) && JSUtil.isHexa(params.prevTxId)) { - params.prevTxId = new buffer.Buffer(params.prevTxId, 'hex'); - } - this.output = params.output ? - (params.output instanceof Output ? params.output : new Output(params.output)) : undefined; - this.prevTxId = params.prevTxId || params.txidbuf; - this.outputIndex = _.isUndefined(params.outputIndex) ? params.txoutnum : params.outputIndex; - this.sequenceNumber = _.isUndefined(params.sequenceNumber) ? - (_.isUndefined(params.seqnum) ? DEFAULT_SEQNUMBER : params.seqnum) : params.sequenceNumber; - if (_.isUndefined(params.script) && _.isUndefined(params.scriptBuffer)) { - throw new errors.Transaction.Input.MissingScript(); + this.stack = this.message + '\n' + (new Error()).stack; + }; + NodeError.prototype = Object.create(parent.prototype); + NodeError.prototype.name = parent.prototype.name + errorDefinition.name; + parent[errorDefinition.name] = NodeError; + if (errorDefinition.errors) { + childDefinitions(NodeError, errorDefinition.errors); } - this.setScript(params.scriptBuffer || params.script); - return this; + return NodeError; }; -Input.prototype.toObject = function toObject() { - return { - prevTxId: this.prevTxId.toString('hex'), - outputIndex: this.outputIndex, - sequenceNumber: this.sequenceNumber, - script: this.script.toString(), - output: this.output ? this.output.toObject() : undefined - }; +/* jshint latedef: false */ +var childDefinitions = function(parent, childDefinitions) { + _.each(childDefinitions, function(childDefinition) { + traverseNode(parent, childDefinition); + }); }; +/* jshint latedef: true */ -Input.fromObject = function(obj) { - $.checkArgument(_.isObject(obj)); - var input = new Input(); - return input._fromObject(obj); +var traverseRoot = function(parent, errorsDefinition) { + childDefinitions(parent, errorsDefinition); + return parent; }; -Input.prototype.toJSON = function toJSON() { - return JSON.stringify(this.toObject()); -}; -Input.fromJSON = function(json) { - $.checkArgument(JSUtil.isValidJSON(json), 'Invalid JSON provided to Input.fromJSON'); - return Input.fromObject(JSON.parse(json)); +var bitcore = {}; +bitcore.Error = function() { + this.message = 'Internal error'; + this.stack = this.message + '\n' + (new Error()).stack; }; +bitcore.Error.prototype = Object.create(Error.prototype); +bitcore.Error.prototype.name = 'bitcore.Error'; -Input.fromBufferReader = function(br) { - var input = new Input(); - input.prevTxId = br.readReverse(32); - input.outputIndex = br.readUInt32LE(); - input._scriptBuffer = br.readVarLengthBuffer(); - input.sequenceNumber = br.readUInt32LE(); - return input; -}; -Input.prototype.toBufferWriter = function(writer) { - if (!writer) { - writer = new BufferWriter(); - } - writer.writeReverse(this.prevTxId); - writer.writeUInt32LE(this.outputIndex); - var script = this._scriptBuffer; - writer.writeVarintNum(script.length); - writer.write(script); - writer.writeUInt32LE(this.sequenceNumber); - return writer; +var data = require('./spec'); +traverseRoot(bitcore.Error, data); + +module.exports = bitcore.Error; + +module.exports.extend = function(spec) { + return traverseNode(bitcore.Error, spec); }; -Input.prototype.setScript = function(script) { - if (script instanceof Script) { - this._script = script; - this._scriptBuffer = script.toBuffer(); - } else if (_.isString(script)) { - this._script = new Script(script); - this._scriptBuffer = this._script.toBuffer(); - } else if (BufferUtil.isBuffer(script)) { - this._script = null; - this._scriptBuffer = new buffer.Buffer(script); - } else { - throw new TypeError('Invalid argument type: script'); - } - return this; -}; +},{"./spec":46,"lodash":95}],46:[function(require,module,exports){ +'use strict'; -/** - * Retrieve signatures for the provided PrivateKey. - * - * @param {Transaction} transaction - the transaction to be signed - * @param {PrivateKey} privateKey - the private key to use when signing - * @param {number} inputIndex - the index of this input in the provided transaction - * @param {number} sigType - defaults to Signature.SIGHASH_ALL - * @param {Buffer} addressHash - if provided, don't calculate the hash of the - * public key associated with the private key provided - * @abstract - */ -Input.prototype.getSignatures = function() { - throw new errors.AbstractMethodInvoked( - 'Trying to sign unsupported output type (only P2PKH and P2SH multisig inputs are supported)' + - ' for input: ' + this.toJSON() - ); -}; +var docsURL = 'http://bitcore.io/'; -Input.prototype.isFullySigned = function() { - throw new errors.AbstractMethodInvoked('Input#isFullySigned'); -}; +module.exports = [{ + name: 'InvalidB58Char', + message: 'Invalid Base58 character: {0} in {1}' +}, { + name: 'InvalidB58Checksum', + message: 'Invalid Base58 checksum for {0}' +}, { + name: 'InvalidNetwork', + message: 'Invalid version for network: got {0}' +}, { + name: 'InvalidState', + message: 'Invalid state: {0}' +}, { + name: 'NotImplemented', + message: 'Function {0} was not implemented yet' +}, { + name: 'InvalidNetworkArgument', + message: 'Invalid network: must be "livenet" or "testnet", got {0}' +}, { + name: 'InvalidArgument', + message: function() { + return 'Invalid Argument' + (arguments[0] ? (': ' + arguments[0]) : '') + + (arguments[1] ? (' Documentation: ' + docsURL + arguments[1]) : ''); + } +}, { + name: 'AbstractMethodInvoked', + message: 'Abstract Method Invokation: {0}' +}, { + name: 'InvalidArgumentType', + message: function() { + return 'Invalid Argument for ' + arguments[2] + ', expected ' + arguments[1] + ' but got ' + typeof arguments[0]; + } +}, { + name: 'Unit', + message: 'Internal Error on Unit {0}', + errors: [{ + 'name': 'UnknownCode', + 'message': 'Unrecognized unit code: {0}' + }, { + 'name': 'InvalidRate', + 'message': 'Invalid exchange rate: {0}' + }] +}, { + name: 'Transaction', + message: 'Internal Error on Transaction {0}', + errors: [{ + name: 'Input', + message: 'Internal Error on Input {0}', + errors: [{ + name: 'MissingScript', + message: 'Need a script to create an input' + }, { + name: 'UnsupportedScript', + message: 'Unsupported input script type: {0}' + }] + }, { + name: 'NeedMoreInfo', + message: '{0}' + }, { + name: 'InvalidIndex', + message: 'Invalid index: {0} is not between 0, {1}' + }, { + name: 'UnableToVerifySignature', + message: 'Unable to verify signature: {0}' + }, { + name: 'DustOutputs', + message: 'Dust amount detected in one output' + }, { + name: 'FeeError', + message: 'Fees are not correctly set {0}', + }, { + name: 'ChangeAddressMissing', + message: 'Change address is missing' + }, { + name: 'BlockHeightTooHigh', + message: 'Block Height can be at most 2^32 -1' + }, { + name: 'NLockTimeOutOfRange', + message: 'Block Height can only be between 0 and 499 999 999' + }, { + name: 'LockTimeTooEarly', + message: 'Lock Time can\'t be earlier than UNIX date 500 000 000' + }] +}, { + name: 'Script', + message: 'Internal Error on Script {0}', + errors: [{ + name: 'UnrecognizedAddress', + message: 'Expected argument {0} to be an address' + }] +}, { + name: 'HDPrivateKey', + message: 'Internal Error on HDPrivateKey {0}', + errors: [{ + name: 'InvalidDerivationArgument', + message: 'Invalid derivation argument {0}, expected string, or number and boolean' + }, { + name: 'InvalidEntropyArgument', + message: 'Invalid entropy: must be an hexa string or binary buffer, got {0}', + errors: [{ + name: 'TooMuchEntropy', + message: 'Invalid entropy: more than 512 bits is non standard, got "{0}"' + }, { + name: 'NotEnoughEntropy', + message: 'Invalid entropy: at least 128 bits needed, got "{0}"' + }] + }, { + name: 'InvalidLength', + message: 'Invalid length for xprivkey string in {0}' + }, { + name: 'InvalidPath', + message: 'Invalid derivation path: {0}' + }, { + name: 'UnrecognizedArgument', + message: 'Invalid argument: creating a HDPrivateKey requires a string, buffer, json or object, got "{0}"' + }] +}, { + name: 'HDPublicKey', + message: 'Internal Error on HDPublicKey {0}', + errors: [{ + name: 'ArgumentIsPrivateExtended', + message: 'Argument is an extended private key: {0}' + }, { + name: 'InvalidDerivationArgument', + message: 'Invalid derivation argument: got {0}' + }, { + name: 'InvalidLength', + message: 'Invalid length for xpubkey: got "{0}"' + }, { + name: 'InvalidPath', + message: 'Invalid derivation path, it should look like: "m/1/100", got "{0}"' + }, { + name: 'MustSupplyArgument', + message: 'Must supply an argument to create a HDPublicKey' + }, { + name: 'UnrecognizedArgument', + message: 'Invalid argument for creation, must be string, json, buffer, or object' + }] +}]; -Input.prototype.addSignature = function() { - throw new errors.AbstractMethodInvoked('Input#addSignature'); -}; +},{}],47:[function(require,module,exports){ +'use strict'; -Input.prototype.clearSignatures = function() { - throw new errors.AbstractMethodInvoked('Input#clearSignatures'); -}; +module.exports = { + _cache: {}, + _count: 0, + _eraseIndex: 0, + _usedList: {}, + _usedIndex: {}, + _CACHE_SIZE: 5000, -Input.prototype.isValidSignature = function(transaction, signature) { - // FIXME: Refactor signature so this is not necessary - signature.signature.nhashtype = signature.sigtype; - return Sighash.verify( - transaction, - signature.signature, - signature.publicKey, - signature.inputIndex, - this.output.script - ); + get: function(xkey, number, hardened) { + hardened = !!hardened; + var key = xkey + '/' + number + '/' + hardened; + if (this._cache[key]) { + this._cacheHit(key); + return this._cache[key]; + } + }, + set: function(xkey, number, hardened, derived) { + hardened = !!hardened; + var key = xkey + '/' + number + '/' + hardened; + this._cache[key] = derived; + this._cacheHit(key); + }, + _cacheHit: function(key) { + if (this._usedIndex[key]) { + delete this._usedList[this._usedIndex[key]]; + } + this._usedList[this._count] = key; + this._usedIndex[key] = this._count; + this._count++; + this._cacheRemove(); + }, + _cacheRemove: function() { + while (this._eraseIndex < this._count - this._CACHE_SIZE) { + if (this._usedList[this._eraseIndex]) { + var removeKey = this._usedList[this._eraseIndex]; + delete this._usedIndex[removeKey]; + delete this._cache[removeKey]; + } + delete this._usedList[this._eraseIndex]; + this._eraseIndex++; + } + } }; -/** - * @returns true if this is a coinbase input (represents no input) - */ -Input.prototype.isNull = function() { - return this.prevTxId.toString('hex') === '0000000000000000000000000000000000000000000000000000000000000000' && - this.outputIndex === 0xffffffff; -}; +},{}],48:[function(require,module,exports){ +(function (Buffer){ +'use strict'; -Input.prototype._estimateSize = function() { - return this.toBufferWriter().toBuffer().length; -}; -module.exports = Input; +var assert = require('assert'); +var buffer = require('buffer'); +var _ = require('lodash'); +var $ = require('./util/preconditions'); -},{"../../encoding/bufferwriter":27,"../../errors":29,"../../script":38,"../../util/buffer":53,"../../util/js":54,"../../util/preconditions":55,"../output":46,"../sighash":47,"buffer":104,"lodash":79}],44:[function(require,module,exports){ -'use strict'; +var BN = require('./crypto/bn'); +var Base58 = require('./encoding/base58'); +var Base58Check = require('./encoding/base58check'); +var Hash = require('./crypto/hash'); +var Network = require('./networks'); +var HDKeyCache = require('./hdkeycache'); +var Point = require('./crypto/point'); +var PrivateKey = require('./privatekey'); +var Random = require('./crypto/random'); -var _ = require('lodash'); -var inherits = require('inherits'); -var Input = require('./input'); -var Output = require('../output'); -var $ = require('../../util/preconditions'); +var errors = require('./errors'); +var hdErrors = errors.HDPrivateKey; +var BufferUtil = require('./util/buffer'); +var JSUtil = require('./util/js'); + +var MINIMUM_ENTROPY_BITS = 128; +var BITS_TO_BYTES = 1 / 8; +var MAXIMUM_ENTROPY_BITS = 512; -var Script = require('../../script'); -var Signature = require('../../crypto/signature'); -var Sighash = require('../sighash'); -var PublicKey = require('../../publickey'); -var BufferUtil = require('../../util/buffer'); -var TransactionSignature = require('../signature'); /** + * Represents an instance of an hierarchically derived private key. + * + * More info on https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki + * * @constructor + * @param {string|Buffer|Object} arg */ -function MultiSigScriptHashInput(input, pubkeys, threshold, signatures) { - Input.apply(this, arguments); - var self = this; - pubkeys = pubkeys || input.publicKeys; - threshold = threshold || input.threshold; - signatures = signatures || input.signatures; - this.publicKeys = _.sortBy(pubkeys, function(publicKey) { return publicKey.toString('hex'); }); - this.redeemScript = Script.buildMultisigOut(this.publicKeys, threshold); - $.checkState(Script.buildScriptHashOut(this.redeemScript).equals(this.output.script), - 'Provided public keys don\'t hash to the provided output'); - this.publicKeyIndex = {}; - _.each(this.publicKeys, function(publicKey, index) { - self.publicKeyIndex[publicKey.toString()] = index; - }); - this.threshold = threshold; - // Empty array of signatures - this.signatures = signatures ? this._deserializeSignatures(signatures) : new Array(this.publicKeys.length); +function HDPrivateKey(arg) { + /* jshint maxcomplexity: 10 */ + if (arg instanceof HDPrivateKey) { + return arg; + } + if (!(this instanceof HDPrivateKey)) { + return new HDPrivateKey(arg); + } + if (!arg) { + return this._generateRandomly(); + } + + if (Network.get(arg)) { + return this._generateRandomly(arg); + } else if (_.isString(arg) || BufferUtil.isBuffer(arg)) { + if (HDPrivateKey.isValidSerialized(arg)) { + this._buildFromSerialized(arg); + } else if (JSUtil.isValidJSON(arg)) { + this._buildFromJSON(arg); + } else if (BufferUtil.isBuffer(arg) && HDPrivateKey.isValidSerialized(arg.toString())) { + this._buildFromSerialized(arg.toString()); + } else { + throw HDPrivateKey.getSerializedError(arg); + } + } else if (_.isObject(arg)) { + this._buildFromObject(arg); + } else { + throw new hdErrors.UnrecognizedArgument(arg); + } } -inherits(MultiSigScriptHashInput, Input); -MultiSigScriptHashInput.prototype.toObject = function() { - var obj = Input.prototype.toObject.apply(this, arguments); - obj.threshold = this.threshold; - obj.publicKeys = _.map(this.publicKeys, function(publicKey) { return publicKey.toString(); }); - obj.signatures = this._serializeSignatures(); - return obj; -}; +/** + * Verifies that a given path is valid. + * + * @param {string|number} arg + * @param {boolean?} hardened + * @return {boolean} + */ +HDPrivateKey.isValidPath = function(arg, hardened) { + if (_.isString(arg)) { + var indexes = HDPrivateKey._getDerivationIndexes(arg); + return indexes !== null && _.all(indexes, HDPrivateKey.isValidPath); + } -MultiSigScriptHashInput.prototype._deserializeSignatures = function(signatures) { - return _.map(signatures, function(signature) { - if (!signature) { - return undefined; + if (_.isNumber(arg)) { + if (arg < HDPrivateKey.Hardened && hardened === true) { + arg += HDPrivateKey.Hardened; } - return new TransactionSignature(signature); - }); -}; + return arg >= 0 && arg < HDPrivateKey.MaxIndex; + } -MultiSigScriptHashInput.prototype._serializeSignatures = function() { - return _.map(this.signatures, function(signature) { - if (!signature) { - return undefined; - } - return signature.toObject(); - }); + return false; }; -MultiSigScriptHashInput.prototype.getSignatures = function(transaction, privateKey, index, sigtype) { - $.checkState(this.output instanceof Output); - sigtype = sigtype || Signature.SIGHASH_ALL; - - var self = this; - var results = []; - _.each(this.publicKeys, function(publicKey) { - if (publicKey.toString() === privateKey.publicKey.toString()) { - results.push(new TransactionSignature({ - publicKey: privateKey.publicKey, - prevTxId: self.prevTxId, - outputIndex: self.outputIndex, - inputIndex: index, - signature: Sighash.sign(transaction, privateKey, sigtype, index, self.redeemScript), - sigtype: sigtype - })); - } - }); - return results; -}; +/** + * Internal function that splits a string path into a derivation index array. + * It will return null if the string path is malformed. + * It does not validate if indexes are in bounds. + * + * @param {string} path + * @return {Array} + */ +HDPrivateKey._getDerivationIndexes = function(path) { + var steps = path.split('/'); -MultiSigScriptHashInput.prototype.addSignature = function(transaction, signature) { - $.checkState(!this.isFullySigned(), 'All needed signatures have already been added'); - $.checkArgument(!_.isUndefined(this.publicKeyIndex[signature.publicKey.toString()]), - 'Signature has no matching public key'); - $.checkState(this.isValidSignature(transaction, signature)); - this.signatures[this.publicKeyIndex[signature.publicKey.toString()]] = signature; - this._updateScript(); - return this; -}; + // Special cases: + if (_.contains(HDPrivateKey.RootElementAlias, path)) { + return []; + } -MultiSigScriptHashInput.prototype._updateScript = function() { - this.setScript(Script.buildP2SHMultisigIn( - this.publicKeys, - this.threshold, - this._createSignatures(), - { cachedMultisig: this.redeemScript } - )); - return this; -}; + if (!_.contains(HDPrivateKey.RootElementAlias, steps[0])) { + return null; + } -MultiSigScriptHashInput.prototype._createSignatures = function() { - return _.map( - _.filter(this.signatures, function(signature) { return !_.isUndefined(signature); }), - function(signature) { - return BufferUtil.concat([ - signature.signature.toDER(), - BufferUtil.integerAsSingleByteBuffer(signature.sigtype) - ]); + var indexes = steps.slice(1).map(function(step) { + var isHardened = step.slice(-1) === '\''; + if (isHardened) { + step = step.slice(0, -1); + } + if (!step || step[0] === '-') { + return NaN; + } + var index = +step; // cast to number + if (isHardened) { + index += HDPrivateKey.Hardened; } - ); -}; -MultiSigScriptHashInput.prototype.clearSignatures = function() { - this.signatures = new Array(this.publicKeys.length); - this._updateScript(); -}; + return index; + }); -MultiSigScriptHashInput.prototype.isFullySigned = function() { - return this.countSignatures() === this.threshold; + return _.any(indexes, isNaN) ? null : indexes; }; -MultiSigScriptHashInput.prototype.countMissingSignatures = function() { - return this.threshold - this.countSignatures(); +/** + * Get a derivated child based on a string or number. + * + * If the first argument is a string, it's parsed as the full path of + * derivation. Valid values for this argument include "m" (which returns the + * same private key), "m/0/1/40/2'/1000", where the ' quote means a hardened + * derivation. + * + * If the first argument is a number, the child with that index will be + * derived. If the second argument is truthy, the hardened version will be + * derived. See the example usage for clarification. + * + * @example + * ```javascript + * var parent = new HDPrivateKey('xprv...'); + * var child_0_1_2h = parent.derive(0).derive(1).derive(2, true); + * var copy_of_child_0_1_2h = parent.derive("m/0/1/2'"); + * assert(child_0_1_2h.xprivkey === copy_of_child_0_1_2h); + * ``` + * + * @param {string|number} arg + * @param {boolean?} hardened + */ +HDPrivateKey.prototype.derive = function(arg, hardened) { + if (_.isNumber(arg)) { + return this._deriveWithNumber(arg, hardened); + } else if (_.isString(arg)) { + return this._deriveFromString(arg); + } else { + throw new hdErrors.InvalidDerivationArgument(arg); + } }; -MultiSigScriptHashInput.prototype.countSignatures = function() { - return _.reduce(this.signatures, function(sum, signature) { - return sum + (!!signature); - }, 0); -}; +HDPrivateKey.prototype._deriveWithNumber = function(index, hardened) { + /* jshint maxstatements: 20 */ + /* jshint maxcomplexity: 10 */ + if (!HDPrivateKey.isValidPath(index, hardened)) { + throw new hdErrors.InvalidPath(index); + } -MultiSigScriptHashInput.prototype.publicKeysWithoutSignature = function() { - var self = this; - return _.filter(this.publicKeys, function(publicKey) { - return !(self.signatures[self.publicKeyIndex[publicKey.toString()]]); - }); -}; + hardened = index >= HDPrivateKey.Hardened ? true : hardened; + if (index < HDPrivateKey.Hardened && hardened === true) { + index += HDPrivateKey.Hardened; + } -MultiSigScriptHashInput.prototype.isValidSignature = function(transaction, signature) { - // FIXME: Refactor signature so this is not necessary - signature.signature.nhashtype = signature.sigtype; - return Sighash.verify( - transaction, - signature.signature, - signature.publicKey, - signature.inputIndex, - this.redeemScript - ); -}; - -MultiSigScriptHashInput.OPCODES_SIZE = 7; // serialized size (<=3) + 0 .. N .. M OP_CHECKMULTISIG -MultiSigScriptHashInput.SIGNATURE_SIZE = 74; // size (1) + DER (<=72) + sighash (1) -MultiSigScriptHashInput.PUBKEY_SIZE = 34; // size (1) + DER (<=33) - -MultiSigScriptHashInput.prototype._estimateSize = function() { - return MultiSigScriptHashInput.OPCODES_SIZE + - this.threshold * MultiSigScriptHashInput.SIGNATURE_SIZE + - this.publicKeys.length * MultiSigScriptHashInput.PUBKEY_SIZE; -}; - -module.exports = MultiSigScriptHashInput; - -},{"../../crypto/signature":23,"../../publickey":37,"../../script":38,"../../util/buffer":53,"../../util/preconditions":55,"../output":46,"../sighash":47,"../signature":48,"./input":43,"inherits":78,"lodash":79}],45:[function(require,module,exports){ -'use strict'; + var cached = HDKeyCache.get(this.xprivkey, index, hardened); + if (cached) { + return cached; + } -var inherits = require('inherits'); + var indexBuffer = BufferUtil.integerAsBuffer(index); + var data; + if (hardened) { + data = BufferUtil.concat([new buffer.Buffer([0]), this.privateKey.toBuffer(), indexBuffer]); + } else { + data = BufferUtil.concat([this.publicKey.toBuffer(), indexBuffer]); + } + var hash = Hash.sha512hmac(data, this._buffers.chainCode); + var leftPart = BN.fromBuffer(hash.slice(0, 32), { + size: 32 + }); + var chainCode = hash.slice(32, 64); -var $ = require('../../util/preconditions'); -var BufferUtil = require('../../util/buffer'); + var privateKey = leftPart.add(this.privateKey.toBigNumber()).mod(Point.getN()).toBuffer({ + size: 32 + }); -var Hash = require('../../crypto/hash'); -var Input = require('./input'); -var Output = require('../output'); -var Sighash = require('../sighash'); -var Script = require('../../script'); -var Signature = require('../../crypto/signature'); -var TransactionSignature = require('../signature'); + var derived = new HDPrivateKey({ + network: this.network, + depth: this.depth + 1, + parentFingerPrint: this.fingerPrint, + childIndex: index, + chainCode: chainCode, + privateKey: privateKey + }); + HDKeyCache.set(this.xprivkey, index, hardened, derived); + return derived; +}; -/** - * Represents a special kind of input of PayToPublicKeyHash kind. - * @constructor - */ -function PublicKeyHashInput() { - Input.apply(this, arguments); -} -inherits(PublicKeyHashInput, Input); +HDPrivateKey.prototype._deriveFromString = function(path) { + if (!HDPrivateKey.isValidPath(path)) { + throw new hdErrors.InvalidPath(path); + } -/* jshint maxparams: 5 */ -/** - * @param {Transaction} transaction - the transaction to be signed - * @param {PrivateKey} privateKey - the private key with which to sign the transaction - * @param {number} index - the index of the input in the transaction input vector - * @param {number=} sigtype - the type of signature, defaults to Signature.SIGHASH_ALL - * @param {Buffer=} hashData - the precalculated hash of the public key associated with the privateKey provided - * @return {Array} of objects that can be - */ -PublicKeyHashInput.prototype.getSignatures = function(transaction, privateKey, index, sigtype, hashData) { - $.checkState(this.output instanceof Output); - hashData = hashData || Hash.sha256ripemd160(privateKey.publicKey.toBuffer()); - sigtype = sigtype || Signature.SIGHASH_ALL; + var indexes = HDPrivateKey._getDerivationIndexes(path); + var derived = indexes.reduce(function(prev, index) { + return prev._deriveWithNumber(index); + }, this); - if (BufferUtil.equals(hashData, this.output.script.getPublicKeyHash())) { - return [new TransactionSignature({ - publicKey: privateKey.publicKey, - prevTxId: this.prevTxId, - outputIndex: this.outputIndex, - inputIndex: index, - signature: Sighash.sign(transaction, privateKey, sigtype, index, this.output.script), - sigtype: sigtype - })]; - } - return []; + return derived; }; -/* jshint maxparams: 3 */ /** - * Add the provided signature + * Verifies that a given serialized private key in base58 with checksum format + * is valid. * - * @param {Object} signature - * @param {PublicKey} signature.publicKey - * @param {Signature} signature.signature - * @param {number=} signature.sigtype - * @return {PublicKeyHashInput} this, for chaining - */ -PublicKeyHashInput.prototype.addSignature = function(transaction, signature) { - $.checkState(this.isValidSignature(transaction, signature), 'Signature is invalid'); - this.setScript(Script.buildPublicKeyHashIn( - signature.publicKey, - signature.signature.toDER(), - signature.sigtype - )); - return this; -}; - -/** - * Clear the input's signature - * @return {PublicKeyHashInput} this, for chaining + * @param {string|Buffer} data - the serialized private key + * @param {string|Network=} network - optional, if present, checks that the + * network provided matches the network serialized. + * @return {boolean} */ -PublicKeyHashInput.prototype.clearSignatures = function() { - this.setScript(Script.empty()); - return this; +HDPrivateKey.isValidSerialized = function(data, network) { + return !HDPrivateKey.getSerializedError(data, network); }; /** - * Query whether the input is signed - * @return {boolean} + * Checks what's the error that causes the validation of a serialized private key + * in base58 with checksum to fail. + * + * @param {string|Buffer} data - the serialized private key + * @param {string|Network=} network - optional, if present, checks that the + * network provided matches the network serialized. + * @return {errors.InvalidArgument|null} */ -PublicKeyHashInput.prototype.isFullySigned = function() { - return this.script.isPublicKeyHashIn(); -}; - -PublicKeyHashInput.SCRIPT_MAX_SIZE = 73 + 34; // sigsize (1 + 72) + pubkey (1 + 33) - -PublicKeyHashInput.prototype._estimateSize = function() { - return PublicKeyHashInput.SCRIPT_MAX_SIZE; -}; - -module.exports = PublicKeyHashInput; - -},{"../../crypto/hash":20,"../../crypto/signature":23,"../../script":38,"../../util/buffer":53,"../../util/preconditions":55,"../output":46,"../sighash":47,"../signature":48,"./input":43,"inherits":78}],46:[function(require,module,exports){ -'use strict'; - -var _ = require('lodash'); -var BN = require('../crypto/bn'); -var buffer = require('buffer'); -var bufferUtil = require('../util/buffer'); -var JSUtil = require('../util/js'); -var BufferWriter = require('../encoding/bufferwriter'); -var Script = require('../script'); - -function Output(params) { - if (!(this instanceof Output)) { - return new Output(params); +HDPrivateKey.getSerializedError = function(data, network) { + /* jshint maxcomplexity: 10 */ + if (!(_.isString(data) || BufferUtil.isBuffer(data))) { + return new hdErrors.UnrecognizedArgument('Expected string or buffer'); } - if (params) { - if (JSUtil.isValidJSON(params)) { - return Output.fromJSON(params); - } - return this._fromObject(params); + if (!Base58.validCharacters(data)) { + return new errors.InvalidB58Char('(unknown)', data); } -} - -Object.defineProperty(Output.prototype, 'script', { - configurable: false, - writeable: false, - enumerable: true, - get: function() { - if (!this._script) { - this._script = new Script(this._scriptBuffer); - } - return this._script; + try { + data = Base58Check.decode(data); + } catch (e) { + return new errors.InvalidB58Checksum(data); } -}); - -Object.defineProperty(Output.prototype, 'satoshis', { - configurable: false, - writeable: true, - enumerable: true, - get: function() { - return this._satoshis; - }, - set: function(num) { - if (num instanceof BN) { - this._satoshisBN = num; - this._satoshis = num.toNumber(); - } else if (_.isString(num)) { - this._satoshis = parseInt(num); - this._satoshisBN = BN.fromNumber(this._satoshis); - } else { - this._satoshisBN = BN.fromNumber(num); - this._satoshis = num; + if (data.length !== HDPrivateKey.DataLength) { + return new hdErrors.InvalidLength(data); + } + if (!_.isUndefined(network)) { + var error = HDPrivateKey._validateNetwork(data, network); + if (error) { + return error; } } -}); + return null; +}; -Output.prototype._fromObject = function(param) { - this.satoshis = param.satoshis; - if (param.script || param.scriptBuffer) { - this.setScript(param.script || param.scriptBuffer); +HDPrivateKey._validateNetwork = function(data, networkArg) { + var network = Network.get(networkArg); + if (!network) { + return new errors.InvalidNetworkArgument(networkArg); } - return this; + var version = data.slice(0, 4); + if (BufferUtil.integerFromBuffer(version) !== network.xprivkey) { + return new errors.InvalidNetwork(version); + } + return null; }; -Output.prototype.toObject = function toObject() { - return { - satoshis: this.satoshis, - script: this.script.toString() - }; +HDPrivateKey.fromJSON = function(arg) { + $.checkArgument(JSUtil.isValidJSON(arg), 'No valid JSON string was provided'); + return new HDPrivateKey(arg); }; -Output.prototype.toJSON = function toJSON() { - return JSON.stringify(this.toObject()); +HDPrivateKey.fromString = function(arg) { + $.checkArgument(_.isString(arg), 'No valid string was provided'); + return new HDPrivateKey(arg); }; -Output.fromJSON = function(json) { - if (JSUtil.isValidJSON(json)) { - json = JSON.parse(json); - } - return new Output({ - satoshis: json.satoshis || +json.valuebn, - script: new Script(json.script) - }); +HDPrivateKey.fromObject = function(arg) { + $.checkArgument(_.isObject(arg), 'No valid argument was provided'); + return new HDPrivateKey(arg); }; -Output.prototype.setScript = function(script) { - if (script instanceof Script) { - this._scriptBuffer = script.toBuffer(); - this._script = script; - } else if (_.isString(script)) { - this._script = new Script(script); - this._scriptBuffer = this._script.toBuffer(); - } else if (bufferUtil.isBuffer(script)) { - this._scriptBuffer = script; - this._script = null; - } else { - throw new TypeError('Invalid argument type: script'); - } - return this; +HDPrivateKey.prototype._buildFromJSON = function(arg) { + return this._buildFromObject(JSON.parse(arg)); }; -Output.prototype.inspect = function() { - return ''; +HDPrivateKey.prototype._buildFromObject = function(arg) { + /* jshint maxcomplexity: 12 */ + // TODO: Type validation + var buffers = { + version: arg.network ? BufferUtil.integerAsBuffer(Network.get(arg.network).xprivkey) : arg.version, + depth: _.isNumber(arg.depth) ? BufferUtil.integerAsSingleByteBuffer(arg.depth) : arg.depth, + parentFingerPrint: _.isNumber(arg.parentFingerPrint) ? BufferUtil.integerAsBuffer(arg.parentFingerPrint) : arg.parentFingerPrint, + childIndex: _.isNumber(arg.childIndex) ? BufferUtil.integerAsBuffer(arg.childIndex) : arg.childIndex, + chainCode: _.isString(arg.chainCode) ? BufferUtil.hexToBuffer(arg.chainCode) : arg.chainCode, + privateKey: (_.isString(arg.privateKey) && JSUtil.isHexa(arg.privateKey)) ? BufferUtil.hexToBuffer(arg.privateKey) : arg.privateKey, + checksum: arg.checksum ? (arg.checksum.length ? arg.checksum : BufferUtil.integerAsBuffer(arg.checksum)) : undefined + }; + return this._buildFromBuffers(buffers); }; -Output.fromBufferReader = function(br) { - var output = new Output(); - output.satoshis = br.readUInt64LEBN(); - var size = br.readVarintNum(); - if (size !== 0) { - output._scriptBuffer = br.read(size); - } else { - output._scriptBuffer = new buffer.Buffer([]); - } - return output; +HDPrivateKey.prototype._buildFromSerialized = function(arg) { + var decoded = Base58Check.decode(arg); + var buffers = { + version: decoded.slice(HDPrivateKey.VersionStart, HDPrivateKey.VersionEnd), + depth: decoded.slice(HDPrivateKey.DepthStart, HDPrivateKey.DepthEnd), + parentFingerPrint: decoded.slice(HDPrivateKey.ParentFingerPrintStart, + HDPrivateKey.ParentFingerPrintEnd), + childIndex: decoded.slice(HDPrivateKey.ChildIndexStart, HDPrivateKey.ChildIndexEnd), + chainCode: decoded.slice(HDPrivateKey.ChainCodeStart, HDPrivateKey.ChainCodeEnd), + privateKey: decoded.slice(HDPrivateKey.PrivateKeyStart, HDPrivateKey.PrivateKeyEnd), + checksum: decoded.slice(HDPrivateKey.ChecksumStart, HDPrivateKey.ChecksumEnd), + xprivkey: arg + }; + return this._buildFromBuffers(buffers); }; -Output.prototype.toBufferWriter = function(writer) { - if (!writer) { - writer = new BufferWriter(); - } - writer.writeUInt64LEBN(this._satoshisBN); - var script = this._scriptBuffer; - writer.writeVarintNum(script.length); - writer.write(script); - return writer; +HDPrivateKey.prototype._generateRandomly = function(network) { + return HDPrivateKey.fromSeed(Random.getRandomBuffer(64), network); }; -module.exports = Output; - -},{"../crypto/bn":18,"../encoding/bufferwriter":27,"../script":38,"../util/buffer":53,"../util/js":54,"buffer":104,"lodash":79}],47:[function(require,module,exports){ -(function (Buffer){ -'use strict'; - -var buffer = require('buffer'); - -var Signature = require('../crypto/signature'); -var Script = require('../script'); -var Output = require('./output'); -var BufferReader = require('../encoding/bufferreader'); -var BufferWriter = require('../encoding/bufferwriter'); -var BN = require('../crypto/bn'); -var Hash = require('../crypto/hash'); -var ECDSA = require('../crypto/ecdsa'); -var $ = require('../util/preconditions'); -var _ = require('lodash'); +/** + * Generate a private key from a seed, as described in BIP32 + * + * @param {string|Buffer} hexa + * @param {*} network + * @return HDPrivateKey + */ +HDPrivateKey.fromSeed = function(hexa, network) { + /* jshint maxcomplexity: 8 */ + if (JSUtil.isHexaString(hexa)) { + hexa = BufferUtil.hexToBuffer(hexa); + } + if (!Buffer.isBuffer(hexa)) { + throw new hdErrors.InvalidEntropyArgument(hexa); + } + if (hexa.length < MINIMUM_ENTROPY_BITS * BITS_TO_BYTES) { + throw new hdErrors.InvalidEntropyArgument.NotEnoughEntropy(hexa); + } + if (hexa.length > MAXIMUM_ENTROPY_BITS * BITS_TO_BYTES) { + throw new hdErrors.InvalidEntropyArgument.TooMuchEntropy(hexa); + } + var hash = Hash.sha512hmac(hexa, new buffer.Buffer('Bitcoin seed')); -var SIGHASH_SINGLE_BUG = '0000000000000000000000000000000000000000000000000000000000000001'; -var BITS_64_ON = 'ffffffffffffffff'; + return new HDPrivateKey({ + network: Network.get(network) || Network.defaultNetwork, + depth: 0, + parentFingerPrint: 0, + childIndex: 0, + privateKey: hash.slice(0, 32), + chainCode: hash.slice(32, 64) + }); +}; /** - * Returns a buffer of length 32 bytes with the hash that needs to be signed - * for OP_CHECKSIG. + * Receives a object with buffers in all the properties and populates the + * internal structure * - * @name Signing.sighash - * @param {Transaction} transaction the transaction to sign - * @param {number} sighashType the type of the hash - * @param {number} inputNumber the input index for the signature - * @param {Script} subscript the script that will be signed + * @param {Object} arg + * @param {buffer.Buffer} arg.version + * @param {buffer.Buffer} arg.depth + * @param {buffer.Buffer} arg.parentFingerPrint + * @param {buffer.Buffer} arg.childIndex + * @param {buffer.Buffer} arg.chainCode + * @param {buffer.Buffer} arg.privateKey + * @param {buffer.Buffer} arg.checksum + * @param {string=} arg.xprivkey - if set, don't recalculate the base58 + * representation + * @return {HDPrivateKey} this */ -var sighash = function sighash(transaction, sighashType, inputNumber, subscript) { - var Transaction = require('./transaction'); - var Input = require('./input'); +HDPrivateKey.prototype._buildFromBuffers = function(arg) { + /* jshint maxcomplexity: 8 */ + /* jshint maxstatements: 20 */ - var i; - // Copy transaction - var txcopy = Transaction.shallowCopy(transaction); + HDPrivateKey._validateBufferArguments(arg); - // Copy script - subscript = new Script(subscript); - subscript.removeCodeseparators(); + JSUtil.defineImmutable(this, { + _buffers: arg + }); - for (i = 0; i < txcopy.inputs.length; i++) { - // Blank signatures for other inputs - txcopy.inputs[i] = new Input(txcopy.inputs[i]).setScript(Script.empty()); + var sequence = [ + arg.version, arg.depth, arg.parentFingerPrint, arg.childIndex, arg.chainCode, + BufferUtil.emptyBuffer(1), arg.privateKey + ]; + var concat = buffer.Buffer.concat(sequence); + if (!arg.checksum || !arg.checksum.length) { + arg.checksum = Base58Check.checksum(concat); + } else { + if (arg.checksum.toString() !== Base58Check.checksum(concat).toString()) { + throw new errors.InvalidB58Checksum(concat); + } } - txcopy.inputs[inputNumber] = new Input(txcopy.inputs[inputNumber]).setScript(subscript); - - if ((sighashType & 31) === Signature.SIGHASH_NONE || - (sighashType & 31) === Signature.SIGHASH_SINGLE) { + var xprivkey; + xprivkey = Base58Check.encode(buffer.Buffer.concat(sequence)); + arg.xprivkey = new Buffer(xprivkey); - // clear all sequenceNumbers - for (i = 0; i < txcopy.inputs.length; i++) { - if (i !== inputNumber) { - txcopy.inputs[i].sequenceNumber = 0; - } - } - } + var privateKey = new PrivateKey(BN.fromBuffer(arg.privateKey)); + var publicKey = privateKey.toPublicKey(); + var size = HDPrivateKey.ParentFingerPrintSize; + var fingerPrint = Hash.sha256ripemd160(publicKey.toBuffer()).slice(0, size); - if ((sighashType & 31) === Signature.SIGHASH_NONE) { - txcopy.outputs = []; + JSUtil.defineImmutable(this, { + xprivkey: xprivkey, + network: Network.get(BufferUtil.integerFromBuffer(arg.version)), + depth: BufferUtil.integerFromSingleByteBuffer(arg.depth), + privateKey: privateKey, + publicKey: publicKey, + fingerPrint: fingerPrint + }); - } else if ((sighashType & 31) === Signature.SIGHASH_SINGLE) { - // The SIGHASH_SINGLE bug. - // https://bitcointalk.org/index.php?topic=260595.0 - if (inputNumber > txcopy.outputs.length - 1) { - return new Buffer(SIGHASH_SINGLE_BUG, 'hex'); - } - if (txcopy.outputs.length <= inputNumber) { - throw new Error('Missing output to sign'); - } + var HDPublicKey = require('./hdpublickey'); + var hdPublicKey = new HDPublicKey(this); - txcopy.outputs.length = inputNumber + 1; + JSUtil.defineImmutable(this, { + hdPublicKey: hdPublicKey, + xpubkey: hdPublicKey.xpubkey + }); - for (i = 0; i < inputNumber; i++) { - txcopy.outputs[i] = new Output({ - satoshis: BN.fromBuffer(new buffer.Buffer(BITS_64_ON, 'hex')), - script: Script.empty() - }); - } - } + return this; +}; - if (sighashType & Signature.SIGHASH_ANYONECANPAY) { - txcopy.inputs = [txcopy.inputs[inputNumber]]; +HDPrivateKey._validateBufferArguments = function(arg) { + var checkBuffer = function(name, size) { + var buff = arg[name]; + assert(BufferUtil.isBuffer(buff), name + ' argument is not a buffer'); + assert( + buff.length === size, + name + ' has not the expected size: found ' + buff.length + ', expected ' + size + ); + }; + checkBuffer('version', HDPrivateKey.VersionSize); + checkBuffer('depth', HDPrivateKey.DepthSize); + checkBuffer('parentFingerPrint', HDPrivateKey.ParentFingerPrintSize); + checkBuffer('childIndex', HDPrivateKey.ChildIndexSize); + checkBuffer('chainCode', HDPrivateKey.ChainCodeSize); + checkBuffer('privateKey', HDPrivateKey.PrivateKeySize); + if (arg.checksum && arg.checksum.length) { + checkBuffer('checksum', HDPrivateKey.CheckSumSize); } - - var buf = new BufferWriter() - .write(txcopy.toBuffer()) - .writeInt32LE(sighashType) - .toBuffer(); - var ret = Hash.sha256sha256(buf); - ret = new BufferReader(ret).readReverse(); - return ret; }; /** - * Create a signature + * Returns the string representation of this private key (a string starting + * with "xprv..." * - * @name Signing.sign - * @param {Transaction} transaction - * @param {PrivateKey} privateKey - * @param {number} sighash - * @param {number} inputIndex - * @param {Script} subscript - * @return {Signature} + * @return string */ -function sign(transaction, privateKey, sighashType, inputIndex, subscript) { - var hashbuf = sighash(transaction, sighashType, inputIndex, subscript); - var sig = ECDSA.sign(hashbuf, privateKey, 'little').set({ - nhashtype: sighashType - }); - return sig; -} - -/** - * Verify a signature - * - * @name Signing.verify - * @param {Transaction} transaction - * @param {Signature} signature - * @param {PublicKey} publicKey - * @param {number} inputIndex - * @param {Script} subscript - * @return {boolean} - */ -function verify(transaction, signature, publicKey, inputIndex, subscript) { - $.checkArgument(!_.isUndefined(transaction)); - $.checkArgument(!_.isUndefined(signature) && !_.isUndefined(signature.nhashtype)); - var hashbuf = sighash(transaction, signature.nhashtype, inputIndex, subscript); - return ECDSA.verify(hashbuf, signature, publicKey, 'little'); -} - -/** - * @namespace Signing - */ -module.exports = { - sighash: sighash, - sign: sign, - verify: verify +HDPrivateKey.prototype.toString = function() { + return this.xprivkey; }; -}).call(this,require("buffer").Buffer) -},{"../crypto/bn":18,"../crypto/ecdsa":19,"../crypto/hash":20,"../crypto/signature":23,"../encoding/bufferreader":26,"../encoding/bufferwriter":27,"../script":38,"../util/preconditions":55,"./input":42,"./output":46,"./transaction":49,"buffer":104,"lodash":79}],48:[function(require,module,exports){ -(function (Buffer){ -'use strict'; - -var _ = require('lodash'); -var $ = require('../util/preconditions'); -var inherits = require('inherits'); -var BufferUtil = require('../util/buffer'); -var JSUtil = require('../util/js'); - -var PublicKey = require('../publickey'); -var errors = require('../errors'); -var Signature = require('../crypto/signature'); - /** - * @desc - * Wrapper around Signature with fields related to signing a transaction specifically - * - * @param {Object|string|TransactionSignature} arg - * @constructor + * Returns the console representation of this extended private key. + * @return string */ -function TransactionSignature(arg) { - if (!(this instanceof TransactionSignature)) { - return new TransactionSignature(arg); - } - if (arg instanceof TransactionSignature) { - return arg; - } - if (_.isString(arg)) { - if (JSUtil.isValidJSON(arg)) { - return TransactionSignature.fromJSON(arg); - } - } - if (_.isObject(arg)) { - return this._fromObject(arg); - } - throw new errors.InvalidArgument('TransactionSignatures must be instantiated from an object'); -} -inherits(TransactionSignature, Signature); - -TransactionSignature.prototype._fromObject = function(arg) { - this._checkObjectArgs(arg); - this.publicKey = new PublicKey(arg.publicKey); - this.prevTxId = BufferUtil.isBuffer(arg.prevTxId) ? arg.prevTxId : new Buffer(arg.prevTxId, 'hex'); - this.outputIndex = arg.outputIndex; - this.inputIndex = arg.inputIndex; - this.signature = (arg.signature instanceof Signature) ? arg.signature : - BufferUtil.isBuffer(arg.signature) ? Signature.fromBuffer(arg.signature) : - Signature.fromString(arg.signature); - this.sigtype = arg.sigtype; - return this; -}; - -TransactionSignature.prototype._checkObjectArgs = function(arg) { - $.checkArgument(PublicKey(arg.publicKey), 'publicKey'); - $.checkArgument(!_.isUndefined(arg.inputIndex), 'inputIndex'); - $.checkArgument(!_.isUndefined(arg.outputIndex), 'outputIndex'); - $.checkState(_.isNumber(arg.inputIndex), 'inputIndex must be a number'); - $.checkState(_.isNumber(arg.outputIndex), 'outputIndex must be a number'); - $.checkArgument(arg.signature, 'signature'); - $.checkArgument(arg.prevTxId, 'prevTxId'); - $.checkState(arg.signature instanceof Signature || - BufferUtil.isBuffer(arg.signature) || - JSUtil.isHexa(arg.signature), 'signature must be a buffer or hexa value'); - $.checkState(BufferUtil.isBuffer(arg.prevTxId) || - JSUtil.isHexa(arg.prevTxId), 'prevTxId must be a buffer or hexa value'); - $.checkArgument(arg.sigtype, 'sigtype'); - $.checkState(_.isNumber(arg.sigtype), 'sigtype must be a number'); +HDPrivateKey.prototype.inspect = function() { + return ''; }; /** - * Serializes a transaction to a plain JS object - * @return {Object} + * Returns a plain object with a representation of this private key. + * + * Fields include:
    + *
  • network: either 'livenet' or 'testnet' + *
  • depth: a number ranging from 0 to 255 + *
  • fingerPrint: a number ranging from 0 to 2^32-1, taken from the hash of the + *
  • associated public key + *
  • parentFingerPrint: a number ranging from 0 to 2^32-1, taken from the hash + *
  • of this parent's associated public key or zero. + *
  • childIndex: the index from which this child was derived (or zero) + *
  • chainCode: an hexa string representing a number used in the derivation + *
  • privateKey: the private key associated, in hexa representation + *
  • xprivkey: the representation of this extended private key in checksum + *
  • base58 format + *
  • checksum: the base58 checksum of xprivkey + *
+ * @return {Object} */ -TransactionSignature.prototype.toObject = function() { +HDPrivateKey.prototype.toObject = function toObject() { return { - publicKey: this.publicKey.toString(), - prevTxId: this.prevTxId.toString('hex'), - outputIndex: this.outputIndex, - inputIndex: this.inputIndex, - signature: this.signature.toString(), - sigtype: this.sigtype + network: Network.get(BufferUtil.integerFromBuffer(this._buffers.version)).name, + depth: BufferUtil.integerFromSingleByteBuffer(this._buffers.depth), + fingerPrint: BufferUtil.integerFromBuffer(this.fingerPrint), + parentFingerPrint: BufferUtil.integerFromBuffer(this._buffers.parentFingerPrint), + childIndex: BufferUtil.integerFromBuffer(this._buffers.childIndex), + chainCode: BufferUtil.bufferToHex(this._buffers.chainCode), + privateKey: this.privateKey.toBuffer().toString('hex'), + checksum: BufferUtil.integerFromBuffer(this._buffers.checksum), + xprivkey: this.xprivkey }; }; /** - * Serializes a transaction to a JSON string + * Returns a JSON representation of the HDPrivateKey + * * @return {string} */ -TransactionSignature.prototype.toJSON = function() { +HDPrivateKey.prototype.toJSON = function toJSON() { return JSON.stringify(this.toObject()); }; /** - * Builds a TransactionSignature from a JSON string - * @param {string} json - * @return {TransactionSignature} + * Build a HDPrivateKey from a buffer + * + * @param {Buffer} arg + * @return {HDPrivateKey} */ -TransactionSignature.fromJSON = function(json) { - return new TransactionSignature(JSON.parse(json)); +HDPrivateKey.fromBuffer = function(arg) { + return new HDPrivateKey(arg.toString()); }; /** - * Builds a TransactionSignature from an object - * @param {Object} object - * @return {TransactionSignature} + * Returns a buffer representation of the HDPrivateKey + * + * @return {string} */ -TransactionSignature.fromObject = function(object) { - $.checkArgument(object); - return new TransactionSignature(object); +HDPrivateKey.prototype.toBuffer = function() { + return BufferUtil.copy(this._buffers.xprivkey); }; -module.exports = TransactionSignature; +HDPrivateKey.DefaultDepth = 0; +HDPrivateKey.DefaultFingerprint = 0; +HDPrivateKey.DefaultChildIndex = 0; +HDPrivateKey.Hardened = 0x80000000; +HDPrivateKey.MaxIndex = 2 * HDPrivateKey.Hardened; + +HDPrivateKey.RootElementAlias = ['m', 'M', 'm\'', 'M\'']; + +HDPrivateKey.VersionSize = 4; +HDPrivateKey.DepthSize = 1; +HDPrivateKey.ParentFingerPrintSize = 4; +HDPrivateKey.ChildIndexSize = 4; +HDPrivateKey.ChainCodeSize = 32; +HDPrivateKey.PrivateKeySize = 32; +HDPrivateKey.CheckSumSize = 4; + +HDPrivateKey.DataLength = 78; +HDPrivateKey.SerializedByteSize = 82; + +HDPrivateKey.VersionStart = 0; +HDPrivateKey.VersionEnd = HDPrivateKey.VersionStart + HDPrivateKey.VersionSize; +HDPrivateKey.DepthStart = HDPrivateKey.VersionEnd; +HDPrivateKey.DepthEnd = HDPrivateKey.DepthStart + HDPrivateKey.DepthSize; +HDPrivateKey.ParentFingerPrintStart = HDPrivateKey.DepthEnd; +HDPrivateKey.ParentFingerPrintEnd = HDPrivateKey.ParentFingerPrintStart + HDPrivateKey.ParentFingerPrintSize; +HDPrivateKey.ChildIndexStart = HDPrivateKey.ParentFingerPrintEnd; +HDPrivateKey.ChildIndexEnd = HDPrivateKey.ChildIndexStart + HDPrivateKey.ChildIndexSize; +HDPrivateKey.ChainCodeStart = HDPrivateKey.ChildIndexEnd; +HDPrivateKey.ChainCodeEnd = HDPrivateKey.ChainCodeStart + HDPrivateKey.ChainCodeSize; +HDPrivateKey.PrivateKeyStart = HDPrivateKey.ChainCodeEnd + 1; +HDPrivateKey.PrivateKeyEnd = HDPrivateKey.PrivateKeyStart + HDPrivateKey.PrivateKeySize; +HDPrivateKey.ChecksumStart = HDPrivateKey.PrivateKeyEnd; +HDPrivateKey.ChecksumEnd = HDPrivateKey.ChecksumStart + HDPrivateKey.CheckSumSize; + +assert(HDPrivateKey.ChecksumEnd === HDPrivateKey.SerializedByteSize); + +module.exports = HDPrivateKey; }).call(this,require("buffer").Buffer) -},{"../crypto/signature":23,"../errors":29,"../publickey":37,"../util/buffer":53,"../util/js":54,"../util/preconditions":55,"buffer":104,"inherits":78,"lodash":79}],49:[function(require,module,exports){ +},{"./crypto/bn":34,"./crypto/hash":36,"./crypto/point":37,"./crypto/random":38,"./encoding/base58":40,"./encoding/base58check":41,"./errors":45,"./hdkeycache":47,"./hdpublickey":49,"./networks":50,"./privatekey":52,"./util/buffer":69,"./util/js":70,"./util/preconditions":71,"assert":194,"buffer":209,"lodash":95}],49:[function(require,module,exports){ +(function (Buffer){ 'use strict'; var _ = require('lodash'); -var $ = require('../util/preconditions'); -var buffer = require('buffer'); +var $ = require('./util/preconditions'); -var errors = require('../errors'); -var BufferUtil = require('../util/buffer'); -var JSUtil = require('../util/js'); -var BufferReader = require('../encoding/bufferreader'); -var BufferWriter = require('../encoding/bufferwriter'); -var Hash = require('../crypto/hash'); -var Signature = require('../crypto/signature'); -var Sighash = require('./sighash'); +var BN = require('./crypto/bn'); +var Base58 = require('./encoding/base58'); +var Base58Check = require('./encoding/base58check'); +var Hash = require('./crypto/hash'); +var HDPrivateKey = require('./hdprivatekey'); +var HDKeyCache = require('./hdkeycache'); +var Network = require('./networks'); +var Point = require('./crypto/point'); +var PublicKey = require('./publickey'); -var Address = require('../address'); -var UnspentOutput = require('./unspentoutput'); -var Input = require('./input'); -var PublicKeyHashInput = Input.PublicKeyHash; -var MultiSigScriptHashInput = Input.MultiSigScriptHash; -var Output = require('./output'); -var Script = require('../script'); -var PrivateKey = require('../privatekey'); -var Block = require('../block'); -var BN = require('../crypto/bn'); +var bitcoreErrors = require('./errors'); +var errors = bitcoreErrors; +var hdErrors = bitcoreErrors.HDPublicKey; +var assert = require('assert'); + +var JSUtil = require('./util/js'); +var BufferUtil = require('./util/buffer'); /** - * Represents a transaction, a set of inputs and outputs to change ownership of tokens + * The representation of an hierarchically derived public key. + * + * See https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki * - * @param {*} serialized * @constructor + * @param {Object|string|Buffer} arg */ -function Transaction(serialized) { - if (!(this instanceof Transaction)) { - return new Transaction(serialized); +function HDPublicKey(arg) { + /* jshint maxcomplexity: 12 */ + /* jshint maxstatements: 20 */ + if (arg instanceof HDPublicKey) { + return arg; } - this.inputs = []; - this.outputs = []; - this._inputAmount = undefined; - this._outputAmount = undefined; - - if (serialized) { - if (serialized instanceof Transaction) { - return Transaction.shallowCopy(serialized); - } else if (JSUtil.isHexa(serialized)) { - this.fromString(serialized); - } else if (JSUtil.isValidJSON(serialized)) { - this.fromJSON(serialized); - } else if (BufferUtil.isBuffer(serialized)) { - this.fromBuffer(serialized); - } else if (_.isObject(serialized)) { - this.fromObject(serialized); + if (!(this instanceof HDPublicKey)) { + return new HDPublicKey(arg); + } + if (arg) { + if (_.isString(arg) || BufferUtil.isBuffer(arg)) { + var error = HDPublicKey.getSerializedError(arg); + if (!error) { + return this._buildFromSerialized(arg); + } else if (JSUtil.isValidJSON(arg)) { + return this._buildFromJSON(arg); + } else if (BufferUtil.isBuffer(arg) && !HDPublicKey.getSerializedError(arg.toString())) { + return this._buildFromSerialized(arg.toString()); + } else { + if (error instanceof hdErrors.ArgumentIsPrivateExtended) { + return new HDPrivateKey(arg).hdPublicKey; + } + throw error; + } } else { - throw new errors.InvalidArgument('Must provide an object or string to deserialize a transaction'); + if (_.isObject(arg)) { + if (arg instanceof HDPrivateKey) { + return this._buildFromPrivate(arg); + } else { + return this._buildFromObject(arg); + } + } else { + throw new hdErrors.UnrecognizedArgument(arg); + } } } else { - this._newTransaction(); + throw new hdErrors.MustSupplyArgument(); } } -var CURRENT_VERSION = 1; -var DEFAULT_NLOCKTIME = 0; - -// Minimum amount for an output for it not to be considered a dust output -Transaction.DUST_AMOUNT = 546; - -// Margin of error to allow fees in the vecinity of the expected value but doesn't allow a big difference -Transaction.FEE_SECURITY_MARGIN = 15; - -// max amount of satoshis in circulation -Transaction.MAX_MONEY = 21000000 * 1e8; - -// nlocktime limit to be considered block height rather than a timestamp -Transaction.NLOCKTIME_BLOCKHEIGHT_LIMIT = 5e8; - -// Max value for an unsigned 32 bit value -Transaction.NLOCKTIME_MAX_VALUE = 4294967295; - -// Value used for fee estimation (satoshis per kilobyte) -Transaction.FEE_PER_KB = 10000; - -// Safe upper bound for change address script size in bytes -Transaction.CHANGE_OUTPUT_MAX_SIZE = 20 + 4 + 34 + 4; -Transaction.MAXIMUM_EXTRA_SIZE = 4 + 9 + 9 + 4; - -/* Constructors and Serialization */ - /** - * Create a 'shallow' copy of the transaction, by serializing and deserializing - * it dropping any additional information that inputs and outputs may have hold + * Verifies that a given path is valid. * - * @param {Transaction} transaction - * @return {Transaction} + * @param {string|number} arg + * @return {boolean} */ -Transaction.shallowCopy = function(transaction) { - var copy = new Transaction(transaction.toBuffer()); - return copy; -}; - -var hashProperty = { - configurable: false, - writeable: false, - enumerable: true, - get: function() { - return new BufferReader(this._getHash()).readReverse().toString('hex'); +HDPublicKey.isValidPath = function(arg) { + if (_.isString(arg)) { + var indexes = HDPrivateKey._getDerivationIndexes(arg); + return indexes !== null && _.all(indexes, HDPublicKey.isValidPath); } -}; -Object.defineProperty(Transaction.prototype, 'hash', hashProperty); -Object.defineProperty(Transaction.prototype, 'id', hashProperty); -var ioProperty = { - configurable: false, - writeable: false, - enumerable: true, - get: function() { - return this._getInputAmount(); + if (_.isNumber(arg)) { + return arg >= 0 && arg < HDPublicKey.Hardened; } -}; -Object.defineProperty(Transaction.prototype, 'inputAmount', ioProperty); -ioProperty.get = function() { - return this._getOutputAmount(); -}; -Object.defineProperty(Transaction.prototype, 'outputAmount', ioProperty); -/** - * Retrieve the little endian hash of the transaction (used for serialization) - * @return {Buffer} - */ -Transaction.prototype._getHash = function() { - return Hash.sha256sha256(this.toBuffer()); + return false; }; /** - * Retrieve a hexa string that can be used with bitcoind's CLI interface - * (decoderawtransaction, sendrawtransaction) + * Get a derivated child based on a string or number. * - * @param {Object|boolean=} unsafe if true, skip all tests. if it's an object, - * it's expected to contain a set of flags to skip certain tests: - * * `disableAll`: disable all checks - * * `disableSmallFees`: disable checking for fees that are too small - * * `disableLargeFees`: disable checking for fees that are too large - * * `disableNotFullySigned`: disable checking if all inputs are fully signed - * * `disableDustOutputs`: disable checking if there are no outputs that are dust amounts - * * `disableMoreOutputThanInput`: disable checking if the transaction spends more bitcoins than the sum of the input amounts - * @return {string} + * If the first argument is a string, it's parsed as the full path of + * derivation. Valid values for this argument include "m" (which returns the + * same public key), "m/0/1/40/2/1000". + * + * Note that hardened keys can't be derived from a public extended key. + * + * If the first argument is a number, the child with that index will be + * derived. See the example usage for clarification. + * + * @example + * ```javascript + * var parent = new HDPublicKey('xpub...'); + * var child_0_1_2 = parent.derive(0).derive(1).derive(2); + * var copy_of_child_0_1_2 = parent.derive("m/0/1/2"); + * assert(child_0_1_2.xprivkey === copy_of_child_0_1_2); + * ``` + * + * @param {string|number} arg */ -Transaction.prototype.serialize = function(unsafe) { - if (true === unsafe || unsafe && unsafe.disableAll) { - return this.uncheckedSerialize(); +HDPublicKey.prototype.derive = function (arg) { + if (_.isNumber(arg)) { + return this._deriveWithNumber(arg); + } else if (_.isString(arg)) { + return this._deriveFromString(arg); } else { - return this.checkedSerialize(unsafe); + throw new hdErrors.InvalidDerivationArgument(arg); } }; -Transaction.prototype.uncheckedSerialize = Transaction.prototype.toString = function() { - return this.toBuffer().toString('hex'); +HDPublicKey.prototype._deriveWithNumber = function (index) { + if (index >= HDPublicKey.Hardened) { + throw new hdErrors.InvalidIndexCantDeriveHardened(); + } + if (index < 0) { + throw new hdErrors.InvalidPath(index); + } + var cached = HDKeyCache.get(this.xpubkey, index, false); + if (cached) { + return cached; + } + + var indexBuffer = BufferUtil.integerAsBuffer(index); + var data = BufferUtil.concat([this.publicKey.toBuffer(), indexBuffer]); + var hash = Hash.sha512hmac(data, this._buffers.chainCode); + var leftPart = BN.fromBuffer(hash.slice(0, 32), {size: 32}); + var chainCode = hash.slice(32, 64); + + var publicKey = PublicKey.fromPoint(Point.getG().mul(leftPart).add(this.publicKey.point)); + + var derived = new HDPublicKey({ + network: this.network, + depth: this.depth + 1, + parentFingerPrint: this.fingerPrint, + childIndex: index, + chainCode: chainCode, + publicKey: publicKey + }); + HDKeyCache.set(this.xpubkey, index, false, derived); + return derived; +}; + +HDPublicKey.prototype._deriveFromString = function (path) { + /* jshint maxcomplexity: 8 */ + if (_.contains(path, "'")) { + throw new hdErrors.InvalidIndexCantDeriveHardened(); + } else if (!HDPublicKey.isValidPath(path)) { + throw new hdErrors.InvalidPath(path); + } + + var indexes = HDPrivateKey._getDerivationIndexes(path); + var derived = indexes.reduce(function(prev, index) { + return prev._deriveWithNumber(index); + }, this); + + return derived; }; /** - * Retrieve a hexa string that can be used with bitcoind's CLI interface - * (decoderawtransaction, sendrawtransaction) + * Verifies that a given serialized public key in base58 with checksum format + * is valid. * - * @param {Object} opts allows to skip certain tests. {@see Transaction#serialize} - * @return {string} + * @param {string|Buffer} data - the serialized public key + * @param {string|Network=} network - optional, if present, checks that the + * network provided matches the network serialized. + * @return {boolean} */ -Transaction.prototype.checkedSerialize = function(opts) { - var serializationError = this.getSerializationError(opts); - if (serializationError) { - serializationError.message += ' Use Transaction#uncheckedSerialize if you want to skip security checks. ' + - 'See http://bitcore.io/guide/transaction.html#Serialization for more info.' - throw serializationError; - } - return this.uncheckedSerialize(); +HDPublicKey.isValidSerialized = function (data, network) { + return _.isNull(HDPublicKey.getSerializedError(data, network)); }; /** - * Retrieve a possible error that could appear when trying to serialize and broadcast this transaction + * Checks what's the error that causes the validation of a serialized public key + * in base58 with checksum to fail. * - * @param {Object} opts allows to skip certain tests. {@see Transaction#serialize} - * @return {bitcore.Error} + * @param {string|Buffer} data - the serialized public key + * @param {string|Network=} network - optional, if present, checks that the + * network provided matches the network serialized. + * @return {errors|null} */ -Transaction.prototype.getSerializationError = function(opts) { - opts = opts || {}; - var missingChange = this._missingChange(); - var feeIsTooLarge = this._isFeeTooLarge(); - var feeIsTooSmall = this._isFeeTooSmall(); - var isFullySigned = this.isFullySigned(); - var hasDustOutputs = this._hasDustOutputs(); - - if (!opts.disableLargeFees && feeIsTooLarge) { - if (missingChange) { - return new errors.Transaction.ChangeAddressMissing('Fee is too large and no change address was provided'); - } - return new errors.Transaction.FeeError(feeIsTooLarge); - } - if (!opts.disableSmallFees && feeIsTooSmall) { - return new errors.Transaction.FeeError(feeIsTooSmall); +HDPublicKey.getSerializedError = function (data, network) { + /* jshint maxcomplexity: 10 */ + /* jshint maxstatements: 20 */ + if (!(_.isString(data) || BufferUtil.isBuffer(data))) { + return new hdErrors.UnrecognizedArgument('expected buffer or string'); } - if (!opts.disableDustOutputs && this._hasDustOutputs()) { - return new errors.Transaction.DustOutputs(); + if (!Base58.validCharacters(data)) { + return new errors.InvalidB58Char('(unknown)', data); } - if (!opts.disableIsFullySigned && !isFullySigned) { - return new errors.Transaction.MissingSignatures(); + try { + data = Base58Check.decode(data); + } catch (e) { + return new errors.InvalidB58Checksum(data); } - if (!opts.disableMoreOutputThanInput && this._getUnspentValue < 0) { - return new errors.Transaction.InvalidOutputAmountSum(); + if (data.length !== HDPublicKey.DataSize) { + return new errors.InvalidLength(data); } -}; - -Transaction.prototype._isFeeTooLarge = function() { - var fee = this._getUnspentValue(); - var maximumFee = Math.floor(Transaction.FEE_SECURITY_MARGIN * this._estimateFee()); - if (fee > maximumFee) { - return 'Fee is too large: expected less than ' + maximumFee + ' but got ' + fee; + if (!_.isUndefined(network)) { + var error = HDPublicKey._validateNetwork(data, network); + if (error) { + return error; + } } -}; - -Transaction.prototype._isFeeTooSmall = function() { - var fee = this._getUnspentValue(); - var minimumFee = Math.ceil(this._estimateFee() / Transaction.FEE_SECURITY_MARGIN); - if (fee < minimumFee) { - return 'Fee is too small: expected more than ' + minimumFee + ' but got ' + fee; + var version = BufferUtil.integerFromBuffer(data.slice(0, 4)); + if (version === Network.livenet.xprivkey || version === Network.testnet.xprivkey ) { + return new hdErrors.ArgumentIsPrivateExtended(); } + return null; }; -Transaction.prototype._missingChange = function() { - return !this._changeScript; -}; - -Transaction.prototype._hasDustOutputs = function() { - var index, output; - for (index in this.outputs) { - output = this.outputs[index]; - if (output.satoshis < Transaction.DUST_AMOUNT && !output.script.isDataOut()) { - return true; - } +HDPublicKey._validateNetwork = function (data, networkArg) { + var network = Network.get(networkArg); + if (!network) { + return new errors.InvalidNetworkArgument(networkArg); } - return false; + var version = data.slice(HDPublicKey.VersionStart, HDPublicKey.VersionEnd); + if (BufferUtil.integerFromBuffer(version) !== network.xpubkey) { + return new errors.InvalidNetwork(version); + } + return null; }; -Transaction.prototype.inspect = function() { - return ''; +HDPublicKey.prototype._buildFromJSON = function (arg) { + return this._buildFromObject(JSON.parse(arg)); }; -Transaction.prototype.toBuffer = function() { - var writer = new BufferWriter(); - return this.toBufferWriter(writer).toBuffer(); +HDPublicKey.prototype._buildFromPrivate = function (arg) { + var args = _.clone(arg._buffers); + var point = Point.getG().mul(BN.fromBuffer(args.privateKey)); + args.publicKey = Point.pointToCompressed(point); + args.version = BufferUtil.integerAsBuffer(Network.get(BufferUtil.integerFromBuffer(args.version)).xpubkey); + args.privateKey = undefined; + args.checksum = undefined; + args.xprivkey = undefined; + return this._buildFromBuffers(args); }; -Transaction.prototype.toBufferWriter = function(writer) { - writer.writeUInt32LE(this.version); - writer.writeVarintNum(this.inputs.length); - _.each(this.inputs, function(input) { - input.toBufferWriter(writer); - }); - writer.writeVarintNum(this.outputs.length); - _.each(this.outputs, function(output) { - output.toBufferWriter(writer); - }); - writer.writeUInt32LE(this.nLockTime); - return writer; +HDPublicKey.prototype._buildFromObject = function (arg) { + /* jshint maxcomplexity: 10 */ + // TODO: Type validation + var buffers = { + version: arg.network ? BufferUtil.integerAsBuffer(Network.get(arg.network).xpubkey) : arg.version, + depth: _.isNumber(arg.depth) ? BufferUtil.integerAsSingleByteBuffer(arg.depth) : arg.depth, + parentFingerPrint: _.isNumber(arg.parentFingerPrint) ? BufferUtil.integerAsBuffer(arg.parentFingerPrint) : arg.parentFingerPrint, + childIndex: _.isNumber(arg.childIndex) ? BufferUtil.integerAsBuffer(arg.childIndex) : arg.childIndex, + chainCode: _.isString(arg.chainCode) ? BufferUtil.hexToBuffer(arg.chainCode) : arg.chainCode, + publicKey: _.isString(arg.publicKey) ? BufferUtil.hexToBuffer(arg.publicKey) : + BufferUtil.isBuffer(arg.publicKey) ? arg.publicKey : arg.publicKey.toBuffer(), + checksum: _.isNumber(arg.checksum) ? BufferUtil.integerAsBuffer(arg.checksum) : arg.checksum + }; + return this._buildFromBuffers(buffers); }; -Transaction.prototype.fromBuffer = function(buffer) { - var reader = new BufferReader(buffer); - return this.fromBufferReader(reader); +HDPublicKey.prototype._buildFromSerialized = function (arg) { + var decoded = Base58Check.decode(arg); + var buffers = { + version: decoded.slice(HDPublicKey.VersionStart, HDPublicKey.VersionEnd), + depth: decoded.slice(HDPublicKey.DepthStart, HDPublicKey.DepthEnd), + parentFingerPrint: decoded.slice(HDPublicKey.ParentFingerPrintStart, + HDPublicKey.ParentFingerPrintEnd), + childIndex: decoded.slice(HDPublicKey.ChildIndexStart, HDPublicKey.ChildIndexEnd), + chainCode: decoded.slice(HDPublicKey.ChainCodeStart, HDPublicKey.ChainCodeEnd), + publicKey: decoded.slice(HDPublicKey.PublicKeyStart, HDPublicKey.PublicKeyEnd), + checksum: decoded.slice(HDPublicKey.ChecksumStart, HDPublicKey.ChecksumEnd), + xpubkey: arg + }; + return this._buildFromBuffers(buffers); }; -Transaction.prototype.fromBufferReader = function(reader) { - $.checkArgument(!reader.finished(), 'No transaction data received'); - var i, sizeTxIns, sizeTxOuts; - - this.version = reader.readUInt32LE(); - sizeTxIns = reader.readVarintNum(); - for (i = 0; i < sizeTxIns; i++) { - var input = Input.fromBufferReader(reader); - this.inputs.push(input); - } - sizeTxOuts = reader.readVarintNum(); - for (i = 0; i < sizeTxOuts; i++) { - this.outputs.push(Output.fromBufferReader(reader)); - } - this.nLockTime = reader.readUInt32LE(); - return this; -}; +/** + * Receives a object with buffers in all the properties and populates the + * internal structure + * + * @param {Object} arg + * @param {buffer.Buffer} arg.version + * @param {buffer.Buffer} arg.depth + * @param {buffer.Buffer} arg.parentFingerPrint + * @param {buffer.Buffer} arg.childIndex + * @param {buffer.Buffer} arg.chainCode + * @param {buffer.Buffer} arg.publicKey + * @param {buffer.Buffer} arg.checksum + * @param {string=} arg.xpubkey - if set, don't recalculate the base58 + * representation + * @return {HDPublicKey} this + */ +HDPublicKey.prototype._buildFromBuffers = function (arg) { + /* jshint maxcomplexity: 8 */ + /* jshint maxstatements: 20 */ -Transaction.prototype.fromJSON = function(json) { - if (JSUtil.isValidJSON(json)) { - json = JSON.parse(json); - } - return this.fromObject(json); -}; + HDPublicKey._validateBufferArguments(arg); -Transaction.prototype.toObject = function toObject() { - var inputs = []; - this.inputs.forEach(function(input) { - inputs.push(input.toObject()); - }); - var outputs = []; - this.outputs.forEach(function(output) { - outputs.push(output.toObject()); + JSUtil.defineImmutable(this, { + _buffers: arg }); - var obj = { - version: this.version, - inputs: inputs, - outputs: outputs, - nLockTime: this.nLockTime - }; - if (this._changeScript) { - obj.changeScript = this._changeScript.toString(); - } - if (!_.isUndefined(this._changeIndex)) { - obj.changeIndex = this._changeIndex; - } - if (!_.isUndefined(this._fee)) { - obj.fee = this._fee; - } - return obj; -}; -Transaction.prototype.fromObject = function(transaction) { - var self = this; - _.each(transaction.inputs, function(input) { - if (!input.output || !input.output.script) { - self.uncheckedAddInput(new Input(input)); - return; - } - input.output.script = new Script(input.output.script); - var txin; - if (input.output.script.isPublicKeyHashOut()) { - txin = new Input.PublicKeyHash(input); - } else if (input.output.script.isScriptHashOut() && input.publicKeys && input.threshold) { - txin = new Input.MultiSigScriptHash( - input, input.publicKeys, input.threshold, input.signatures - ); - } else { - throw new errors.Transaction.Input.UnsupportedScript(input.output.script); + var sequence = [ + arg.version, arg.depth, arg.parentFingerPrint, arg.childIndex, arg.chainCode, + arg.publicKey + ]; + var concat = BufferUtil.concat(sequence); + var checksum = Base58Check.checksum(concat); + if (!arg.checksum || !arg.checksum.length) { + arg.checksum = checksum; + } else { + if (arg.checksum.toString('hex') !== checksum.toString('hex')) { + throw new errors.InvalidB58Checksum(concat, checksum); } - self.addInput(txin); - }); - _.each(transaction.outputs, function(output) { - self.addOutput(new Output(output)); - }); - if (transaction.changeIndex) { - this._changeIndex = transaction.changeIndex; - } - if (transaction.changeScript) { - this._changeScript = new Script(transaction.changeScript); - } - if (transaction.fee) { - this.fee(transaction.fee); } - this.nLockTime = transaction.nLockTime; - this.version = transaction.version; - this._checkConsistency(); - return this; -}; -Transaction.prototype._checkConsistency = function() { - if (!_.isUndefined(this._changeIndex)) { - $.checkState(this._changeScript); - $.checkState(this.outputs[this._changeIndex]); - $.checkState(this.outputs[this._changeIndex].script.toString() === - this._changeScript.toString()); - } - // TODO: add other checks -}; + var xpubkey; + xpubkey = Base58Check.encode(BufferUtil.concat(sequence)); + arg.xpubkey = new Buffer(xpubkey); -/** - * Sets nLockTime so that transaction is not valid until the desired date(a - * timestamp in seconds since UNIX epoch is also accepted) - * - * @param {Date | Number} time - * @return {Transaction} this - */ -Transaction.prototype.lockUntilDate = function(time) { - $.checkArgument(time); - if (_.isNumber(time) && time < Transaction.NLOCKTIME_BLOCKHEIGHT_LIMIT) { - throw new errors.Transaction.LockTimeTooEarly(); - } - if (_.isDate(time)) { - time = time.getTime() / 1000; - } - this.nLockTime = time; - return this; -}; + var publicKey = PublicKey.fromString(arg.publicKey); + var size = HDPublicKey.ParentFingerPrintSize; + var fingerPrint = Hash.sha256ripemd160(publicKey.toBuffer()).slice(0, size); + + JSUtil.defineImmutable(this, { + xpubkey: xpubkey, + network: Network.get(BufferUtil.integerFromBuffer(arg.version)), + depth: BufferUtil.integerFromSingleByteBuffer(arg.depth), + publicKey: publicKey, + fingerPrint: fingerPrint + }); -/** - * Sets nLockTime so that transaction is not valid until the desired block - * height. - * - * @param {Number} height - * @return {Transaction} this - */ -Transaction.prototype.lockUntilBlockHeight = function(height) { - $.checkArgument(_.isNumber(height)); - if (height >= Transaction.NLOCKTIME_BLOCKHEIGHT_LIMIT) { - throw new errors.Transaction.BlockHeightTooHigh(); - } - if (height < 0) { - throw new errors.Transaction.NLockTimeOutOfRange(); - } - this.nLockTime = height; return this; }; -/** - * Returns a semantic version of the transaction's nLockTime. - * @return {Number|Date} - * If nLockTime is 0, it returns null, - * if it is < 500000000, it returns a block height (number) - * else it returns a Date object. - */ -Transaction.prototype.getLockTime = function() { - if (!this.nLockTime) { - return null; - } - if (this.nLockTime < Transaction.NLOCKTIME_BLOCKHEIGHT_LIMIT) { - return this.nLockTime; +HDPublicKey._validateBufferArguments = function (arg) { + var checkBuffer = function(name, size) { + var buff = arg[name]; + assert(BufferUtil.isBuffer(buff), name + ' argument is not a buffer, it\'s ' + typeof buff); + assert( + buff.length === size, + name + ' has not the expected size: found ' + buff.length + ', expected ' + size + ); + }; + checkBuffer('version', HDPublicKey.VersionSize); + checkBuffer('depth', HDPublicKey.DepthSize); + checkBuffer('parentFingerPrint', HDPublicKey.ParentFingerPrintSize); + checkBuffer('childIndex', HDPublicKey.ChildIndexSize); + checkBuffer('chainCode', HDPublicKey.ChainCodeSize); + checkBuffer('publicKey', HDPublicKey.PublicKeySize); + if (arg.checksum && arg.checksum.length) { + checkBuffer('checksum', HDPublicKey.CheckSumSize); } - return new Date(1000 * this.nLockTime); }; -Transaction.prototype.toJSON = function toJSON() { - return JSON.stringify(this.toObject()); +HDPublicKey.fromJSON = function(arg) { + $.checkArgument(JSUtil.isValidJSON(arg), 'No valid JSON string was provided'); + return new HDPublicKey(arg); }; -Transaction.prototype.fromString = function(string) { - this.fromBuffer(new buffer.Buffer(string, 'hex')); +HDPublicKey.fromObject = function(arg) { + $.checkArgument(_.isObject(arg), 'No valid argument was provided'); + return new HDPublicKey(arg); }; -Transaction.prototype._newTransaction = function() { - this.version = CURRENT_VERSION; - this.nLockTime = DEFAULT_NLOCKTIME; +HDPublicKey.fromString = function(arg) { + $.checkArgument(_.isString(arg), 'No valid string was provided'); + return new HDPublicKey(arg); }; -/* Transaction creation interface */ - /** - * Add an input to this transaction. This is a high level interface - * to add an input, for more control, use @{link Transaction#addInput}. - * - * Can receive, as output information, the output of bitcoind's `listunspent` command, - * and a slightly fancier format recognized by bitcore: - * - * ``` - * { - * address: 'mszYqVnqKoQx4jcTdJXxwKAissE3Jbrrc1', - * txId: 'a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458', - * outputIndex: 0, - * script: Script.empty(), - * satoshis: 1020000 - * } - * ``` - * Where `address` can be either a string or a bitcore Address object. The - * same is true for `script`, which can be a string or a bitcore Script. - * - * Beware that this resets all the signatures for inputs (in further versions, - * SIGHASH_SINGLE or SIGHASH_NONE signatures will not be reset). - * - * @example - * ```javascript - * var transaction = new Transaction(); - * - * // From a pay to public key hash output from bitcoind's listunspent - * transaction.from({'txid': '0000...', vout: 0, amount: 0.1, scriptPubKey: 'OP_DUP ...'}); - * - * // From a pay to public key hash output - * transaction.from({'txId': '0000...', outputIndex: 0, satoshis: 1000, script: 'OP_DUP ...'}); - * - * // From a multisig P2SH output - * transaction.from({'txId': '0000...', inputIndex: 0, satoshis: 1000, script: '... OP_HASH'}, - * ['03000...', '02000...'], 2); - * ``` - * - * @param {Object} utxo - * @param {Array=} pubkeys - * @param {number=} threshold + * Returns the base58 checked representation of the public key + * @return {string} a string starting with "xpub..." in livenet */ -Transaction.prototype.from = function(utxo, pubkeys, threshold) { - if (_.isArray(utxo)) { - var self = this; - _.each(utxo, function(utxo) { - self.from(utxo, pubkeys, threshold); - }); - return this; - } - var exists = _.any(this.inputs, function(input) { - // TODO: Maybe prevTxId should be a string? Or defined as read only property? - return input.prevTxId.toString('hex') === utxo.txId && input.outputIndex === utxo.outputIndex; - }); - if (exists) { - return; - } - if (pubkeys && threshold) { - this._fromMultisigUtxo(utxo, pubkeys, threshold); - } else { - this._fromNonP2SH(utxo); - } - return this; -}; - -Transaction.prototype._fromNonP2SH = function(utxo) { - var clazz; - utxo = new UnspentOutput(utxo); - if (utxo.script.isPublicKeyHashOut()) { - clazz = PublicKeyHashInput; - } else { - clazz = Input; - } - this.addInput(new clazz({ - output: new Output({ - script: utxo.script, - satoshis: utxo.satoshis - }), - prevTxId: utxo.txId, - outputIndex: utxo.outputIndex, - script: Script.empty() - })); +HDPublicKey.prototype.toString = function () { + return this.xpubkey; }; -Transaction.prototype._fromMultisigUtxo = function(utxo, pubkeys, threshold) { - $.checkArgument(threshold <= pubkeys.length, - 'Number of required signatures must be greater than the number of public keys'); - utxo = new UnspentOutput(utxo); - this.addInput(new MultiSigScriptHashInput({ - output: new Output({ - script: utxo.script, - satoshis: utxo.satoshis - }), - prevTxId: utxo.txId, - outputIndex: utxo.outputIndex, - script: Script.empty() - }, pubkeys, threshold)); +/** + * Returns the console representation of this extended public key. + * @return string + */ +HDPublicKey.prototype.inspect = function() { + return ''; }; /** - * Add an input to this transaction. The input must be an instance of the `Input` class. - * It should have information about the Output that it's spending, but if it's not already - * set, two additional parameters, `outputScript` and `satoshis` can be provided. + * Returns a plain javascript object with information to reconstruct a key. * - * @param {Input} input - * @param {String|Script} outputScript - * @param {number} satoshis - * @return Transaction this, for chaining + * Fields are:
    + *
  • network: 'livenet' or 'testnet' + *
  • depth: a number from 0 to 255, the depth to the master extended key + *
  • fingerPrint: a number of 32 bits taken from the hash of the public key + *
  • fingerPrint: a number of 32 bits taken from the hash of this key's + *
  • parent's public key + *
  • childIndex: index with which this key was derived + *
  • chainCode: string in hexa encoding used for derivation + *
  • publicKey: string, hexa encoded, in compressed key format + *
  • checksum: BufferUtil.integerFromBuffer(this._buffers.checksum), + *
  • xpubkey: the string with the base58 representation of this extended key + *
  • checksum: the base58 checksum of xpubkey + *
*/ -Transaction.prototype.addInput = function(input, outputScript, satoshis) { - $.checkArgumentType(input, Input, 'input'); - if (!input.output && (_.isUndefined(outputScript) || _.isUndefined(satoshis))) { - throw new errors.Transaction.NeedMoreInfo('Need information about the UTXO script and satoshis'); - } - if (!input.output && outputScript && !_.isUndefined(satoshis)) { - outputScript = outputScript instanceof Script ? outputScript : new Script(outputScript); - $.checkArgumentType(satoshis, 'number', 'satoshis'); - input.output = new Output({ - script: outputScript, - satoshis: satoshis - }); - } - return this.uncheckedAddInput(input); +HDPublicKey.prototype.toObject = function toObject() { + return { + network: Network.get(BufferUtil.integerFromBuffer(this._buffers.version)).name, + depth: BufferUtil.integerFromSingleByteBuffer(this._buffers.depth), + fingerPrint: BufferUtil.integerFromBuffer(this.fingerPrint), + parentFingerPrint: BufferUtil.integerFromBuffer(this._buffers.parentFingerPrint), + childIndex: BufferUtil.integerFromBuffer(this._buffers.childIndex), + chainCode: BufferUtil.bufferToHex(this._buffers.chainCode), + publicKey: this.publicKey.toString(), + checksum: BufferUtil.integerFromBuffer(this._buffers.checksum), + xpubkey: this.xpubkey + }; }; /** - * Add an input to this transaction, without checking that the input has information about - * the output that it's spending. - * - * @param {Input} input - * @return Transaction this, for chaining + * Serializes this object into a JSON string + * @return {string} */ -Transaction.prototype.uncheckedAddInput = function(input) { - $.checkArgumentType(input, Input, 'input'); - this.inputs.push(input); - this._updateChangeOutput(); - return this; +HDPublicKey.prototype.toJSON = function toJSON() { + return JSON.stringify(this.toObject()); }; /** - * Returns true if the transaction has enough info on all inputs to be correctly validated + * Create a HDPublicKey from a buffer argument * - * @return {boolean} + * @param {Buffer} arg + * @return {HDPublicKey} */ -Transaction.prototype.hasAllUtxoInfo = function() { - return _.all(this.inputs.map(function(input) { - return !!input.output; - })); +HDPublicKey.fromBuffer = function(arg) { + return new HDPublicKey(arg); }; /** - * Manually set the fee for this transaction. Beware that this resets all the signatures - * for inputs (in further versions, SIGHASH_SINGLE or SIGHASH_NONE signatures will not - * be reset). + * Return a buffer representation of the xpubkey * - * @param {number} amount satoshis to be sent - * @return {Transaction} this, for chaining + * @return {Buffer} */ -Transaction.prototype.fee = function(amount) { - this._fee = amount; - this._updateChangeOutput(); - return this; +HDPublicKey.prototype.toBuffer = function() { + return BufferUtil.copy(this._buffers.xpubkey); }; -/* Output management */ +HDPublicKey.Hardened = 0x80000000; +HDPublicKey.RootElementAlias = ['m', 'M']; -/** - * Set the change address for this transaction - * - * Beware that this resets all the signatures for inputs (in further versions, - * SIGHASH_SINGLE or SIGHASH_NONE signatures will not be reset). - * - * @param {address} An address for change to be sent to. - * @return {Transaction} this, for chaining - */ -Transaction.prototype.change = function(address) { - this._changeScript = Script.fromAddress(address); - this._updateChangeOutput(); - return this; -}; +HDPublicKey.VersionSize = 4; +HDPublicKey.DepthSize = 1; +HDPublicKey.ParentFingerPrintSize = 4; +HDPublicKey.ChildIndexSize = 4; +HDPublicKey.ChainCodeSize = 32; +HDPublicKey.PublicKeySize = 33; +HDPublicKey.CheckSumSize = 4; +HDPublicKey.DataSize = 78; +HDPublicKey.SerializedByteSize = 82; -/** - * @return {Output} change output, if it exists - */ -Transaction.prototype.getChangeOutput = function() { - if (!_.isUndefined(this._changeIndex)) { - return this.outputs[this._changeIndex]; - } - return null; -}; +HDPublicKey.VersionStart = 0; +HDPublicKey.VersionEnd = HDPublicKey.VersionStart + HDPublicKey.VersionSize; +HDPublicKey.DepthStart = HDPublicKey.VersionEnd; +HDPublicKey.DepthEnd = HDPublicKey.DepthStart + HDPublicKey.DepthSize; +HDPublicKey.ParentFingerPrintStart = HDPublicKey.DepthEnd; +HDPublicKey.ParentFingerPrintEnd = HDPublicKey.ParentFingerPrintStart + HDPublicKey.ParentFingerPrintSize; +HDPublicKey.ChildIndexStart = HDPublicKey.ParentFingerPrintEnd; +HDPublicKey.ChildIndexEnd = HDPublicKey.ChildIndexStart + HDPublicKey.ChildIndexSize; +HDPublicKey.ChainCodeStart = HDPublicKey.ChildIndexEnd; +HDPublicKey.ChainCodeEnd = HDPublicKey.ChainCodeStart + HDPublicKey.ChainCodeSize; +HDPublicKey.PublicKeyStart = HDPublicKey.ChainCodeEnd; +HDPublicKey.PublicKeyEnd = HDPublicKey.PublicKeyStart + HDPublicKey.PublicKeySize; +HDPublicKey.ChecksumStart = HDPublicKey.PublicKeyEnd; +HDPublicKey.ChecksumEnd = HDPublicKey.ChecksumStart + HDPublicKey.CheckSumSize; -/** - * Add an output to the transaction. - * - * Beware that this resets all the signatures for inputs (in further versions, - * SIGHASH_SINGLE or SIGHASH_NONE signatures will not be reset). - * - * @param {string|Address} address - * @param {number} amount in satoshis - * @return {Transaction} this, for chaining - */ -Transaction.prototype.to = function(address, amount) { - this.addOutput(new Output({ - script: Script(new Address(address)), - satoshis: amount - })); - return this; -}; +assert(HDPublicKey.PublicKeyEnd === HDPublicKey.DataSize); +assert(HDPublicKey.ChecksumEnd === HDPublicKey.SerializedByteSize); -/** - * Add an OP_RETURN output to the transaction. - * - * Beware that this resets all the signatures for inputs (in further versions, - * SIGHASH_SINGLE or SIGHASH_NONE signatures will not be reset). - * - * @param {Buffer|string} value the data to be stored in the OP_RETURN output. - * In case of a string, the UTF-8 representation will be stored - * @return {Transaction} this, for chaining - */ -Transaction.prototype.addData = function(value) { - this.addOutput(new Output({ - script: Script.buildDataOut(value), - satoshis: 0 - })); - return this; -}; +module.exports = HDPublicKey; + +}).call(this,require("buffer").Buffer) +},{"./crypto/bn":34,"./crypto/hash":36,"./crypto/point":37,"./encoding/base58":40,"./encoding/base58check":41,"./errors":45,"./hdkeycache":47,"./hdprivatekey":48,"./networks":50,"./publickey":53,"./util/buffer":69,"./util/js":70,"./util/preconditions":71,"assert":194,"buffer":209,"lodash":95}],50:[function(require,module,exports){ +'use strict'; +var _ = require('lodash'); +var BufferUtil = require('./util/buffer'); +var networks = []; +var networkMaps = {}; /** - * Add an output to the transaction. - * - * @param {Output} output the output to add. - * @return {Transaction} this, for chaining + * A network is merely a map containing values that correspond to version + * numbers for each bitcoin network. Currently only supporting "livenet" + * (a.k.a. "mainnet") and "testnet". + * @constructor */ -Transaction.prototype.addOutput = function(output) { - $.checkArgumentType(output, Output, 'output'); - this._addOutput(output); - this._updateChangeOutput(); - return this; -}; +function Network() {} -Transaction.prototype._addOutput = function(output) { - this.outputs.push(output); - this._outputAmount = undefined; +Network.prototype.toString = function toString() { + return this.name; }; - /** - * Calculates or gets the total output amount in satoshis - * - * @return {Number} the transaction total output amount + * @function + * @member Networks#get + * Retrieves the network associated with a magic number or string. + * @param {string|number|Network} arg + * @param {string} key - if set, only check if the magic number associated with this name matches + * @return Network */ -Transaction.prototype._getOutputAmount = function() { - if (_.isUndefined(this._outputAmount)) { - var self = this; - this._outputAmount = 0; - _.each(this.outputs, function(output) { - self._outputAmount += output.satoshis; - }); +function getNetwork(arg, key) { + if (~networks.indexOf(arg)) { + return arg; } - return this._outputAmount; -}; - - -/** - * Calculates or gets the total input amount in satoshis - * - * @return {Number} the transaction total input amount - */ -Transaction.prototype._getInputAmount = function() { - if (_.isUndefined(this._inputAmount)) { - var self = this; - this._inputAmount = 0; - _.each(this.inputs, function(input) { - if (_.isUndefined(input.output)) { - throw new errors.Transaction.Input.MissingPreviousOutput(); + if (key) { + for (var index in networks) { + if (networks[index][key] === arg) { + return networks[index]; } - self._inputAmount += input.output.satoshis; - }); + } + return undefined; } - return this._inputAmount; -}; + return networkMaps[arg]; +} -Transaction.prototype._updateChangeOutput = function() { - if (!this._changeScript) { - return; - } - this._clearSignatures(); - if (!_.isUndefined(this._changeIndex)) { - this._removeOutput(this._changeIndex); - } - var available = this._getUnspentValue(); - var fee = this.getFee(); - var changeAmount = available - fee; - if (changeAmount > 0) { - this._changeIndex = this.outputs.length; - this._addOutput(new Output({ - script: this._changeScript, - satoshis: changeAmount - })); - } else { - this._changeIndex = undefined; - } -}; /** - * Calculates the fees for the transaction. - * - * If there is no change output set, the fee will be the - * output amount minus the input amount. - * If there's a fixed fee set, return that - * If there's no fee set, estimate it based on size - * @return {Number} miner fee for this transaction in satoshis + * @function + * @member Networks#add + * Will add a custom Network + * @param {Object} data + * @param {String} data.name - The name of the network + * @param {String} data.alias - The aliased name of the network + * @param {Number} data.pubkeyhash - The publickey hash prefix + * @param {Number} data.privatekey - The privatekey prefix + * @param {Number} data.scripthash - The scripthash prefix + * @param {Number} data.xpubkey - The extended public key magic + * @param {Number} data.xprivkey - The extended private key magic + * @param {Number} data.networkMagic - The network magic number + * @param {Number} data.port - The network port + * @param {Array} data.dnsSeeds - An array of dns seeds + * @return Network */ -Transaction.prototype.getFee = function() { - // if no change output is set, fees should equal all the unspent amount - if (!this._changeScript) { - return this._getUnspentValue(); - } - return _.isUndefined(this._fee) ? this._estimateFee() : this._fee; -}; +function addNetwork(data) { -/** - * Estimates fee from serialized transaction size in bytes. - */ -Transaction.prototype._estimateFee = function() { - var estimatedSize = this._estimateSize(); - var available = this._getUnspentValue(); - return Transaction._estimateFee(estimatedSize, available); -}; + var network = new Network(); -Transaction.prototype._getUnspentValue = function() { - return this._getInputAmount() - this._getOutputAmount(); -}; + _.extend(network, { + name: data.name, + alias: data.alias, + pubkeyhash: data.pubkeyhash, + privatekey: data.privatekey, + scripthash: data.scripthash, + xpubkey: data.xpubkey, + xprivkey: data.xprivkey, + networkMagic: BufferUtil.integerAsBuffer(data.networkMagic), + port: data.port, + dnsSeeds: data.dnsSeeds + }); -Transaction.prototype._clearSignatures = function() { - _.each(this.inputs, function(input) { - input.clearSignatures(); + _.each(_.values(network), function(value) { + if (!_.isObject(value)) { + networkMaps[value] = network; + } }); -}; -Transaction._estimateFee = function(size, amountAvailable) { - var fee = Math.ceil(size / Transaction.FEE_PER_KB); - if (amountAvailable > fee) { - size += Transaction.CHANGE_OUTPUT_MAX_SIZE; - } - return Math.ceil(size / 1000) * Transaction.FEE_PER_KB; -}; + networks.push(network); -Transaction.prototype._estimateSize = function() { - var result = Transaction.MAXIMUM_EXTRA_SIZE; - _.each(this.inputs, function(input) { - result += input._estimateSize(); - }); - _.each(this.outputs, function(output) { - result += output.script.toBuffer().length + 9; - }); - return result; -}; + return network; -Transaction.prototype._removeOutput = function(index) { - var output = this.outputs[index]; - this.outputs = _.without(this.outputs, output); -}; +} -Transaction.prototype.removeOutput = function(index) { - this._removeOutput(index); - this._updateChangeOutput(); -}; +addNetwork({ + name: 'livenet', + alias: 'mainnet', + pubkeyhash: 0x00, + privatekey: 0x80, + scripthash: 0x05, + xpubkey: 0x0488b21e, + xprivkey: 0x0488ade4, + networkMagic: 0xf9beb4d9, + port: 8333, + dnsSeeds: [ + 'seed.bitcoin.sipa.be', + 'dnsseed.bluematt.me', + 'dnsseed.bitcoin.dashjr.org', + 'seed.bitcoinstats.com', + 'seed.bitnodes.io', + 'bitseed.xf2.org' + ] +}); + +addNetwork({ + name: 'testnet', + alias: 'testnet', + pubkeyhash: 0x6f, + privatekey: 0xef, + scripthash: 0xc4, + xpubkey: 0x043587cf, + xprivkey: 0x04358394, + networkMagic: 0x0b110907, + port: 18333, + dnsSeeds: [ + 'testnet-seed.bitcoin.petertodd.org', + 'testnet-seed.bluematt.me', + 'testnet-seed.alexykot.me', + 'testnet-seed.bitcoin.schildbach.de' + ], +}); /** - * Randomize this transaction's outputs ordering. The shuffling algorithm is a - * version of the Fisher-Yates shuffle, provided by lodash's _.shuffle(). - * - * @return {Transaction} this - */ -Transaction.prototype.shuffleOutputs = function() { - return this.sortOutputs(_.shuffle); -}; +* @instance +* @member Networks#livenet +*/ +var livenet = getNetwork('livenet'); /** - * Sort this transaction's outputs, according to a given sorting function that - * takes an array as argument and returns a new array, with the same elements - * but with a different order. The argument function MUST NOT modify the order - * of the original array - * - * @param {Function} sortingFunction - * @return {Transaction} this +* @instance +* @member Networks#testnet +*/ +var testnet = getNetwork('testnet'); + +/** + * @namespace Networks */ -Transaction.prototype.sortOutputs = function(sortingFunction) { - var outs = sortingFunction(this.outputs); - return this._newOutputOrder(outs); +module.exports = { + add: addNetwork, + defaultNetwork: livenet, + livenet: livenet, + mainnet: livenet, + testnet: testnet, + get: getNetwork }; -Transaction.prototype._newOutputOrder = function(newOutputs) { - var changeIndex = 0; - var length = this.outputs.length; - while (changeIndex < length && this.outputs[this._changeIndex] !== newOutputs[changeIndex]) { - changeIndex++; - } - if (changeIndex === length) { - throw new errors.Transaction.InvalidSorting(); - } - this.outputs = newOutputs; - this._changeIndex = changeIndex; - return this; -}; +},{"./util/buffer":69,"lodash":95}],51:[function(require,module,exports){ +(function (Buffer){ +'use strict'; -Transaction.prototype.removeInput = function(txId, outputIndex) { - var index; - if (!outputIndex && _.isNumber(txId)) { - index = txId; - } else { - index = _.findIndex(this.inputs, function(input) { - return input.prevTxId.toString('hex') === txId && input.outputIndex === outputIndex; - }); - } - if (index < 0 || index >= this.inputs.length) { - throw new errors.Transaction.InvalidIndex(index, this.inputs.length); +var _ = require('lodash'); +var $ = require('./util/preconditions'); +var BufferUtil = require('./util/buffer'); +var JSUtil = require('./util/js'); + +function Opcode(num) { + if (!(this instanceof Opcode)) { + return new Opcode(num); } - var input = this.inputs[index]; - this.inputs = _.without(this.inputs, input); - this._updateChangeOutput(); -}; -/* Signature handling */ + var value; -/** - * Sign the transaction using one or more private keys. - * - * It tries to sign each input, verifying that the signature will be valid - * (matches a public key). - * - * @param {Array|String|PrivateKey} privateKey - * @param {number} sigtype - * @return {Transaction} this, for chaining - */ -Transaction.prototype.sign = function(privateKey, sigtype) { - $.checkState(this.hasAllUtxoInfo()); - var self = this; - if (_.isArray(privateKey)) { - _.each(privateKey, function(privateKey) { - self.sign(privateKey, sigtype); - }); - return this; + if (_.isNumber(num)) { + value = num; + } else if (_.isString(num)) { + value = Opcode.map[num]; + } else { + throw new TypeError('Unrecognized num type: "' + typeof(num) + '" for Opcode'); } - _.each(this.getSignatures(privateKey, sigtype), function(signature) { - self.applySignature(signature); + + JSUtil.defineImmutable(this, { + num: value }); + return this; +} + +Opcode.fromBuffer = function(buf) { + $.checkArgument(BufferUtil.isBuffer(buf)); + return new Opcode(Number('0x' + buf.toString('hex'))); }; -Transaction.prototype.getSignatures = function(privKey, sigtype) { - privKey = new PrivateKey(privKey); - sigtype = sigtype || Signature.SIGHASH_ALL; - var transaction = this; - var results = []; - var hashData = Hash.sha256ripemd160(privKey.publicKey.toBuffer()); - _.each(this.inputs, function forEachInput(input, index) { - _.each(input.getSignatures(transaction, privKey, index, sigtype, hashData), function(signature) { - results.push(signature); - }); - }); - return results; +Opcode.fromNumber = function(num) { + $.checkArgument(_.isNumber(num)); + return new Opcode(num); }; -/** - * Add a signature to the transaction - * - * @param {Object} signature - * @param {number} signature.inputIndex - * @param {number} signature.sigtype - * @param {PublicKey} signature.publicKey - * @param {Signature} signature.signature - * @return {Transaction} this, for chaining - */ -Transaction.prototype.applySignature = function(signature) { - this.inputs[signature.inputIndex].addSignature(this, signature); - return this; +Opcode.fromString = function(str) { + $.checkArgument(_.isString(str)); + var value = Opcode.map[str]; + if (typeof value === 'undefined') { + throw new TypeError('Invalid opcodestr'); + } + return new Opcode(value); }; -Transaction.prototype.isFullySigned = function() { - _.each(this.inputs, function(input) { - if (input.isFullySigned === Input.prototype.isFullySigned) { - throw new errors.Transaction.UnableToVerifySignature( - 'Unrecognized script kind, or not enough information to execute script.' + - 'This usually happens when creating a transaction from a serialized transaction' - ); - } - }); - return _.all(_.map(this.inputs, function(input) { - return input.isFullySigned(); - })); +Opcode.prototype.toHex = function() { + return this.num.toString(16); }; -Transaction.prototype.isValidSignature = function(signature) { - var self = this; - if (this.inputs[signature.inputIndex].isValidSignature === Input.prototype.isValidSignature) { - throw new errors.Transaction.UnableToVerifySignature( - 'Unrecognized script kind, or not enough information to execute script.' + - 'This usually happens when creating a transaction from a serialized transaction' - ); - } - return this.inputs[signature.inputIndex].isValidSignature(self, signature); +Opcode.prototype.toBuffer = function() { + return new Buffer(this.toHex(), 'hex'); }; -/** - * @returns {bool} whether the signature is valid for this transaction input - */ -Transaction.prototype.verifySignature = function(sig, pubkey, nin, subscript) { - return Sighash.verify(this, sig, pubkey, nin, subscript); +Opcode.prototype.toNumber = function() { + return this.num; }; -/** - * Check that a transaction passes basic sanity tests. If not, return a string - * describing the error. This function contains the same logic as - * CheckTransaction in bitcoin core. - */ -Transaction.prototype.verify = function() { - // Basic checks that don't depend on any context - if (this.inputs.length === 0) { - return 'transaction txins empty'; +Opcode.prototype.toString = function() { + var str = Opcode.reverseMap[this.num]; + if (typeof str === 'undefined') { + throw new Error('Opcode does not have a string representation'); } + return str; +}; - if (this.outputs.length === 0) { - return 'transaction txouts empty'; - } - - // Size limits - if (this.toBuffer().length > Block.MAX_BLOCK_SIZE) { - return 'transaction over the maximum block size'; +Opcode.smallInt = function(n) { + $.checkArgument(n >= 0 && n <= 16, 'Invalid Argument: n must be between 0 and 16'); + if (n === 0) { + return Opcode('OP_0'); } + return new Opcode(Opcode.map.OP_1 + n - 1); +}; - // Check for negative or overflow output values - var valueoutbn = new BN(0); - for (var i = 0; i < this.outputs.length; i++) { - var txout = this.outputs[i]; - var valuebn = txout._satoshisBN; - if (valuebn.lt(BN.Zero)) { - return 'transaction txout ' + i + ' negative'; - } - if (valuebn.gt(new BN(Transaction.MAX_MONEY, 10))) { - return 'transaction txout ' + i + ' greater than MAX_MONEY'; - } - valueoutbn = valueoutbn.add(valuebn); - if (valueoutbn.gt(new BN(Transaction.MAX_MONEY))) { - return 'transaction txout ' + i + ' total output greater than MAX_MONEY'; - } - } +Opcode.map = { + // push value + OP_FALSE: 0, + OP_0: 0, + OP_PUSHDATA1: 76, + OP_PUSHDATA2: 77, + OP_PUSHDATA4: 78, + OP_1NEGATE: 79, + OP_RESERVED: 80, + OP_TRUE: 81, + OP_1: 81, + OP_2: 82, + OP_3: 83, + OP_4: 84, + OP_5: 85, + OP_6: 86, + OP_7: 87, + OP_8: 88, + OP_9: 89, + OP_10: 90, + OP_11: 91, + OP_12: 92, + OP_13: 93, + OP_14: 94, + OP_15: 95, + OP_16: 96, - // Check for duplicate inputs - var txinmap = {}; - for (i = 0; i < this.inputs.length; i++) { - var txin = this.inputs[i]; + // control + OP_NOP: 97, + OP_VER: 98, + OP_IF: 99, + OP_NOTIF: 100, + OP_VERIF: 101, + OP_VERNOTIF: 102, + OP_ELSE: 103, + OP_ENDIF: 104, + OP_VERIFY: 105, + OP_RETURN: 106, - var inputid = txin.prevTxId + ':' + txin.outputIndex; - if (!_.isUndefined(txinmap[inputid])) { - return 'transaction input ' + i + ' duplicate input'; - } - txinmap[inputid] = true; - } + // stack ops + OP_TOALTSTACK: 107, + OP_FROMALTSTACK: 108, + OP_2DROP: 109, + OP_2DUP: 110, + OP_3DUP: 111, + OP_2OVER: 112, + OP_2ROT: 113, + OP_2SWAP: 114, + OP_IFDUP: 115, + OP_DEPTH: 116, + OP_DROP: 117, + OP_DUP: 118, + OP_NIP: 119, + OP_OVER: 120, + OP_PICK: 121, + OP_ROLL: 122, + OP_ROT: 123, + OP_SWAP: 124, + OP_TUCK: 125, - var isCoinbase = this.isCoinbase(); - if (isCoinbase) { - var buf = this.inputs[0]._script.toBuffer(); - if (buf.length < 2 || buf.length > 100) { - return 'coinbase trasaction script size invalid'; - } - } else { - for (i = 0; i < this.inputs.length; i++) { - if (this.inputs[i].isNull()) { - return 'tranasction input ' + i + ' has null input'; - } - } - } - return true; -}; + // splice ops + OP_CAT: 126, + OP_SUBSTR: 127, + OP_LEFT: 128, + OP_RIGHT: 129, + OP_SIZE: 130, -/** - * Analagous to bitcoind's IsCoinBase function in transaction.h - */ -Transaction.prototype.isCoinbase = function() { - return (this.inputs.length === 1 && this.inputs[0].isNull()); -}; + // bit logic + OP_INVERT: 131, + OP_AND: 132, + OP_OR: 133, + OP_XOR: 134, + OP_EQUAL: 135, + OP_EQUALVERIFY: 136, + OP_RESERVED1: 137, + OP_RESERVED2: 138, + // numeric + OP_1ADD: 139, + OP_1SUB: 140, + OP_2MUL: 141, + OP_2DIV: 142, + OP_NEGATE: 143, + OP_ABS: 144, + OP_NOT: 145, + OP_0NOTEQUAL: 146, -module.exports = Transaction; + OP_ADD: 147, + OP_SUB: 148, + OP_MUL: 149, + OP_DIV: 150, + OP_MOD: 151, + OP_LSHIFT: 152, + OP_RSHIFT: 153, -},{"../address":13,"../block":16,"../crypto/bn":18,"../crypto/hash":20,"../crypto/signature":23,"../encoding/bufferreader":26,"../encoding/bufferwriter":27,"../errors":29,"../privatekey":36,"../script":38,"../util/buffer":53,"../util/js":54,"../util/preconditions":55,"./input":42,"./output":46,"./sighash":47,"./unspentoutput":50,"buffer":104,"lodash":79}],50:[function(require,module,exports){ -'use strict'; + OP_BOOLAND: 154, + OP_BOOLOR: 155, + OP_NUMEQUAL: 156, + OP_NUMEQUALVERIFY: 157, + OP_NUMNOTEQUAL: 158, + OP_LESSTHAN: 159, + OP_GREATERTHAN: 160, + OP_LESSTHANOREQUAL: 161, + OP_GREATERTHANOREQUAL: 162, + OP_MIN: 163, + OP_MAX: 164, -var _ = require('lodash'); -var $ = require('../util/preconditions'); -var JSUtil = require('../util/js'); + OP_WITHIN: 165, -var Script = require('../script'); -var Address = require('../address'); -var Unit = require('../unit'); + // crypto + OP_RIPEMD160: 166, + OP_SHA1: 167, + OP_SHA256: 168, + OP_HASH160: 169, + OP_HASH256: 170, + OP_CODESEPARATOR: 171, + OP_CHECKSIG: 172, + OP_CHECKSIGVERIFY: 173, + OP_CHECKMULTISIG: 174, + OP_CHECKMULTISIGVERIFY: 175, -/** - * Represents an unspent output information: its script, associated amount and address, - * transaction id and output index. - * - * @constructor - * @param {object} data - * @param {string} data.txid the previous transaction id - * @param {string=} data.txId alias for `txid` - * @param {number} data.vout the index in the transaction - * @param {number=} data.outputIndex alias for `vout` - * @param {string|Script} data.scriptPubKey the script that must be resolved to release the funds - * @param {string|Script=} data.script alias for `scriptPubKey` - * @param {number} data.amount amount of bitcoins associated - * @param {number=} data.satoshis alias for `amount`, but expressed in satoshis (1 BTC = 1e8 satoshis) - * @param {string|Address=} data.address the associated address to the script, if provided - */ -function UnspentOutput(data) { - /* jshint maxcomplexity: 20 */ - /* jshint maxstatements: 20 */ - if (!(this instanceof UnspentOutput)) { - return new UnspentOutput(data); - } - $.checkArgument(_.isObject(data), 'Must provide an object from where to extract data'); - var address = data.address ? new Address(data.address) : undefined; - var txId = data.txid ? data.txid : data.txId; - if (!txId || !JSUtil.isHexaString(txId) || txId.length > 64) { - // TODO: Use the errors library - throw new Error('Invalid TXID in object', data); - } - var outputIndex = _.isUndefined(data.vout) ? data.outputIndex : data.vout; - if (!_.isNumber(outputIndex)) { - throw new Error('Invalid outputIndex, received ' + outputIndex); - } - $.checkArgument(!_.isUndefined(data.scriptPubKey) || !_.isUndefined(data.script), - 'Must provide the scriptPubKey for that output!'); - var script = new Script(data.scriptPubKey || data.script); - $.checkArgument(!_.isUndefined(data.amount) || !_.isUndefined(data.satoshis), - 'Must provide an amount for the output'); - var amount = !_.isUndefined(data.amount) ? new Unit.fromBTC(data.amount).toSatoshis() : data.satoshis; - $.checkArgument(_.isNumber(amount), 'Amount must be a number'); - JSUtil.defineImmutable(this, { - address: address, - txId: txId, - outputIndex: outputIndex, - script: script, - satoshis: amount - }); -} + // expansion + OP_NOP1: 176, + OP_NOP2: 177, + OP_NOP3: 178, + OP_NOP4: 179, + OP_NOP5: 180, + OP_NOP6: 181, + OP_NOP7: 182, + OP_NOP8: 183, + OP_NOP9: 184, + OP_NOP10: 185, -/** - * Provide an informative output when displaying this object in the console - * @returns string - */ -UnspentOutput.prototype.inspect = function() { - return ''; + // template matching params + OP_PUBKEYHASH: 253, + OP_PUBKEY: 254, + OP_INVALIDOPCODE: 255 }; -/** - * String representation: just "txid:index" - * @returns string - */ -UnspentOutput.prototype.toString = function() { - return this.txId + ':' + this.outputIndex; -}; +Opcode.reverseMap = []; -/** - * Deserialize an UnspentOutput from an object or JSON string - * @param {object|string} data - * @return UnspentOutput - */ -UnspentOutput.fromJSON = UnspentOutput.fromObject = function(data) { - if (JSUtil.isValidJSON(data)) { - data = JSON.parse(data); - } - return new UnspentOutput(data); -}; +for (var k in Opcode.map) { + Opcode.reverseMap[Opcode.map[k]] = k; +} + +// Easier access to opcodes +_.extend(Opcode, Opcode.map); /** - * Retrieve a string representation of this object - * @return {string} + * @returns true if opcode is one of OP_0, OP_1, ..., OP_16 */ -UnspentOutput.prototype.toJSON = function() { - return JSON.stringify(this.toObject()); +Opcode.isSmallIntOp = function(opcode) { + if (opcode instanceof Opcode) { + opcode = opcode.toNumber(); + } + return ((opcode === Opcode.map.OP_0) || + ((opcode >= Opcode.map.OP_1) && (opcode <= Opcode.map.OP_16))); }; /** - * Returns a plain object (no prototype or methods) with the associated infor for this output - * @return {object} + * Will return a string formatted for the console + * + * @returns {String} Script opcode */ -UnspentOutput.prototype.toObject = function() { - return { - address: this.address ? this.address.toString() : undefined, - txid: this.txId, - vout: this.outputIndex, - scriptPubKey: this.script.toBuffer().toString('hex'), - amount: Unit.fromSatoshis(this.satoshis).toBTC() - }; +Opcode.prototype.inspect = function() { + return ''; }; -module.exports = UnspentOutput; +module.exports = Opcode; -},{"../address":13,"../script":38,"../unit":51,"../util/js":54,"../util/preconditions":55,"lodash":79}],51:[function(require,module,exports){ +}).call(this,require("buffer").Buffer) +},{"./util/buffer":69,"./util/js":70,"./util/preconditions":71,"buffer":209,"lodash":95}],52:[function(require,module,exports){ +(function (Buffer){ 'use strict'; var _ = require('lodash'); - -var errors = require('./errors'); +var Address = require('./address'); +var Base58Check = require('./encoding/base58check'); +var BN = require('./crypto/bn'); var JSUtil = require('./util/js'); - -var UNITS = { - 'BTC' : [1e8, 8], - 'mBTC' : [1e5, 5], - 'uBTC' : [1e2, 2], - 'bits' : [1e2, 2], - 'satoshis' : [1, 0] -}; +var Networks = require('./networks'); +var Point = require('./crypto/point'); +var PublicKey = require('./publickey'); +var Random = require('./crypto/random'); /** - * Utility for handling and converting bitcoins units. The supported units are - * BTC, mBTC, bits (also named uBTC) and satoshis. A unit instance can be created with an - * amount and a unit code, or alternatively using static methods like {fromBTC}. - * It also allows to be created from a fiat amount and the exchange rate, or - * alternatively using the {fromFiat} static method. - * You can consult for different representation of a unit instance using it's - * {to} method, the fixed unit methods like {toSatoshis} or alternatively using - * the unit accessors. It also can be converted to a fiat amount by providing the - * corresponding BTC/fiat exchange rate. + * Instantiate a PrivateKey from a BN, Buffer and WIF. * * @example * ```javascript - * var sats = Unit.fromBTC(1.3).toSatoshis(); - * var mili = Unit.fromBits(1.3).to(Unit.mBTC); - * var bits = Unit.fromFiat(1.3, 350).bits; - * var btc = new Unit(1.3, Unit.bits).BTC; + * // generate a new random key + * var key = PrivateKey(); + * + * // get the associated address + * var address = key.toAddress(); + * + * // encode into wallet export format + * var exported = key.toWIF(); + * + * // instantiate from the exported (and saved) private key + * var imported = PrivateKey.fromWIF(exported); * ``` * - * @param {Number} amount - The amount to be represented - * @param {String|Number} code - The unit of the amount or the exchange rate - * @returns {Unit} A new instance of an Unit + * @param {string} data - The encoded data in various formats + * @param {Network|string} [network] - a {@link Network} object, or a string with the network name + * @returns {PrivateKey} A new valid instance of an PrivateKey * @constructor */ -function Unit(amount, code) { - if (!(this instanceof Unit)) { - return new Unit(amount, code); - } +var PrivateKey = function PrivateKey(data, network) { + /* jshint maxstatements: 20 */ + /* jshint maxcomplexity: 8 */ - // convert fiat to BTC - if (_.isNumber(code)) { - if (code <= 0) { - throw new errors.Unit.InvalidRate(code); - } - amount = amount / code; - code = Unit.BTC; + if (!(this instanceof PrivateKey)) { + return new PrivateKey(data, network); + } + if (data instanceof PrivateKey) { + return data; } - this._value = this._from(amount, code); + var info = this._classifyArguments(data, network); - var self = this; - var defineAccesor = function(key) { - Object.defineProperty(self, key, { - get: function() { return self.to(key); }, - enumerable: true, - }); - }; + // validation + if (!info.bn || info.bn.cmp(new BN(0)) === 0){ + throw new TypeError('Number can not be equal to zero, undefined, null or false'); + } + if (!info.bn.lt(Point.getN())) { + throw new TypeError('Number must be less than N'); + } + if (typeof(info.network) === 'undefined') { + throw new TypeError('Must specify the network ("livenet" or "testnet")'); + } - Object.keys(UNITS).forEach(defineAccesor); -} + JSUtil.defineImmutable(this, { + bn: info.bn, + compressed: info.compressed, + network: info.network + }); -Object.keys(UNITS).forEach(function(key) { - Unit[key] = key; -}); + Object.defineProperty(this, 'publicKey', { + configurable: false, + enumerable: true, + get: this.toPublicKey.bind(this) + }); -/** - * Returns a Unit instance created from JSON string or object - * - * @param {String|Object} json - JSON with keys: amount and code - * @returns {Unit} A Unit instance - */ -Unit.fromJSON = function fromJSON(json){ - if (JSUtil.isValidJSON(json)) { - json = JSON.parse(json); - } - return new Unit(json.amount, json.code); -}; + return this; -/** - * Returns a Unit instance created from an amount in BTC - * - * @param {Number} amount - The amount in BTC - * @returns {Unit} A Unit instance - */ -Unit.fromBTC = function(amount) { - return new Unit(amount, Unit.BTC); }; /** - * Returns a Unit instance created from an amount in mBTC + * Internal helper to instantiate PrivateKey internal `info` object from + * different kinds of arguments passed to the constructor. * - * @param {Number} amount - The amount in mBTC - * @returns {Unit} A Unit instance + * @param {*} data + * @param {Network|string} [network] - a {@link Network} object, or a string with the network name + * @return {Object} */ -Unit.fromMilis = function(amount) { - return new Unit(amount, Unit.mBTC); +PrivateKey.prototype._classifyArguments = function(data, network) { + /* jshint maxcomplexity: 10 */ + var info = { + compressed: true, + network: network ? Networks.get(network) : Networks.defaultNetwork + }; + + // detect type of data + if (_.isUndefined(data) || _.isNull(data)){ + info.bn = PrivateKey._getRandomBN(); + } else if (data instanceof BN) { + info.bn = data; + } else if (data instanceof Buffer || data instanceof Uint8Array) { + info = PrivateKey._transformBuffer(data, network); + } else if (PrivateKey._isJSON(data)){ + info = PrivateKey._transformJSON(data); + } else if (!network && Networks.get(data)) { + info.bn = PrivateKey._getRandomBN(); + info.network = Networks.get(data); + } else if (typeof(data) === 'string'){ + if (JSUtil.isHexa(data)) { + info.bn = new BN(new Buffer(data, 'hex')); + } else { + info = PrivateKey._transformWIF(data, network); + } + } else { + throw new TypeError('First argument is an unrecognized data type.'); + } + return info; }; /** - * Returns a Unit instance created from an amount in bits + * Internal function to get a random Big Number (BN) * - * @param {Number} amount - The amount in bits - * @returns {Unit} A Unit instance + * @returns {BN} A new randomly generated BN + * @private */ -Unit.fromMicros = Unit.fromBits = function(amount) { - return new Unit(amount, Unit.bits); +PrivateKey._getRandomBN = function(){ + var condition; + var bn; + do { + var privbuf = Random.getRandomBuffer(32); + bn = BN.fromBuffer(privbuf); + condition = bn.lt(Point.getN()); + } while (!condition); + return bn; }; /** - * Returns a Unit instance created from an amount in satoshis + * Internal function to detect if a param is a JSON string or plain object * - * @param {Number} amount - The amount in satoshis - * @returns {Unit} A Unit instance + * @param {*} param - value to test + * @returns {boolean} + * @private */ -Unit.fromSatoshis = function(amount) { - return new Unit(amount, Unit.satoshis); +PrivateKey._isJSON = function(json) { + return JSUtil.isValidJSON(json) || (json.bn && json.network); }; /** - * Returns a Unit instance created from a fiat amount and exchange rate. + * Internal function to transform a WIF Buffer into a private key * - * @param {Number} amount - The amount in fiat - * @param {Number} rate - The exchange rate BTC/fiat - * @returns {Unit} A Unit instance + * @param {Buffer} buf - An WIF string + * @param {Network|string} [network] - a {@link Network} object, or a string with the network name + * @returns {Object} An object with keys: bn, network and compressed + * @private */ -Unit.fromFiat = function(amount, rate) { - return new Unit(amount, rate); -}; +PrivateKey._transformBuffer = function(buf, network) { -Unit.prototype._from = function(amount, code) { - if (!UNITS[code]) { - throw new errors.Unit.UnknownCode(code); + var info = {}; + + if (buf.length === 32) { + return PrivateKey._transformBNBuffer(buf, network); } - return parseInt((amount * UNITS[code][0]).toFixed()); -}; -/** - * Returns the value represented in the specified unit - * - * @param {String|Number} code - The unit code or exchange rate - * @returns {Number} The converted value - */ -Unit.prototype.to = function(code) { - if (_.isNumber(code)) { - if (code <= 0) { - throw new errors.Unit.InvalidRate(code); - } - return parseFloat((this.BTC * code).toFixed(2)); + info.network = Networks.get(buf[0], 'privatekey'); + if (buf[0] === Networks.livenet.privatekey) { + info.network = Networks.livenet; + } else if (buf[0] === Networks.testnet.privatekey) { + info.network = Networks.testnet; + } else { + throw new Error('Invalid network'); } - if (!UNITS[code]) { - throw new errors.Unit.UnknownCode(code); + if (network && info.network !== Networks.get(network)) { + throw new TypeError('Private key network mismatch'); } - var value = this._value / UNITS[code][0]; - return parseFloat(value.toFixed(UNITS[code][1])); + if (buf.length === 1 + 32 + 1 && buf[1 + 32 + 1 - 1] === 1) { + info.compressed = true; + } else if (buf.length === 1 + 32) { + info.compressed = false; + } else { + throw new Error('Length of buffer must be 33 (uncompressed) or 34 (compressed)'); + } + + info.bn = BN.fromBuffer(buf.slice(1, 32 + 1)); + + return info; }; /** - * Returns the value represented in BTC + * Internal function to transform a BN buffer into a private key * - * @returns {Number} The value converted to BTC + * @param {Buffer} buf + * @param {Network|string} [network] - a {@link Network} object, or a string with the network name + * @returns {object} an Object with keys: bn, network, and compressed + * @private */ -Unit.prototype.toBTC = function() { - return this.to(Unit.BTC); +PrivateKey._transformBNBuffer = function(buf, network) { + var info = {}; + info.network = Networks.get(network) || Networks.defaultNetwork; + info.bn = BN.fromBuffer(buf); + info.compressed = false; + return info; }; /** - * Returns the value represented in mBTC + * Internal function to transform a WIF string into a private key * - * @returns {Number} The value converted to mBTC + * @param {String} buf - An WIF string + * @returns {Object} An object with keys: bn, network and compressed + * @private */ -Unit.prototype.toMilis = function() { - return this.to(Unit.mBTC); +PrivateKey._transformWIF = function(str, network) { + return PrivateKey._transformBuffer(Base58Check.decode(str), network); }; /** - * Returns the value represented in bits + * Instantiate a PrivateKey from a JSON string * - * @returns {Number} The value converted to bits + * @param {String} json - The JSON encoded private key string + * @returns {PrivateKey} A new valid instance of PrivateKey */ -Unit.prototype.toMicros = Unit.prototype.toBits = function() { - return this.to(Unit.bits); +PrivateKey.fromJSON = function(json) { + if (!PrivateKey._isJSON(json)) { + throw new TypeError('Must be a valid JSON string or plain object'); + } + + return new PrivateKey(json); }; /** - * Returns the value represented in satoshis + * Instantiate a PrivateKey from a Buffer with the DER or WIF representation * - * @returns {Number} The value converted to satoshis + * @param {Buffer} arg + * @param {Network} network + * @return {PrivateKey} */ -Unit.prototype.toSatoshis = function() { - return this.to(Unit.satoshis); +PrivateKey.fromBuffer = function(arg, network) { + return new PrivateKey(arg, network); }; /** - * Returns the value represented in fiat + * Internal function to transform a JSON string on plain object into a private key + * return this. * - * @param {string} rate - The exchange rate between BTC/currency - * @returns {Number} The value converted to satoshis + * @param {String} json - A JSON string or plain object + * @returns {Object} An object with keys: bn, network and compressed + * @private */ -Unit.prototype.atRate = function(rate) { - return this.to(rate); +PrivateKey._transformJSON = function(json) { + if (JSUtil.isValidJSON(json)) { + json = JSON.parse(json); + } + var bn = new BN(json.bn, 'hex'); + return { + bn: bn, + network: json.network, + compressed: json.compressed + }; }; /** - * Returns a the string representation of the value in satoshis + * Instantiate a PrivateKey from a WIF string * - * @returns {string} the value in satoshis + * @param {String} str - The WIF encoded private key string + * @returns {PrivateKey} A new valid instance of PrivateKey */ -Unit.prototype.toString = function() { - return this.satoshis + ' satoshis'; +PrivateKey.fromString = PrivateKey.fromWIF = function(str) { + return new PrivateKey(str); }; /** - * Returns a plain object representation of the Unit + * Instantiate a PrivateKey from random bytes * - * @returns {Object} An object with the keys: amount and code + * @param {String} [network] - Either "livenet" or "testnet" + * @returns {PrivateKey} A new valid instance of PrivateKey */ -Unit.prototype.toObject = function toObject() { - return { - amount: this.BTC, - code: Unit.BTC - }; +PrivateKey.fromRandom = function(network) { + var bn = PrivateKey._getRandomBN(); + return new PrivateKey(bn, network); }; -Unit.prototype.toJSON = function toJSON() { - return JSON.stringify(this.toObject()); +/** + * Check if there would be any errors when initializing a PrivateKey + * + * @param {String} data - The encoded data in various formats + * @param {String} [network] - Either "livenet" or "testnet" + * @returns {null|Error} An error if exists + */ + +PrivateKey.getValidationError = function(data, network) { + var error; + try { + /* jshint nonew: false */ + new PrivateKey(data, network); + } catch (e) { + error = e; + } + return error; }; /** - * Returns a string formatted for the console + * Check if the parameters are valid * - * @returns {string} the value in satoshis + * @param {String} data - The encoded data in various formats + * @param {String} [network] - Either "livenet" or "testnet" + * @returns {Boolean} If the private key is would be valid */ -Unit.prototype.inspect = function() { - return ''; +PrivateKey.isValid = function(data, network){ + return !PrivateKey.getValidationError(data, network); }; -module.exports = Unit; - -},{"./errors":29,"./util/js":54,"lodash":79}],52:[function(require,module,exports){ -'use strict'; - -var _ = require('lodash'); -var URL = require('url'); - -var Address = require('./address'); -var Unit = require('./unit'); -var JSUtil = require('./util/js'); - /** - * Bitcore URI - * - * Instantiate an URI from a bitcoin URI String or an Object. An URI instance - * can be created with a bitcoin uri string or an object. All instances of - * URI are valid, the static method isValid allows checking before instanciation. - * - * All standard parameters can be found as members of the class, the address - * is represented using an {Address} instance and the amount is represented in - * satoshis. Any other non-standard parameters can be found under the extra member. - * - * @example - * ```javascript - * - * var uri = new URI('bitcoin:12A1MyfXbW6RhdRAZEqofac5jCQQjwEPBu?amount=1.2'); - * console.log(uri.address, uri.amount); - * ``` + * Will output the PrivateKey encoded as hex string * - * @param {string|Object} data - A bitcoin URI string or an Object - * @param {Array.=} knownParams - Required non-standard params - * @throws {TypeError} Invalid bitcoin address - * @throws {TypeError} Invalid amount - * @throws {Error} Unknown required argument - * @returns {URI} A new valid and frozen instance of URI - * @constructor + * @returns {String} */ -var URI = function(data, knownParams) { - if (!(this instanceof URI)) { - return new URI(data, knownParams); - } +PrivateKey.prototype.toString = function() { + return this.toBuffer().toString('hex'); +}; - this.extras = {}; - this.knownParams = knownParams || []; - this.address = this.network = this.amount = this.message = null; +/** + * Will output the PrivateKey to a WIF string + * + * @returns {String} A WIP representation of the private key + */ +PrivateKey.prototype.toWIF = function() { + var network = this.network; + var compressed = this.compressed; - if (typeof(data) === 'string') { - var params = URI.parse(data); - if (params.amount) { - params.amount = this._parseAmount(params.amount); - } - this._fromObject(params); - } else if (typeof(data) === 'object') { - this._fromObject(data); + var buf; + if (compressed) { + buf = Buffer.concat([new Buffer([network.privatekey]), + this.bn.toBuffer({size: 32}), + new Buffer([0x01])]); } else { - throw new TypeError('Unrecognized data format.'); + buf = Buffer.concat([new Buffer([network.privatekey]), + this.bn.toBuffer({size: 32})]); } + + return Base58Check.encode(buf); }; /** - * Instantiate a URI from a String + * Will return the private key as a BN instance * - * @param {string} str - JSON string or object of the URI - * @returns {URI} A new instance of a URI + * @returns {BN} A BN instance of the private key */ -URI.fromString = function fromString(str) { - if (typeof(str) !== 'string') { - throw new TypeError('Expected a string'); - } - return new URI(str); +PrivateKey.prototype.toBigNumber = function(){ + return this.bn; }; /** - * Instantiate a URI from JSON + * Will return the private key as a BN buffer * - * @param {String|Object} json - JSON string or object of the URI - * @returns {URI} A new instance of a URI + * @returns {Buffer} A buffer of the private key */ -URI.fromJSON = function fromJSON(json) { - if (JSUtil.isValidJSON(json)) { - json = JSON.parse(json); - } - return new URI(json); +PrivateKey.prototype.toBuffer = function(){ + return this.bn.toBuffer(); }; /** - * Check if an bitcoin URI string is valid - * - * @example - * ```javascript - * - * var valid = URI.isValid('bitcoin:12A1MyfXbW6RhdRAZEqofac5jCQQjwEPBu'); - * // true - * ``` + * Will return the corresponding public key * - * @param {string|Object} data - A bitcoin URI string or an Object - * @param {Array.=} knownParams - Required non-standard params - * @returns {boolean} Result of uri validation + * @returns {PublicKey} A public key generated from the private key */ -URI.isValid = function(arg, knownParams) { - try { - new URI(arg, knownParams); - } catch (err) { - return false; +PrivateKey.prototype.toPublicKey = function(){ + if (!this._pubkey) { + this._pubkey = PublicKey.fromPrivateKey(this); } - return true; + return this._pubkey; }; /** - * Convert a bitcoin URI string into a simple object. + * Will return an address for the private key * - * @param {string} uri - A bitcoin URI string - * @throws {TypeError} Invalid bitcoin URI - * @returns {Object} An object with the parsed params + * @returns {Address} An address generated from the private key */ -URI.parse = function(uri) { - var info = URL.parse(uri, true); +PrivateKey.prototype.toAddress = function() { + var pubkey = this.toPublicKey(); + return Address.fromPublicKey(pubkey, this.network); +}; - if (info.protocol !== 'bitcoin:') { - throw new TypeError('Invalid bitcoin URI'); - } +/** + * @returns {Object} A plain object representation + */ +PrivateKey.prototype.toObject = function toObject() { + return { + bn: this.bn.toString('hex'), + compressed: this.compressed, + network: this.network.toString() + }; +}; - // workaround to host insensitiveness - var group = /[^:]*:\/?\/?([^?]*)/.exec(uri); - info.query.address = group && group[1] || undefined; +PrivateKey.prototype.toJSON = function toJSON() { + return JSON.stringify(this.toObject()); +}; - return info.query; +/** + * Will return a string formatted for the console + * + * @returns {String} Private key + */ +PrivateKey.prototype.inspect = function() { + var uncompressed = !this.compressed ? ', uncompressed' : ''; + return ''; }; -URI.Members = ['address', 'amount', 'message', 'label', 'r']; +module.exports = PrivateKey; + +}).call(this,require("buffer").Buffer) +},{"./address":31,"./crypto/bn":34,"./crypto/point":37,"./crypto/random":38,"./encoding/base58check":41,"./networks":50,"./publickey":53,"./util/js":70,"buffer":209,"lodash":95}],53:[function(require,module,exports){ +(function (Buffer){ +'use strict'; + +var Address = require('./address'); +var BN = require('./crypto/bn'); +var Point = require('./crypto/point'); +var Hash = require('./crypto/hash'); +var JSUtil = require('./util/js'); +var Network = require('./networks'); +var _ = require('lodash'); +var $ = require('./util/preconditions'); /** - * Internal function to load the URI instance with an object. + * Instantiate a PublicKey from a {@link PrivateKey}, {@link Point}, `string`, or `Buffer`. * - * @param {Object} obj - Object with the information - * @throws {TypeError} Invalid bitcoin address - * @throws {TypeError} Invalid amount - * @throws {Error} Unknown required argument + * There are two internal properties, `network` and `compressed`, that deal with importing + * a PublicKey from a PrivateKey in WIF format. More details described on {@link PrivateKey} + * + * @example + * ```javascript + * // instantiate from a private key + * var key = PublicKey(privateKey, true); + * + * // export to as a DER hex encoded string + * var exported = key.toString(); + * + * // import the public key + * var imported = PublicKey.fromString(exported); + * ``` + * + * @param {String} data - The encoded data in various formats + * @param {Object} extra - additional options + * @param {Network=} extra.network - Which network should the address for this public key be for + * @param {String=} extra.compressed - If the public key is compressed + * @returns {PublicKey} A new valid instance of an PublicKey + * @constructor */ -URI.prototype._fromObject = function(obj) { - /* jshint maxcomplexity: 10 */ +var PublicKey = function PublicKey(data, extra) { - if (!Address.isValid(obj.address)) { - throw new TypeError('Invalid bitcoin address'); + if (!(this instanceof PublicKey)) { + return new PublicKey(data, extra); } - this.address = new Address(obj.address); - this.network = this.address.network; - this.amount = obj.amount; + $.checkArgument(data, new TypeError('First argument is required, please include public key data.')); - for (var key in obj) { - if (key === 'address' || key === 'amount') { - continue; - } + if (data instanceof PublicKey) { + // Return copy, but as it's an immutable object, return same argument + return data; + } + extra = extra || {}; - if (/^req-/.exec(key) && this.knownParams.indexOf(key) === -1) { - throw Error('Unknown required argument ' + key); - } + var info = this._classifyArgs(data, extra); - var destination = URI.Members.indexOf(key) > -1 ? this : this.extras; - destination[key] = obj[key]; - } + // validation + info.point.validate(); + + JSUtil.defineImmutable(this, { + point: info.point, + compressed: info.compressed, + network: info.network || Network.defaultNetwork + }); + + return this; }; /** - * Internal function to transform a BTC string amount into satoshis - * - * @param {string} amount - Amount BTC string - * @throws {TypeError} Invalid amount - * @returns {Object} Amount represented in satoshis + * Internal function to differentiate between arguments passed to the constructor + * @param {*} data + * @param {Object} extra */ -URI.prototype._parseAmount = function(amount) { - amount = Number(amount); - if (isNaN(amount)) { - throw new TypeError('Invalid amount'); - } - return Unit.fromBTC(amount).toSatoshis(); -}; +PublicKey.prototype._classifyArgs = function(data, extra) { + /* jshint maxcomplexity: 10 */ + var info = { + compressed: _.isUndefined(extra.compressed) || extra.compressed, + network: _.isUndefined(extra.network) ? undefined : Network.get(extra.network) + }; -URI.prototype.toObject = function toObject() { - var json = {}; - for (var i = 0; i < URI.Members.length; i++) { - var m = URI.Members[i]; - if (this.hasOwnProperty(m) && typeof(this[m]) !== 'undefined') { - json[m] = this[m].toString(); - } + // detect type of data + if (data instanceof Point) { + info.point = data; + } else if (PublicKey._isJSON(data)) { + info = PublicKey._transformJSON(data); + } else if (typeof(data) === 'string') { + info = PublicKey._transformDER(new Buffer(data, 'hex')); + } else if (PublicKey._isBuffer(data)) { + info = PublicKey._transformDER(data); + } else if (PublicKey._isPrivateKey(data)) { + info = PublicKey._transformPrivateKey(data); + } else { + throw new TypeError('First argument is an unrecognized data format.'); } - _.extend(json, this.extras); - return json; + return info; }; -URI.prototype.toJSON = function toJSON() { - return JSON.stringify(this.toObject()); +/** + * Internal function to detect if an object is a {@link PrivateKey} + * + * @param {*} param - object to test + * @returns {boolean} + * @private + */ +PublicKey._isPrivateKey = function(param) { + var PrivateKey = require('./privatekey'); + return param instanceof PrivateKey; }; /** - * Will return a the string representation of the URI + * Internal function to detect if an object is a Buffer * - * @returns {string} Bitcoin URI string + * @param {*} param - object to test + * @returns {boolean} + * @private */ -URI.prototype.toString = function() { - var query = {}; - if (this.amount) { - query.amount = Unit.fromSatoshis(this.amount).toBTC(); - } - if (this.message) { - query.message = this.message; - } - if (this.label) { - query.label = this.label; - } - if (this.r) { - query.r = this.r; - } - _.extend(query, this.extras); - - return URL.format({ - protocol: 'bitcoin:', - host: this.address, - query: query - }); +PublicKey._isBuffer = function(param) { + return (param instanceof Buffer) || (param instanceof Uint8Array); }; /** - * Will return a string formatted for the console + * Internal function to detect if a param is a JSON string or plain object * - * @returns {string} Bitcoin URI + * @param {*} param - value to test + * @returns {boolean} + * @private */ -URI.prototype.inspect = function() { - return ''; +PublicKey._isJSON = function(json) { + return !!(JSUtil.isValidJSON(json) || (json.x && json.y)); }; -module.exports = URI; +/** + * Internal function to transform a private key into a public key point + * + * @param {PrivateKey} privkey - An instance of PrivateKey + * @returns {Object} An object with keys: point and compressed + * @private + */ +PublicKey._transformPrivateKey = function(privkey) { + $.checkArgument(PublicKey._isPrivateKey(privkey), + new TypeError('Must be an instance of PrivateKey')); + var info = {}; + info.point = Point.getG().mul(privkey.bn); + info.compressed = privkey.compressed; + info.network = privkey.network; + return info; +}; -},{"./address":13,"./unit":51,"./util/js":54,"lodash":79,"url":270}],53:[function(require,module,exports){ -(function (Buffer){ -'use strict'; +/** + * Internal function to transform DER into a public key point + * + * @param {Buffer} buf - An hex encoded buffer + * @param {bool} [strict] - if set to false, will loosen some conditions + * @returns {Object} An object with keys: point and compressed + * @private + */ +PublicKey._transformDER = function(buf, strict) { + /* jshint maxstatements: 30 */ + /* jshint maxcomplexity: 12 */ + $.checkArgument(PublicKey._isBuffer(buf), new TypeError('Must be a hex buffer of DER encoded public key')); + var info = {}; -var buffer = require('buffer'); -var assert = require('assert'); + strict = _.isUndefined(strict) ? true : strict; -var js = require('./js'); -var $ = require('./preconditions'); + var x; + var y; + var xbuf; + var ybuf; -function equals(a, b) { - if (a.length !== b.length) { - return false; - } - var length = a.length; - for (var i = 0; i < length; i++) { - if (a[i] !== b[i]) { - return false; + if (buf[0] === 0x04 || (!strict && (buf[0] === 0x06 || buf[0] === 0x07))) { + xbuf = buf.slice(1, 33); + ybuf = buf.slice(33, 65); + if (xbuf.length !== 32 || ybuf.length !== 32 || buf.length !== 65) { + throw new TypeError('Length of x and y must be 32 bytes'); } + x = new BN(xbuf); + y = new BN(ybuf); + info.point = new Point(x, y); + info.compressed = false; + } else if (buf[0] === 0x03) { + xbuf = buf.slice(1); + x = new BN(xbuf); + info = PublicKey._transformX(true, x); + info.compressed = true; + } else if (buf[0] === 0x02) { + xbuf = buf.slice(1); + x = new BN(xbuf); + info = PublicKey._transformX(false, x); + info.compressed = true; + } else { + throw new TypeError('Invalid DER format public key'); } - return true; -} - -module.exports = { - /** - * Fill a buffer with a value. - * - * @param {Buffer} buffer - * @param {number} value - * @return {Buffer} - */ - fill: function fill(buffer, value) { - $.checkArgumentType(buffer, 'Buffer', 'buffer'); - $.checkArgumentType(value, 'number', 'value'); - var length = buffer.length; - for (var i = 0; i < length; i++) { - buffer[i] = value; - } - return buffer; - }, - - /** - * Return a copy of a buffer - * - * @param {Buffer} original - * @return {Buffer} - */ - copy: function(original) { - var buffer = new Buffer(original.length); - original.copy(buffer); - return buffer; - }, - - /** - * Returns true if the given argument is an instance of a buffer. Tests for - * both node's Buffer and Uint8Array - * - * @param {*} arg - * @return {boolean} - */ - isBuffer: function isBuffer(arg) { - return buffer.Buffer.isBuffer(arg) || arg instanceof Uint8Array; - }, - - /** - * Returns a zero-filled byte array - * - * @param {number} bytes - * @return {Buffer} - */ - emptyBuffer: function emptyBuffer(bytes) { - $.checkArgumentType(bytes, 'number', 'bytes'); - var result = new buffer.Buffer(bytes); - for (var i = 0; i < bytes; i++) { - result.write('\0', i); - } - return result; - }, - - /** - * Concatenates a buffer - * - * Shortcut for buffer.Buffer.concat - */ - concat: buffer.Buffer.concat, - - equals: equals, - equal: equals, - - /** - * Transforms a number from 0 to 255 into a Buffer of size 1 with that value - * - * @param {number} integer - * @return {Buffer} - */ - integerAsSingleByteBuffer: function integerAsSingleByteBuffer(integer) { - $.checkArgumentType(integer, 'number', 'integer'); - return new buffer.Buffer([integer & 0xff]); - }, - - /** - * Transform a 4-byte integer into a Buffer of length 4. - * - * @param {number} integer - * @return {Buffer} - */ - integerAsBuffer: function integerAsBuffer(integer) { - $.checkArgumentType(integer, 'number', 'integer'); - var bytes = []; - bytes.push((integer >> 24) & 0xff); - bytes.push((integer >> 16) & 0xff); - bytes.push((integer >> 8) & 0xff); - bytes.push(integer & 0xff); - return new Buffer(bytes); - }, + return info; +}; - /** - * Transform the first 4 values of a Buffer into a number, in little endian encoding - * - * @param {Buffer} buffer - * @return {number} - */ - integerFromBuffer: function integerFromBuffer(buffer) { - $.checkArgumentType(buffer, 'Buffer', 'buffer'); - return buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3]; - }, +/** + * Internal function to transform X into a public key point + * + * @param {Boolean} odd - If the point is above or below the x axis + * @param {Point} x - The x point + * @returns {Object} An object with keys: point and compressed + * @private + */ +PublicKey._transformX = function(odd, x) { + $.checkArgument(typeof odd === 'boolean', + new TypeError('Must specify whether y is odd or not (true or false)')); + var info = {}; + info.point = Point.fromX(odd, x); + return info; +}; - /** - * Transforms the first byte of an array into a number ranging from -128 to 127 - * @param {Buffer} buffer - * @return {number} - */ - integerFromSingleByteBuffer: function integerFromBuffer(buffer) { - $.checkArgumentType(buffer, 'Buffer', 'buffer'); - return buffer[0]; - }, +/** + * Instantiate a PublicKey from JSON + * + * @param {String} json - A JSON string + * @returns {PublicKey} A new valid instance of PublicKey + */ +PublicKey.fromJSON = function(json) { + $.checkArgument(PublicKey._isJSON(json), + new TypeError('Must be a valid JSON string or plain object')); + return new PublicKey(json); +}; - /** - * Transforms a buffer into a string with a number in hexa representation - * - * Shorthand for buffer.toString('hex') - * - * @param {Buffer} buffer - * @return {string} - */ - bufferToHex: function bufferToHex(buffer) { - $.checkArgumentType(buffer, 'Buffer', 'buffer'); - return buffer.toString('hex'); - }, +/** + * Internal function to transform a JSON into a public key point + * + * @param {Buffer} buf - a JSON string or plain object + * @returns {Object} An object with keys: point and compressed + * @private + */ +PublicKey._transformJSON = function(json) { + if (JSUtil.isValidJSON(json)) { + json = JSON.parse(json); + } + var x = new BN(json.x, 'hex'); + var y = new BN(json.y, 'hex'); + var point = new Point(x, y); + return new PublicKey(point, { + compressed: json.compressed + }); +}; - /** - * Reverse a buffer - * @param {Buffer} param - * @return {Buffer} - */ - reverse: function reverse(param) { - $.checkArgumentType(param, 'Buffer', 'param'); - var ret = new buffer.Buffer(param.length); - for (var i = 0; i < param.length; i++) { - ret[i] = param[param.length - i - 1]; - } - return ret; - }, +/** + * Instantiate a PublicKey from a PrivateKey + * + * @param {PrivateKey} privkey - An instance of PrivateKey + * @returns {PublicKey} A new valid instance of PublicKey + */ +PublicKey.fromPrivateKey = function(privkey) { + $.checkArgument(PublicKey._isPrivateKey(privkey), new TypeError('Must be an instance of PrivateKey')); + var info = PublicKey._transformPrivateKey(privkey); + return new PublicKey(info.point, { + compressed: info.compressed, + network: info.network + }); +}; - /** - * Transforms an hexa encoded string into a Buffer with binary values - * - * Shorthand for Buffer(string, 'hex') - * - * @param {string} string - * @return {Buffer} - */ - hexToBuffer: function hexToBuffer(string) { - assert(js.isHexa(string)); - return new buffer.Buffer(string, 'hex'); - } +/** + * Instantiate a PublicKey from a Buffer + * @param {Buffer} buf - A DER hex buffer + * @param {bool} [strict] - if set to false, will loosen some conditions + * @returns {PublicKey} A new valid instance of PublicKey + */ +PublicKey.fromDER = PublicKey.fromBuffer = function(buf, strict) { + $.checkArgument(PublicKey._isBuffer(buf), + new TypeError('Must be a hex buffer of DER encoded public key')); + var info = PublicKey._transformDER(buf, strict); + return new PublicKey(info.point, { + compressed: info.compressed + }); }; -module.exports.NULL_HASH = module.exports.fill(new Buffer(32), 0); -module.exports.EMPTY_BUFFER = new Buffer(0); +/** + * Instantiate a PublicKey from a Point + * + * @param {Point} point - A Point instance + * @param {boolean=} compressed - whether to store this public key as compressed format + * @returns {PublicKey} A new valid instance of PublicKey + */ +PublicKey.fromPoint = function(point, compressed) { + $.checkArgument(point instanceof Point, + new TypeError('First argument must be an instance of Point.')); + return new PublicKey(point, { + compressed: compressed + }); +}; -}).call(this,require("buffer").Buffer) -},{"./js":54,"./preconditions":55,"assert":89,"buffer":104}],54:[function(require,module,exports){ -'use strict'; +/** + * Instantiate a PublicKey from a DER hex encoded string + * + * @param {String} str - A DER hex string + * @param {String} [encoding] - The type of string encoding + * @returns {PublicKey} A new valid instance of PublicKey + */ +PublicKey.fromString = function(str, encoding) { + var buf = new Buffer(str, encoding || 'hex'); + var info = PublicKey._transformDER(buf); + return new PublicKey(info.point, { + compressed: info.compressed + }); +}; -var _ = require('lodash'); +/** + * Instantiate a PublicKey from an X Point + * + * @param {Boolean} odd - If the point is above or below the x axis + * @param {Point} x - The x point + * @returns {PublicKey} A new valid instance of PublicKey + */ +PublicKey.fromX = function(odd, x) { + var info = PublicKey._transformX(odd, x); + return new PublicKey(info.point, { + compressed: info.compressed + }); +}; /** - * Determines whether a string contains only hexadecimal values + * Check if there would be any errors when initializing a PublicKey * - * @name JSUtil.isHexa - * @param {string} value - * @return {boolean} true if the string is the hexa representation of a number + * @param {String} data - The encoded data in various formats + * @param {String} [compressed] - If the public key is compressed + * @returns {null|Error} An error if exists */ -var isHexa = function isHexa(value) { - if (!_.isString(value)) { - return false; +PublicKey.getValidationError = function(data) { + var error; + try { + /* jshint nonew: false */ + new PublicKey(data); + } catch (e) { + error = e; } - return /^[0-9a-fA-F]+$/.test(value); + return error; }; /** - * @namespace JSUtil + * Check if the parameters are valid + * + * @param {String} data - The encoded data in various formats + * @param {String} [compressed] - If the public key is compressed + * @returns {Boolean} If the public key would be valid */ -module.exports = { - /** - * Test if an argument is a valid JSON object. If it is, returns a truthy - * value (the json object decoded), so no double JSON.parse call is necessary - * - * @param {string} arg - * @return {Object|boolean} false if the argument is not a JSON string. - */ - isValidJSON: function isValidJSON(arg) { - var parsed; - if (!_.isString(arg)) { - return false; - } - try { - parsed = JSON.parse(arg); - } catch (e) { - return false; - } - if (typeof(parsed) === 'object') { - return true; - } - return false; - }, - isHexa: isHexa, - isHexaString: isHexa, +PublicKey.isValid = function(data) { + return !PublicKey.getValidationError(data); +}; - /** - * Clone an array - */ - cloneArray: function(array) { - return [].concat(array); - }, +/** + * @returns {Object} A plain object of the PublicKey + */ +PublicKey.prototype.toObject = function toObject() { + return { + x: this.point.getX().toString('hex'), + y: this.point.getY().toString('hex'), + compressed: this.compressed + }; +}; - /** - * Define immutable properties on a target object - * - * @param {Object} target - An object to be extended - * @param {Object} values - An object of properties - * @return {Object} The target object - */ - defineImmutable: function defineImmutable(target, values){ - Object.keys(values).forEach(function(key){ - Object.defineProperty(target, key, { - configurable: false, - enumerable: true, - value: values[key] - }); - }); - return target; - } +PublicKey.prototype.toJSON = function toJSON() { + return JSON.stringify(this.toObject()); }; -},{"lodash":79}],55:[function(require,module,exports){ -'use strict'; +/** + * Will output the PublicKey to a DER Buffer + * + * @returns {Buffer} A DER hex encoded buffer + */ +PublicKey.prototype.toBuffer = PublicKey.prototype.toDER = function() { + var x = this.point.getX(); + var y = this.point.getY(); -var errors = require('../errors'); -var _ = require('lodash'); + var xbuf = x.toBuffer({ + size: 32 + }); + var ybuf = y.toBuffer({ + size: 32 + }); -module.exports = { - checkState: function(condition, message) { - if (!condition) { - throw new errors.InvalidState(message); - } - }, - checkArgument: function(condition, argumentName, message, docsPath) { - if (!condition) { - throw new errors.InvalidArgument(argumentName, message, docsPath); - } - }, - checkArgumentType: function(argument, type, argumentName) { - argumentName = argumentName || '(unknown name)'; - if (_.isString(type)) { - if (type === 'Buffer') { - var BufferUtil = require('./buffer'); - if (!BufferUtil.isBuffer(argument)) { - throw new errors.InvalidArgumentType(argument, type, argumentName); - } - } else if (typeof argument !== type) { - throw new errors.InvalidArgumentType(argument, type, argumentName); - } + var prefix; + if (!this.compressed) { + prefix = new Buffer([0x04]); + return Buffer.concat([prefix, xbuf, ybuf]); + } else { + var odd = ybuf[ybuf.length - 1] % 2; + if (odd) { + prefix = new Buffer([0x03]); } else { - if (!(argument instanceof type)) { - throw new errors.InvalidArgumentType(argument, type.name, argumentName); - } + prefix = new Buffer([0x02]); } + return Buffer.concat([prefix, xbuf]); } }; -},{"../errors":29,"./buffer":53,"lodash":79}],56:[function(require,module,exports){ -// Utils - -function assert(val, msg) { - if (!val) - throw new Error(msg || 'Assertion failed'); -} +/** + * Will return a sha256 + ripemd160 hash of the serialized public key + * @see https://github.com/bitcoin/bitcoin/blob/master/src/pubkey.h#L141 + * @returns {Buffer} + */ +PublicKey.prototype._getID = function _getID() { + return Hash.sha256ripemd160(this.toBuffer()); +}; -function assertEqual(l, r, msg) { - if (l != r) - throw new Error(msg || ('Assertion failed: ' + l + ' != ' + r)); -} +/** + * Will return an address for the public key + * + * @returns {Address} An address generated from the public key + */ +PublicKey.prototype.toAddress = function(network) { + return Address.fromPublicKey(this, network || this.network); +}; -// 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 -} +/** + * Will output the PublicKey to a DER encoded hex string + * + * @returns {String} A DER hex encoded string + */ +PublicKey.prototype.toString = function() { + return this.toDER().toString('hex'); +}; -// BN +/** + * Will return a string formatted for the console + * + * @returns {String} Public key + */ +PublicKey.prototype.inspect = function() { + return ''; +}; -function BN(number, base, endian) { - // May be `new BN(bn)` ? - if (number !== null && - typeof number === 'object' && - Array.isArray(number.words)) { - return number; - } - this.sign = false; - this.words = null; - this.length = 0; +module.exports = PublicKey; - // Reduction context - this.red = null; +}).call(this,require("buffer").Buffer) +},{"./address":31,"./crypto/bn":34,"./crypto/hash":36,"./crypto/point":37,"./networks":50,"./privatekey":52,"./util/js":70,"./util/preconditions":71,"buffer":209,"lodash":95}],54:[function(require,module,exports){ +module.exports = require('./script'); - if (base === 'le' || base === 'be') { - endian = base; - base = 10; - } +module.exports.Interpreter = require('./interpreter'); - if (number !== null) - this._init(number || 0, base || 10, endian || 'be'); -} -if (typeof module === 'object') - module.exports = BN; +},{"./interpreter":55,"./script":56}],55:[function(require,module,exports){ +(function (Buffer){ +'use strict'; -BN.BN = BN; -BN.wordSize = 26; +var _ = require('lodash'); -BN.prototype._init = function init(number, base, endian) { - if (typeof number === 'number') { - if (number < 0) { - this.sign = true; - number = -number; - } - if (number < 0x4000000) { - this.words = [ number & 0x3ffffff ]; - this.length = 1; - } else { - this.words = [ - number & 0x3ffffff, - (number / 0x4000000) & 0x3ffffff - ]; - this.length = 2; - } - return; - } else if (typeof number === 'object') { - return this._initArray(number, base, endian); +var Script = require('./script'); +var Opcode = require('../opcode'); +var BN = require('../crypto/bn'); +var Hash = require('../crypto/hash'); +var Signature = require('../crypto/signature'); +var PublicKey = require('../publickey'); + +/** + * Bitcoin transactions contain scripts. Each input has a script called the + * scriptSig, and each output has a script called the scriptPubkey. To validate + * an input, the input's script is concatenated with the referenced output script, + * and the result is executed. If at the end of execution the stack contains a + * "true" value, then the transaction is valid. + * + * The primary way to use this class is via the verify function. + * e.g., Interpreter().verify( ... ); + */ +var Interpreter = function Interpreter(obj) { + if (!(this instanceof Interpreter)) { + return new Interpreter(obj); } - if (base === 'hex') - base = 16; - assert(base === (base | 0) && base >= 2 && base <= 36); + if (obj) { + this.initialize(); + this.set(obj); + } else { + this.initialize(); + } +}; - number = number.toString().replace(/\s+/g, ''); - var start = 0; - if (number[0] === '-') - start++; +/** + * Verifies a Script by executing it and returns true if it is valid. + * This function needs to be provided with the scriptSig and the scriptPubkey + * separately. + * @param {Script} scriptSig - the script's first part (corresponding to the tx input) + * @param {Script} scriptPubkey - the script's last part (corresponding to the tx output) + * @param {Transaction} [tx] - the Transaction containing the scriptSig in one input (used + * to check signature validity for some opcodes like OP_CHECKSIG) + * @param {number} nin - index of the transaction input containing the scriptSig verified. + * @param {number} flags - evaluation flags. See Interpreter.SCRIPT_* constants + * + * Translated from bitcoind's VerifyScript + */ +Interpreter.prototype.verify = function(scriptSig, scriptPubkey, tx, nin, flags) { + var Transaction = require('../transaction'); + if (_.isUndefined(tx)) { + tx = new Transaction(); + } + if (_.isUndefined(nin)) { + nin = 0; + } + if (_.isUndefined(flags)) { + flags = 0; + } + this.set({ + script: scriptSig, + tx: tx, + nin: nin, + flags: flags + }); + var stackCopy; - if (base === 16) - this._parseHex(number, start); - else - this._parseBase(number, base, start); + if ((flags & Interpreter.SCRIPT_VERIFY_SIGPUSHONLY) !== 0 && !scriptSig.isPushOnly()) { + this.errstr = 'SCRIPT_ERR_SIG_PUSHONLY'; + return false; + } - if (number[0] === '-') - this.sign = true; + // evaluate scriptSig + if (!this.evaluate()) { + return false; + } - this.strip(); -}; + if (flags & Interpreter.SCRIPT_VERIFY_P2SH) { + stackCopy = this.stack.slice(); + } -BN.prototype._initArray = function _initArray(number, base, endian) { - // Perhaps a Uint8Array - assert(typeof number.length === 'number'); - 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 stack = this.stack; + this.initialize(); + this.set({ + script: scriptPubkey, + stack: stack, + tx: tx, + nin: nin, + flags: flags + }); - var off = 0; - if (endian === 'be') { - for (var i = number.length - 1, j = 0; i >= 0; i -= 3) { - var 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 (var i = 0, j = 0; i < number.length; i += 3) { - var 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++; - } - } + // evaluate scriptPubkey + if (!this.evaluate()) { + return false; } - return this.strip(); -}; - -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; - // Scan 24-bit chunks and add them to the number - var off = 0; - for (var i = number.length - 6, j = 0; i >= start; i -= 6) { - var w = parseInt(number.slice(i, i + 6), 16); - this.words[j] |= (w << off) & 0x3ffffff; - this.words[j + 1] |= w >>> (26 - off) & 0x3fffff; - off += 24; - if (off >= 26) { - off -= 26; - j++; - } + if (this.stack.length === 0) { + this.errstr = 'SCRIPT_ERR_EVAL_FALSE_NO_RESULT'; + return false; } - if (i + 6 !== start) { - var w = parseInt(number.slice(start, i + 6), 16); - this.words[j] |= (w << off) & 0x3ffffff; - this.words[j + 1] |= w >>> (26 - off) & 0x3fffff; + + var buf = this.stack[this.stack.length - 1]; + if (!Interpreter.castToBool(buf)) { + this.errstr = 'SCRIPT_ERR_EVAL_FALSE_IN_STACK'; + return false; } - this.strip(); -}; -BN.prototype._parseBase = function parseBase(number, base, start) { - // Initialize as zero - this.words = [ 0 ]; - this.length = 1; + // Additional validation for spend-to-script-hash transactions: + if ((flags & Interpreter.SCRIPT_VERIFY_P2SH) && scriptPubkey.isScriptHashOut()) { + // scriptSig must be literals-only or validation fails + if (!scriptSig.isPushOnly()) { + this.errstr = 'SCRIPT_ERR_SIG_PUSHONLY'; + return false; + } - var word = 0; - var q = 1; - var p = 0; - var bigQ = null; - for (var i = start; i < number.length; i++) { - var digit; - var ch = number[i]; - if (base === 10 || ch <= '9') - digit = ch | 0; - else if (ch >= 'a') - digit = ch.charCodeAt(0) - 97 + 10; - else - digit = ch.charCodeAt(0) - 65 + 10; - word *= base; - word += digit; - q *= base; - p++; + // stackCopy cannot be empty here, because if it was the + // P2SH HASH <> EQUAL scriptPubKey would be evaluated with + // an empty stack and the EvalScript above would return false. + if (stackCopy.length === 0) { + throw new Error('internal error - stack copy empty'); + } - if (q > 0xfffff) { - assert(q <= 0x3ffffff); - if (!bigQ) - bigQ = new BN(q); - this.mul(bigQ).copy(this); - this.iadd(new BN(word)); - word = 0; - q = 1; - p = 0; + var redeemScriptSerialized = stackCopy[stackCopy.length - 1]; + var redeemScript = Script.fromBuffer(redeemScriptSerialized); + stackCopy.pop(); + + this.initialize(); + this.set({ + script: redeemScript, + stack: stackCopy, + tx: tx, + nin: nin, + flags: flags + }); + + // evaluate redeemScript + if (!this.evaluate()) { + return false; + } + + if (stackCopy.length === 0) { + this.errstr = 'SCRIPT_ERR_EVAL_FALSE_NO_P2SH_STACK'; + return false; + } + + if (!Interpreter.castToBool(stackCopy[stackCopy.length - 1])) { + this.errstr = 'SCRIPT_ERR_EVAL_FALSE_IN_P2SH_STACK'; + return false; + } else { + return true; } } - if (p !== 0) { - this.mul(new BN(q)).copy(this); - this.iadd(new BN(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.sign = this.sign; - dest.red = this.red; + return true; }; -BN.prototype.clone = function clone() { - var r = new BN(null); - this.copy(r); - return r; -}; +module.exports = Interpreter; -// 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(); +Interpreter.prototype.initialize = function(obj) { + this.stack = []; + this.altstack = []; + this.pc = 0; + this.pbegincodehash = 0; + this.nOpCount = 0; + this.vfExec = []; + this.errstr = ''; + this.flags = 0; }; -BN.prototype._normSign = function _normSign() { - // -0 = 0 - if (this.length === 1 && this.words[0] === 0) - this.sign = false; - return this; +Interpreter.prototype.set = function(obj) { + this.script = obj.script || this.script; + this.tx = obj.tx || this.tx; + this.nin = typeof obj.nin !== 'undefined' ? obj.nin : this.nin; + this.stack = obj.stack || this.stack; + this.altstack = obj.altack || this.altstack; + this.pc = typeof obj.pc !== 'undefined' ? obj.pc : this.pc; + this.pbegincodehash = typeof obj.pbegincodehash !== 'undefined' ? obj.pbegincodehash : this.pbegincodehash; + this.nOpCount = typeof obj.nOpCount !== 'undefined' ? obj.nOpCount : this.nOpCount; + this.vfExec = obj.vfExec || this.vfExec; + this.errstr = obj.errstr || this.errstr; + this.flags = typeof obj.flags !== 'undefined' ? obj.flags : this.flags; }; -BN.prototype.inspect = function inspect() { - return (this.red ? ''; -}; +Interpreter.true = new Buffer([1]); +Interpreter.false = new Buffer([]); -/* +Interpreter.MAX_SCRIPT_ELEMENT_SIZE = 520; -var zeros = []; -var groupSizes = []; -var groupBases = []; +// flags taken from bitcoind +// bitcoind commit: b5d1b1092998bc95313856d535c632ea5a8f9104 +Interpreter.SCRIPT_VERIFY_NONE = 0; -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; - // TODO: <= - while (groupBase < (1 << BN.wordSize) / base) { - groupBase *= base; - groupSize += 1; - } - groupSizes[base] = groupSize; - groupBases[base] = groupBase; -} +// Evaluate P2SH subscripts (softfork safe, BIP16). +Interpreter.SCRIPT_VERIFY_P2SH = (1 << 0); -*/ +// Passing a non-strict-DER signature or one with undefined hashtype to a checksig operation causes script failure. +// Passing a pubkey that is not (0x04 + 64 bytes) or (0x02 or 0x03 + 32 bytes) to checksig causes that pubkey to be +// skipped (not softfork safe: this flag can widen the validity of OP_CHECKSIG OP_NOT). +Interpreter.SCRIPT_VERIFY_STRICTENC = (1 << 1); -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' -]; +// Passing a non-strict-DER signature to a checksig operation causes script failure (softfork safe, BIP62 rule 1) +Interpreter.SCRIPT_VERIFY_DERSIG = (1 << 2); -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 -]; +// Passing a non-strict-DER signature or one with S > order/2 to a checksig operation causes script failure +// (softfork safe, BIP62 rule 5). +Interpreter.SCRIPT_VERIFY_LOW_S = (1 << 3); -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 -]; +// verify dummy stack item consumed by CHECKMULTISIG is of zero-length (softfork safe, BIP62 rule 7). +Interpreter.SCRIPT_VERIFY_NULLDUMMY = (1 << 4); -BN.prototype.toString = function toString(base, padding) { - base = base || 10; - if (base === 16 || base === 'hex') { - var out = ''; - var off = 0; - var padding = padding | 0 || 1; - 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--; +// Using a non-push operator in the scriptSig causes script failure (softfork safe, BIP62 rule 2). +Interpreter.SCRIPT_VERIFY_SIGPUSHONLY = (1 << 5); + +// Require minimal encodings for all push operations (OP_0... OP_16, OP_1NEGATE where possible, direct +// pushes up to 75 bytes, OP_PUSHDATA up to 255 bytes, OP_PUSHDATA2 for anything larger). Evaluating +// any other push causes the script to fail (BIP62 rule 3). +// In addition, whenever a stack element is interpreted as a number, it must be of minimal length (BIP62 rule 4). +// (softfork safe) +Interpreter.SCRIPT_VERIFY_MINIMALDATA = (1 << 6); + +// Discourage use of NOPs reserved for upgrades (NOP1-10) +// +// Provided so that nodes can avoid accepting or mining transactions +// containing executed NOP's whose meaning may change after a soft-fork, +// thus rendering the script invalid; with this flag set executing +// discouraged NOPs fails the script. This verification flag will never be +// a mandatory flag applied to scripts in a block. NOPs that are not +// executed, e.g. within an unexecuted IF ENDIF block, are *not* rejected. +Interpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS = (1 << 7); + +Interpreter.castToBool = function(buf) { + for (var i = 0; i < buf.length; i++) { + if (buf[i] !== 0) { + // can be negative zero + if (i === buf.length - 1 && buf[i] === 0x80) { + return false; } + return true; } - if (carry !== 0) - out = carry.toString(16) + out; - while (out.length % padding !== 0) - out = '0' + out; - if (this.sign) - out = '-' + out; - return out; - } else 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]; - var out = ''; - var c = this.clone(); - c.sign = false; - while (c.cmpn(0) !== 0) { - var r = c.modn(groupBase).toString(base); - c = c.idivn(groupBase); + } + return false; +}; - if (c.cmpn(0) !== 0) - out = zeros[groupSize - r.length] + r + out; - else - out = r + out; +/** + * Translated from bitcoind's CheckSignatureEncoding + */ +Interpreter.prototype.checkSignatureEncoding = function(buf) { + var sig; + if ((this.flags & (Interpreter.SCRIPT_VERIFY_DERSIG | Interpreter.SCRIPT_VERIFY_LOW_S | Interpreter.SCRIPT_VERIFY_STRICTENC)) !== 0 && !Signature.isTxDER(buf)) { + this.errstr = 'SCRIPT_ERR_SIG_DER_INVALID_FORMAT'; + return false; + } else if ((this.flags & Interpreter.SCRIPT_VERIFY_LOW_S) !== 0) { + sig = Signature.fromTxFormat(buf); + if (!sig.hasLowS()) { + this.errstr = 'SCRIPT_ERR_SIG_DER_HIGH_S'; + return false; + } + } else if ((this.flags & Interpreter.SCRIPT_VERIFY_STRICTENC) !== 0) { + sig = Signature.fromTxFormat(buf); + if (!sig.hasDefinedHashtype()) { + this.errstr = 'SCRIPT_ERR_SIG_HASHTYPE'; + return false; } - if (this.cmpn(0) === 0) - out = '0' + out; - if (this.sign) - out = '-' + out; - return out; - } else { - assert(false, 'Base should be between 2 and 36'); } + return true; }; -BN.prototype.toJSON = function toJSON() { - return this.toString(16); +/** + * Translated from bitcoind's CheckPubKeyEncoding + */ +Interpreter.prototype.checkPubkeyEncoding = function(buf) { + if ((this.flags & Interpreter.SCRIPT_VERIFY_STRICTENC) !== 0 && !PublicKey.isValid(buf)) { + this.errstr = 'SCRIPT_ERR_PUBKEYTYPE'; + return false; + } + return true; }; -BN.prototype.toArray = function toArray() { - this.strip(); - var res = new Array(this.byteLength()); - res[0] = 0; +/** + * Based on bitcoind's EvalScript function, with the inner loop moved to + * Interpreter.prototype.step() + * bitcoind commit: b5d1b1092998bc95313856d535c632ea5a8f9104 + */ +Interpreter.prototype.evaluate = function() { + if (this.script.toBuffer().length > 10000) { + this.errstr = 'SCRIPT_ERR_SCRIPT_SIZE'; + return false; + } - var q = this.clone(); - for (var i = 0; q.cmpn(0) !== 0; i++) { - var b = q.andln(0xff); - q.ishrn(8); + try { + while (this.pc < this.script.chunks.length) { + var fSuccess = this.step(); + if (!fSuccess) { + return false; + } + } - // Assume big-endian - res[res.length - i - 1] = b; + // Size limits + if (this.stack.length + this.altstack.length > 1000) { + this.errstr = 'SCRIPT_ERR_STACK_SIZE'; + return false; + } + } catch (e) { + this.errstr = 'SCRIPT_ERR_UNKNOWN_ERROR: ' + e; + return false; } - return res; -}; - -/* -function genCountBits(bits) { - var arr = []; - - for (var i = bits - 1; i >= 0; i--) { - var bit = '0x' + (1 << i).toString(16); - arr.push('w >= ' + bit + ' ? ' + (i + 1)); + if (this.vfExec.length > 0) { + this.errstr = 'SCRIPT_ERR_UNBALANCED_CONDITIONAL'; + return false; } - return new Function('w', 'return ' + arr.join(' :\n') + ' :\n0;'); -}; - -BN.prototype._countBits = genCountBits(26); -*/ - -// Sadly chrome apps could not contain `new Function()` calls -BN.prototype._countBits = function _countBits(w) { - return w >= 0x2000000 ? 26 : - w >= 0x1000000 ? 25 : - w >= 0x800000 ? 24 : - w >= 0x400000 ? 23 : - w >= 0x200000 ? 22 : - w >= 0x100000 ? 21 : - w >= 0x80000 ? 20 : - w >= 0x40000 ? 19 : - w >= 0x20000 ? 18 : - w >= 0x10000 ? 17 : - w >= 0x8000 ? 16 : - w >= 0x4000 ? 15 : - w >= 0x2000 ? 14 : - w >= 0x1000 ? 13 : - w >= 0x800 ? 12 : - w >= 0x400 ? 11 : - w >= 0x200 ? 10 : - w >= 0x100 ? 9 : - w >= 0x80 ? 8 : - w >= 0x40 ? 7 : - w >= 0x20 ? 6 : - w >= 0x10 ? 5 : - w >= 0x8 ? 4 : - w >= 0x4 ? 3 : - w >= 0x2 ? 2 : - w >= 0x1 ? 1 : - 0; -}; - -// Return number of used bits in a BN -BN.prototype.bitLength = function bitLength() { - var hi = 0; - var w = this.words[this.length - 1]; - var hi = this._countBits(w); - return (this.length - 1) * 26 + hi; -}; - -BN.prototype.byteLength = function byteLength() { - var hi = 0; - var w = this.words[this.length - 1]; - return Math.ceil(this.bitLength() / 8); -}; - -// Return negative clone of `this` -BN.prototype.neg = function neg() { - if (this.cmpn(0) === 0) - return this.clone(); - - var r = this.clone(); - r.sign = !this.sign; - return r; + return true; }; -// Add `num` to `this` in-place -BN.prototype.iadd = function iadd(num) { - // negative + positive - if (this.sign && !num.sign) { - this.sign = false; - var r = this.isub(num); - this.sign = !this.sign; - return this._normSign(); - - // positive + negative - } else if (!this.sign && num.sign) { - num.sign = false; - var r = this.isub(num); - num.sign = true; - return r._normSign(); - } +/** + * Based on the inner loop of bitcoind's EvalScript function + * bitcoind commit: b5d1b1092998bc95313856d535c632ea5a8f9104 + */ +Interpreter.prototype.step = function() { - // a.length > b.length - var a; - var b; - if (this.length > num.length) { - a = this; - b = num; - } else { - a = num; - b = this; - } + var fRequireMinimal = (this.flags & Interpreter.SCRIPT_VERIFY_MINIMALDATA) !== 0; - var carry = 0; - for (var i = 0; i < b.length; i++) { - var r = a.words[i] + b.words[i] + carry; - this.words[i] = r & 0x3ffffff; - carry = r >>> 26; - } - for (; carry !== 0 && i < a.length; i++) { - var r = a.words[i] + carry; - this.words[i] = r & 0x3ffffff; - carry = r >>> 26; - } + //bool fExec = !count(vfExec.begin(), vfExec.end(), false); + var fExec = (this.vfExec.indexOf(false) === -1); + var buf, buf1, buf2, spliced, n, x1, x2, bn, bn1, bn2, bufSig, bufPubkey, subscript; + var sig, pubkey; + var fValue, fSuccess; - 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]; + // Read instruction + var chunk = this.script.chunks[this.pc]; + this.pc++; + var opcodenum = chunk.opcodenum; + if (_.isUndefined(opcodenum)) { + this.errstr = 'SCRIPT_ERR_UNDEFINED_OPCODE'; + return false; } - - return this; -}; - -// Add `num` to `this` -BN.prototype.add = function add(num) { - if (num.sign && !this.sign) { - num.sign = false; - var res = this.sub(num); - num.sign = true; - return res; - } else if (!num.sign && this.sign) { - this.sign = false; - var res = num.sub(this); - this.sign = true; - return res; + if (chunk.buf && chunk.buf.length > Interpreter.MAX_SCRIPT_ELEMENT_SIZE) { + this.errstr = 'SCRIPT_ERR_PUSH_SIZE'; + return false; } - if (this.length > num.length) - return this.clone().iadd(num); - else - return num.clone().iadd(this); -}; - -// Subtract `num` from `this` in-place -BN.prototype.isub = function isub(num) { - // this - (-num) = this + num - if (num.sign) { - num.sign = false; - var r = this.iadd(num); - num.sign = true; - return r._normSign(); - - // -this - num = -(this + num) - } else if (this.sign) { - this.sign = false; - this.iadd(num); - this.sign = true; - return this._normSign(); + // Note how Opcode.OP_RESERVED does not count towards the opcode limit. + if (opcodenum > Opcode.OP_16 && ++(this.nOpCount) > 201) { + this.errstr = 'SCRIPT_ERR_OP_COUNT'; + return false; } - // At this point both numbers are positive - var cmp = this.cmp(num); - - // Optimization - zeroify - if (cmp === 0) { - this.sign = false; - this.length = 1; - this.words[0] = 0; - return this; - } - // a > b - if (cmp > 0) { - var a = this; - var b = num; - } else { - var a = num; - var b = this; + if (opcodenum === Opcode.OP_CAT || + opcodenum === Opcode.OP_SUBSTR || + opcodenum === Opcode.OP_LEFT || + opcodenum === Opcode.OP_RIGHT || + opcodenum === Opcode.OP_INVERT || + opcodenum === Opcode.OP_AND || + opcodenum === Opcode.OP_OR || + opcodenum === Opcode.OP_XOR || + opcodenum === Opcode.OP_2MUL || + opcodenum === Opcode.OP_2DIV || + opcodenum === Opcode.OP_MUL || + opcodenum === Opcode.OP_DIV || + opcodenum === Opcode.OP_MOD || + opcodenum === Opcode.OP_LSHIFT || + opcodenum === Opcode.OP_RSHIFT) { + this.errstr = 'SCRIPT_ERR_DISABLED_OPCODE'; + return false; } - var carry = 0; - for (var i = 0; i < b.length; i++) { - var r = a.words[i] - b.words[i] - carry; - if (r < 0) { - r += 0x4000000; - carry = 1; - } else { - carry = 0; + if (fExec && 0 <= opcodenum && opcodenum <= Opcode.OP_PUSHDATA4) { + if (fRequireMinimal && !this.script.checkMinimalPush(this.pc - 1)) { + this.errstr = 'SCRIPT_ERR_MINIMALDATA'; + return false; } - this.words[i] = r; - } - for (; carry !== 0 && i < a.length; i++) { - var r = a.words[i] - carry; - if (r < 0) { - r += 0x4000000; - carry = 1; + if (!chunk.buf) { + this.stack.push(Interpreter.false); + } else if (chunk.len !== chunk.buf.length) { + throw new Error('Length of push value not equal to length of data'); } else { - carry = 0; + this.stack.push(chunk.buf); } - this.words[i] = r; - } + } else if (fExec || (Opcode.OP_IF <= opcodenum && opcodenum <= Opcode.OP_ENDIF)) { + switch (opcodenum) { + // Push value + case Opcode.OP_1NEGATE: + case Opcode.OP_1: + case Opcode.OP_2: + case Opcode.OP_3: + case Opcode.OP_4: + case Opcode.OP_5: + case Opcode.OP_6: + case Opcode.OP_7: + case Opcode.OP_8: + case Opcode.OP_9: + case Opcode.OP_10: + case Opcode.OP_11: + case Opcode.OP_12: + case Opcode.OP_13: + case Opcode.OP_14: + case Opcode.OP_15: + case Opcode.OP_16: + { + // ( -- value) + // ScriptNum bn((int)opcode - (int)(Opcode.OP_1 - 1)); + n = opcodenum - (Opcode.OP_1 - 1); + buf = new BN(n).toScriptNumBuffer(); + this.stack.push(buf); + // The result of these opcodes should always be the minimal way to push the data + // they push, so no need for a CheckMinimalPush here. + } + break; - // 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.sign = true; + // + // Control + // + case Opcode.OP_NOP: + break; - return this.strip(); -}; + case Opcode.OP_NOP1: + case Opcode.OP_NOP2: + case Opcode.OP_NOP3: + case Opcode.OP_NOP4: + case Opcode.OP_NOP5: + case Opcode.OP_NOP6: + case Opcode.OP_NOP7: + case Opcode.OP_NOP8: + case Opcode.OP_NOP9: + case Opcode.OP_NOP10: + { + if (this.flags & Interpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) { + this.errstr = 'SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS'; + return false; + } + } + break; -// Subtract `num` from `this` -BN.prototype.sub = function sub(num) { - return this.clone().isub(num); -}; + case Opcode.OP_IF: + case Opcode.OP_NOTIF: + { + // if [statements] [else [statements]] endif + // bool fValue = false; + fValue = false; + if (fExec) { + if (this.stack.length < 1) { + this.errstr = 'SCRIPT_ERR_UNBALANCED_CONDITIONAL'; + return false; + } + buf = this.stack.pop(); + fValue = Interpreter.castToBool(buf); + if (opcodenum === Opcode.OP_NOTIF) { + fValue = !fValue; + } + } + this.vfExec.push(fValue); + } + break; -/* -// NOTE: This could be potentionally used to generate loop-less multiplications -function _genCombMulTo(alen, blen) { - var len = alen + blen - 1; - var src = [ - 'var a = this.words, b = num.words, o = out.words, c = 0, w, ' + - 'mask = 0x3ffffff, shift = 0x4000000;', - 'out.length = ' + len + ';' - ]; - for (var k = 0; k < len; k++) { - var minJ = Math.max(0, k - alen + 1); - var maxJ = Math.min(k, blen - 1); + case Opcode.OP_ELSE: + { + if (this.vfExec.length === 0) { + this.errstr = 'SCRIPT_ERR_UNBALANCED_CONDITIONAL'; + return false; + } + this.vfExec[this.vfExec.length - 1] = !this.vfExec[this.vfExec.length - 1]; + } + break; - for (var j = minJ; j <= maxJ; j++) { - var i = k - j; - var mul = 'a[' + i + '] * b[' + j + ']'; + case Opcode.OP_ENDIF: + { + if (this.vfExec.length === 0) { + this.errstr = 'SCRIPT_ERR_UNBALANCED_CONDITIONAL'; + return false; + } + this.vfExec.pop(); + } + break; - if (j === minJ) { - src.push('w = ' + mul + ' + c;'); - src.push('c = (w / shift) | 0;'); - } else { - src.push('w += ' + mul + ';'); - src.push('c += (w / shift) | 0;'); - } - src.push('w &= mask;'); - } - src.push('o[' + k + '] = w;'); - } - src.push('if (c !== 0) {', - ' o[' + k + '] = c;', - ' out.length++;', - '}', - 'return out;'); + case Opcode.OP_VERIFY: + { + // (true -- ) or + // (false -- false) and return + if (this.stack.length < 1) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + buf = this.stack[this.stack.length - 1]; + fValue = Interpreter.castToBool(buf); + if (fValue) { + this.stack.pop(); + } else { + this.errstr = 'SCRIPT_ERR_VERIFY'; + return false; + } + } + break; - return src.join('\n'); -} -*/ + case Opcode.OP_RETURN: + { + this.errstr = 'SCRIPT_ERR_OP_RETURN'; + return false; + } + break; -BN.prototype._smallMulTo = function _smallMulTo(num, out) { - out.sign = num.sign !== this.sign; - out.length = this.length + num.length; - var carry = 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 = carry >>> 26; - var rword = carry & 0x3ffffff; - var maxJ = Math.min(k, num.length - 1); - for (var j = Math.max(0, k - this.length + 1); j <= maxJ; j++) { - var i = k - j; - var a = this.words[i] | 0; - var b = num.words[j] | 0; - var r = a * b; + // + // Stack ops + // + case Opcode.OP_TOALTSTACK: + { + if (this.stack.length < 1) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + this.altstack.push(this.stack.pop()); + } + break; - var lo = r & 0x3ffffff; - ncarry = (ncarry + ((r / 0x4000000) | 0)) | 0; - lo = (lo + rword) | 0; - rword = lo & 0x3ffffff; - ncarry = (ncarry + (lo >>> 26)) | 0; - } - out.words[k] = rword; - carry = ncarry; - } - if (carry !== 0) { - out.words[k] = carry; - } else { - out.length--; - } + case Opcode.OP_FROMALTSTACK: + { + if (this.altstack.length < 1) { + this.errstr = 'SCRIPT_ERR_INVALID_ALTSTACK_OPERATION'; + return false; + } + this.stack.push(this.altstack.pop()); + } + break; - return out.strip(); -}; + case Opcode.OP_2DROP: + { + // (x1 x2 -- ) + if (this.stack.length < 2) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + this.stack.pop(); + this.stack.pop(); + } + break; -BN.prototype._bigMulTo = function _bigMulTo(num, out) { - out.sign = num.sign !== this.sign; - out.length = this.length + num.length; + case Opcode.OP_2DUP: + { + // (x1 x2 -- x1 x2 x1 x2) + if (this.stack.length < 2) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + buf1 = this.stack[this.stack.length - 2]; + buf2 = this.stack[this.stack.length - 1]; + this.stack.push(buf1); + this.stack.push(buf2); + } + break; - 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 - this.length + 1); j <= maxJ; j++) { - var i = k - j; - var a = this.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--; - } + case Opcode.OP_3DUP: + { + // (x1 x2 x3 -- x1 x2 x3 x1 x2 x3) + if (this.stack.length < 3) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + buf1 = this.stack[this.stack.length - 3]; + buf2 = this.stack[this.stack.length - 2]; + var buf3 = this.stack[this.stack.length - 1]; + this.stack.push(buf1); + this.stack.push(buf2); + this.stack.push(buf3); + } + break; - return out.strip(); -}; + case Opcode.OP_2OVER: + { + // (x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2) + if (this.stack.length < 4) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + buf1 = this.stack[this.stack.length - 4]; + buf2 = this.stack[this.stack.length - 3]; + this.stack.push(buf1); + this.stack.push(buf2); + } + break; -BN.prototype.mulTo = function mulTo(num, out) { - var res; - if (this.length + num.length < 63) - res = this._smallMulTo(num, out); - else - res = this._bigMulTo(num, out); - return res; -}; + case Opcode.OP_2ROT: + { + // (x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2) + if (this.stack.length < 6) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + spliced = this.stack.splice(this.stack.length - 6, 2); + this.stack.push(spliced[0]); + this.stack.push(spliced[1]); + } + break; -// 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); -}; + case Opcode.OP_2SWAP: + { + // (x1 x2 x3 x4 -- x3 x4 x1 x2) + if (this.stack.length < 4) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + spliced = this.stack.splice(this.stack.length - 4, 2); + this.stack.push(spliced[0]); + this.stack.push(spliced[1]); + } + break; -// In-place Multiplication -BN.prototype.imul = function imul(num) { - if (this.cmpn(0) === 0 || num.cmpn(0) === 0) { - this.words[0] = 0; - this.length = 1; - return this; - } + case Opcode.OP_IFDUP: + { + // (x - 0 | x x) + if (this.stack.length < 1) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + buf = this.stack[this.stack.length - 1]; + fValue = Interpreter.castToBool(buf); + if (fValue) { + this.stack.push(buf); + } + } + break; - var tlen = this.length; - var nlen = num.length; + case Opcode.OP_DEPTH: + { + // -- stacksize + buf = new BN(this.stack.length).toScriptNumBuffer(); + this.stack.push(buf); + } + break; - this.sign = num.sign !== this.sign; - this.length = this.length + num.length; - this.words[this.length - 1] = 0; + case Opcode.OP_DROP: + { + // (x -- ) + if (this.stack.length < 1) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + this.stack.pop(); + } + break; - var lastCarry = 0; - for (var k = this.length - 2; k >= 0; k--) { - // Sum all words with the same `i + j = k` and accumulate `carry`, - // note that carry could be >= 0x3ffffff - var carry = 0; - var rword = 0; - var maxJ = Math.min(k, nlen - 1); - for (var j = Math.max(0, k - tlen + 1); j <= maxJ; j++) { - var i = k - j; - var a = this.words[i]; - var b = num.words[j]; - var r = a * b; + case Opcode.OP_DUP: + { + // (x -- x x) + if (this.stack.length < 1) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + this.stack.push(this.stack[this.stack.length - 1]); + } + break; - var lo = r & 0x3ffffff; - carry += (r / 0x4000000) | 0; - lo += rword; - rword = lo & 0x3ffffff; - carry += lo >>> 26; - } - this.words[k] = rword; - this.words[k + 1] += carry; - carry = 0; - } + case Opcode.OP_NIP: + { + // (x1 x2 -- x2) + if (this.stack.length < 2) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + this.stack.splice(this.stack.length - 2, 1); + } + break; - // Propagate overflows - var carry = 0; - for (var i = 1; i < this.length; i++) { - var w = this.words[i] + carry; - this.words[i] = w & 0x3ffffff; - carry = w >>> 26; - } + case Opcode.OP_OVER: + { + // (x1 x2 -- x1 x2 x1) + if (this.stack.length < 2) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + this.stack.push(this.stack[this.stack.length - 2]); + } + break; - return this.strip(); -}; + case Opcode.OP_PICK: + case Opcode.OP_ROLL: + { + // (xn ... x2 x1 x0 n - xn ... x2 x1 x0 xn) + // (xn ... x2 x1 x0 n - ... x2 x1 x0 xn) + if (this.stack.length < 2) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + buf = this.stack[this.stack.length - 1]; + bn = BN.fromScriptNumBuffer(buf, fRequireMinimal); + n = bn.toNumber(); + this.stack.pop(); + if (n < 0 || n >= this.stack.length) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + buf = this.stack[this.stack.length - n - 1]; + if (opcodenum === Opcode.OP_ROLL) { + this.stack.splice(this.stack.length - n - 1, 1); + } + this.stack.push(buf); + } + break; -// `this` * `this` -BN.prototype.sqr = function sqr() { - return this.mul(this); -}; + case Opcode.OP_ROT: + { + // (x1 x2 x3 -- x2 x3 x1) + // x2 x1 x3 after first swap + // x2 x3 x1 after second swap + if (this.stack.length < 3) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + x1 = this.stack[this.stack.length - 3]; + x2 = this.stack[this.stack.length - 2]; + var x3 = this.stack[this.stack.length - 1]; + this.stack[this.stack.length - 3] = x2; + this.stack[this.stack.length - 2] = x3; + this.stack[this.stack.length - 1] = x1; + } + break; -// `this` * `this` in-place -BN.prototype.isqr = function isqr() { - return this.mul(this); -}; + case Opcode.OP_SWAP: + { + // (x1 x2 -- x2 x1) + if (this.stack.length < 2) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + x1 = this.stack[this.stack.length - 2]; + x2 = this.stack[this.stack.length - 1]; + this.stack[this.stack.length - 2] = x2; + this.stack[this.stack.length - 1] = x1; + } + break; -// Shift-left in-place -BN.prototype.ishln = function ishln(bits) { - assert(typeof bits === 'number' && bits >= 0); - var r = bits % 26; - var s = (bits - r) / 26; - var carryMask = (0x3ffffff >>> (26 - r)) << (26 - r); + case Opcode.OP_TUCK: + { + // (x1 x2 -- x2 x1 x2) + if (this.stack.length < 2) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + this.stack.splice(this.stack.length - 2, 0, this.stack[this.stack.length - 1]); + } + break; - var o = this.clone(); - if (r !== 0) { - var carry = 0; - for (var i = 0; i < this.length; i++) { - var newCarry = this.words[i] & carryMask; - var c = (this.words[i] - newCarry) << r; - this.words[i] = c | carry; - carry = newCarry >>> (26 - r); - } - if (carry) { - this.words[i] = carry; - this.length++; - } - } - if (s !== 0) { - for (var i = this.length - 1; i >= 0; i--) - this.words[i + s] = this.words[i]; - for (var i = 0; i < s; i++) - this.words[i] = 0; - this.length += s; - } + case Opcode.OP_SIZE: + { + // (in -- in size) + if (this.stack.length < 1) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + bn = new BN(this.stack[this.stack.length - 1].length); + this.stack.push(bn.toScriptNumBuffer()); + } + break; - return this.strip(); -}; -// Shift-right in-place -// NOTE: `hint` is a lowest bit before trailing zeroes -// NOTE: if `extended` is true - { lo: ..., hi: } object will be returned -BN.prototype.ishrn = function ishrn(bits, hint, extended) { - assert(typeof bits === 'number' && bits >= 0); - if (hint) - hint = (hint - (hint % 26)) / 26; - else - hint = 0; + // + // Bitwise logic + // + case Opcode.OP_EQUAL: + case Opcode.OP_EQUALVERIFY: + //case Opcode.OP_NOTEQUAL: // use Opcode.OP_NUMNOTEQUAL + { + // (x1 x2 - bool) + if (this.stack.length < 2) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + buf1 = this.stack[this.stack.length - 2]; + buf2 = this.stack[this.stack.length - 1]; + var fEqual = buf1.toString('hex') === buf2.toString('hex'); + this.stack.pop(); + this.stack.pop(); + this.stack.push(fEqual ? Interpreter.true : Interpreter.false); + if (opcodenum === Opcode.OP_EQUALVERIFY) { + if (fEqual) { + this.stack.pop(); + } else { + this.errstr = 'SCRIPT_ERR_EQUALVERIFY'; + return false; + } + } + } + break; - var r = bits % 26; - var s = Math.min((bits - r) / 26, this.length); - var mask = 0x3ffffff ^ ((0x3ffffff >>> r) << r); - var maskedWords = extended; - hint -= s; - hint = Math.max(0, hint); + // + // Numeric + // + case Opcode.OP_1ADD: + case Opcode.OP_1SUB: + case Opcode.OP_NEGATE: + case Opcode.OP_ABS: + case Opcode.OP_NOT: + case Opcode.OP_0NOTEQUAL: + { + // (in -- out) + if (this.stack.length < 1) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + buf = this.stack[this.stack.length - 1]; + bn = BN.fromScriptNumBuffer(buf, fRequireMinimal); + switch (opcodenum) { + case Opcode.OP_1ADD: + bn = bn.add(BN.One); + break; + case Opcode.OP_1SUB: + bn = bn.sub(BN.One); + break; + case Opcode.OP_NEGATE: + bn = bn.neg(); + break; + case Opcode.OP_ABS: + if (bn.cmp(BN.Zero) < 0) { + bn = bn.neg(); + } + break; + case Opcode.OP_NOT: + bn = new BN((bn.cmp(BN.Zero) === 0) + 0); + break; + case Opcode.OP_0NOTEQUAL: + bn = new BN((bn.cmp(BN.Zero) !== 0) + 0); + break; + //default: assert(!'invalid opcode'); break; // TODO: does this ever occur? + } + this.stack.pop(); + this.stack.push(bn.toScriptNumBuffer()); + } + break; - // Extended mode, copy masked part - if (maskedWords) { - for (var i = 0; i < s; i++) - maskedWords.words[i] = this.words[i]; - maskedWords.length = s; - } + case Opcode.OP_ADD: + case Opcode.OP_SUB: + case Opcode.OP_BOOLAND: + case Opcode.OP_BOOLOR: + case Opcode.OP_NUMEQUAL: + case Opcode.OP_NUMEQUALVERIFY: + case Opcode.OP_NUMNOTEQUAL: + case Opcode.OP_LESSTHAN: + case Opcode.OP_GREATERTHAN: + case Opcode.OP_LESSTHANOREQUAL: + case Opcode.OP_GREATERTHANOREQUAL: + case Opcode.OP_MIN: + case Opcode.OP_MAX: + { + // (x1 x2 -- out) + if (this.stack.length < 2) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + bn1 = BN.fromScriptNumBuffer(this.stack[this.stack.length - 2], fRequireMinimal); + bn2 = BN.fromScriptNumBuffer(this.stack[this.stack.length - 1], fRequireMinimal); + bn = new BN(0); - if (s === 0) { - // No-op, we should not move anything at all - } else if (this.length > s) { - this.length -= s; - for (var i = 0; i < this.length; i++) - this.words[i] = this.words[i + s]; - } else { - this.words[0] = 0; - this.length = 1; - } + switch (opcodenum) { + case Opcode.OP_ADD: + bn = bn1.add(bn2); + break; - var carry = 0; - for (var i = this.length - 1; i >= 0 && (carry !== 0 || i >= hint); i--) { - var word = this.words[i]; - this.words[i] = (carry << (26 - r)) | (word >>> r); - carry = word & mask; - } + case Opcode.OP_SUB: + bn = bn1.sub(bn2); + break; - // Push carried bits as a mask - if (maskedWords && carry !== 0) - maskedWords.words[maskedWords.length++] = carry; + // case Opcode.OP_BOOLAND: bn = (bn1 != bnZero && bn2 != bnZero); break; + case Opcode.OP_BOOLAND: + bn = new BN(((bn1.cmp(BN.Zero) !== 0) && (bn2.cmp(BN.Zero) !== 0)) + 0); + break; + // case Opcode.OP_BOOLOR: bn = (bn1 != bnZero || bn2 != bnZero); break; + case Opcode.OP_BOOLOR: + bn = new BN(((bn1.cmp(BN.Zero) !== 0) || (bn2.cmp(BN.Zero) !== 0)) + 0); + break; + // case Opcode.OP_NUMEQUAL: bn = (bn1 == bn2); break; + case Opcode.OP_NUMEQUAL: + bn = new BN((bn1.cmp(bn2) === 0) + 0); + break; + // case Opcode.OP_NUMEQUALVERIFY: bn = (bn1 == bn2); break; + case Opcode.OP_NUMEQUALVERIFY: + bn = new BN((bn1.cmp(bn2) === 0) + 0); + break; + // case Opcode.OP_NUMNOTEQUAL: bn = (bn1 != bn2); break; + case Opcode.OP_NUMNOTEQUAL: + bn = new BN((bn1.cmp(bn2) !== 0) + 0); + break; + // case Opcode.OP_LESSTHAN: bn = (bn1 < bn2); break; + case Opcode.OP_LESSTHAN: + bn = new BN((bn1.cmp(bn2) < 0) + 0); + break; + // case Opcode.OP_GREATERTHAN: bn = (bn1 > bn2); break; + case Opcode.OP_GREATERTHAN: + bn = new BN((bn1.cmp(bn2) > 0) + 0); + break; + // case Opcode.OP_LESSTHANOREQUAL: bn = (bn1 <= bn2); break; + case Opcode.OP_LESSTHANOREQUAL: + bn = new BN((bn1.cmp(bn2) <= 0) + 0); + break; + // case Opcode.OP_GREATERTHANOREQUAL: bn = (bn1 >= bn2); break; + case Opcode.OP_GREATERTHANOREQUAL: + bn = new BN((bn1.cmp(bn2) >= 0) + 0); + break; + case Opcode.OP_MIN: + bn = (bn1.cmp(bn2) < 0 ? bn1 : bn2); + break; + case Opcode.OP_MAX: + bn = (bn1.cmp(bn2) > 0 ? bn1 : bn2); + break; + // default: assert(!'invalid opcode'); break; //TODO: does this ever occur? + } + this.stack.pop(); + this.stack.pop(); + this.stack.push(bn.toScriptNumBuffer()); - if (this.length === 0) { - this.words[0] = 0; - this.length = 1; - } + if (opcodenum === Opcode.OP_NUMEQUALVERIFY) { + // if (CastToBool(stacktop(-1))) + if (Interpreter.castToBool(this.stack[this.stack.length - 1])) { + this.stack.pop(); + } else { + this.errstr = 'SCRIPT_ERR_NUMEQUALVERIFY'; + return false; + } + } + } + break; - this.strip(); - if (extended) - return { hi: this, lo: maskedWords }; - - return this; -}; + case Opcode.OP_WITHIN: + { + // (x min max -- out) + if (this.stack.length < 3) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + bn1 = BN.fromScriptNumBuffer(this.stack[this.stack.length - 3], fRequireMinimal); + bn2 = BN.fromScriptNumBuffer(this.stack[this.stack.length - 2], fRequireMinimal); + var bn3 = BN.fromScriptNumBuffer(this.stack[this.stack.length - 1], fRequireMinimal); + //bool fValue = (bn2 <= bn1 && bn1 < bn3); + fValue = (bn2.cmp(bn1) <= 0) && (bn1.cmp(bn3) < 0); + this.stack.pop(); + this.stack.pop(); + this.stack.pop(); + this.stack.push(fValue ? Interpreter.true : Interpreter.false); + } + break; -// Shift-left -BN.prototype.shln = function shln(bits) { - return this.clone().ishln(bits); -}; -// Shift-right -BN.prototype.shrn = function shrn(bits) { - return this.clone().ishrn(bits); -}; + // + // Crypto + // + case Opcode.OP_RIPEMD160: + case Opcode.OP_SHA1: + case Opcode.OP_SHA256: + case Opcode.OP_HASH160: + case Opcode.OP_HASH256: + { + // (in -- hash) + if (this.stack.length < 1) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + buf = this.stack[this.stack.length - 1]; + //valtype vchHash((opcode == Opcode.OP_RIPEMD160 || + // opcode == Opcode.OP_SHA1 || opcode == Opcode.OP_HASH160) ? 20 : 32); + var bufHash; + if (opcodenum === Opcode.OP_RIPEMD160) { + bufHash = Hash.ripemd160(buf); + } else if (opcodenum === Opcode.OP_SHA1) { + bufHash = Hash.sha1(buf); + } else if (opcodenum === Opcode.OP_SHA256) { + bufHash = Hash.sha256(buf); + } else if (opcodenum === Opcode.OP_HASH160) { + bufHash = Hash.sha256ripemd160(buf); + } else if (opcodenum === Opcode.OP_HASH256) { + bufHash = Hash.sha256sha256(buf); + } + this.stack.pop(); + this.stack.push(bufHash); + } + break; -// 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; + case Opcode.OP_CODESEPARATOR: + { + // Hash starts after the code separator + this.pbegincodehash = this.pc; + } + break; - // Fast case: bit is much higher than all existing words - if (this.length <= s) { - return false; - } + case Opcode.OP_CHECKSIG: + case Opcode.OP_CHECKSIGVERIFY: + { + // (sig pubkey -- bool) + if (this.stack.length < 2) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } - // Check bit and return - var w = this.words[s]; + bufSig = this.stack[this.stack.length - 2]; + bufPubkey = this.stack[this.stack.length - 1]; - return !!(w & q); -}; + // Subset of script starting at the most recent codeseparator + // CScript scriptCode(pbegincodehash, pend); + subscript = new Script().set({ + chunks: this.script.chunks.slice(this.pbegincodehash) + }); -// 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; + // Drop the signature, since there's no way for a signature to sign itself + var tmpScript = new Script().add(bufSig); + subscript.findAndDelete(tmpScript); - assert(!this.sign, 'imaskn works only with positive numbers'); + if (!this.checkSignatureEncoding(bufSig) || !this.checkPubkeyEncoding(bufPubkey)) { + return false; + } - if (r !== 0) - s++; - this.length = Math.min(s, this.length); + try { + sig = Signature.fromTxFormat(bufSig); + pubkey = PublicKey.fromBuffer(bufPubkey, false); + fSuccess = this.tx.verifySignature(sig, pubkey, this.nin, subscript); + } catch (e) { + //invalid sig or pubkey + fSuccess = false; + } - if (r !== 0) { - var mask = 0x3ffffff ^ ((0x3ffffff >>> r) << r); - this.words[this.length - 1] &= mask; - } + this.stack.pop(); + this.stack.pop(); + // stack.push_back(fSuccess ? vchTrue : vchFalse); + this.stack.push(fSuccess ? Interpreter.true : Interpreter.false); + if (opcodenum === Opcode.OP_CHECKSIGVERIFY) { + if (fSuccess) { + this.stack.pop(); + } else { + this.errstr = 'SCRIPT_ERR_CHECKSIGVERIFY'; + return false; + } + } + } + break; - return this.strip(); -}; + case Opcode.OP_CHECKMULTISIG: + case Opcode.OP_CHECKMULTISIGVERIFY: + { + // ([sig ...] num_of_signatures [pubkey ...] num_of_pubkeys -- bool) -// Return only lowers bits of number -BN.prototype.maskn = function maskn(bits) { - return this.clone().imaskn(bits); -}; + var i = 1; + if (this.stack.length < i) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } -// Add plain number `num` to `this` -BN.prototype.iaddn = function iaddn(num) { - assert(typeof num === 'number'); - if (num < 0) - return this.isubn(-num); + var nKeysCount = BN.fromScriptNumBuffer(this.stack[this.stack.length - i], fRequireMinimal).toNumber(); + if (nKeysCount < 0 || nKeysCount > 20) { + this.errstr = 'SCRIPT_ERR_PUBKEY_COUNT'; + return false; + } + this.nOpCount += nKeysCount; + if (this.nOpCount > 201) { + this.errstr = 'SCRIPT_ERR_OP_COUNT'; + return false; + } + // int ikey = ++i; + var ikey = ++i; + i += nKeysCount; + if (this.stack.length < i) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } - // Possible sign change - if (this.sign) { - if (this.length === 1 && this.words[0] < num) { - this.words[0] = num - this.words[0]; - this.sign = false; - return this; - } + var nSigsCount = BN.fromScriptNumBuffer(this.stack[this.stack.length - i], fRequireMinimal).toNumber(); + if (nSigsCount < 0 || nSigsCount > nKeysCount) { + this.errstr = 'SCRIPT_ERR_SIG_COUNT'; + return false; + } + // int isig = ++i; + var isig = ++i; + i += nSigsCount; + if (this.stack.length < i) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } - this.sign = false; - this.isubn(num); - this.sign = true; - return this; - } - this.words[0] += num; + // Subset of script starting at the most recent codeseparator + subscript = new Script().set({ + chunks: this.script.chunks.slice(this.pbegincodehash) + }); - // 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); + // Drop the signatures, since there's no way for a signature to sign itself + for (var k = 0; k < nSigsCount; k++) { + bufSig = this.stack[this.stack.length - isig - k]; + subscript.findAndDelete(new Script().add(bufSig)); + } - return this; -}; + fSuccess = true; + while (fSuccess && nSigsCount > 0) { + // valtype& vchSig = stacktop(-isig); + bufSig = this.stack[this.stack.length - isig]; + // valtype& vchPubKey = stacktop(-ikey); + bufPubkey = this.stack[this.stack.length - ikey]; -// Subtract plain number `num` from `this` -BN.prototype.isubn = function isubn(num) { - assert(typeof num === 'number'); - if (num < 0) - return this.iaddn(-num); + if (!this.checkSignatureEncoding(bufSig) || !this.checkPubkeyEncoding(bufPubkey)) { + return false; + } - if (this.sign) { - this.sign = false; - this.iaddn(num); - this.sign = true; - return this; - } + var fOk; + try { + sig = Signature.fromTxFormat(bufSig); + pubkey = PublicKey.fromBuffer(bufPubkey, false); + fOk = this.tx.verifySignature(sig, pubkey, this.nin, subscript); + } catch (e) { + //invalid sig or pubkey + fOk = false; + } - this.words[0] -= num; + if (fOk) { + isig++; + nSigsCount--; + } + ikey++; + nKeysCount--; - // Carry - for (var i = 0; i < this.length && this.words[i] < 0; i++) { - this.words[i] += 0x4000000; - this.words[i + 1] -= 1; - } + // If there are more signatures left than keys left, + // then too many signatures have failed + if (nSigsCount > nKeysCount) { + fSuccess = false; + } + } - return this.strip(); -}; + // Clean up stack of actual arguments + while (i-- > 1) { + this.stack.pop(); + } -BN.prototype.addn = function addn(num) { - return this.clone().iaddn(num); -}; + // A bug causes CHECKMULTISIG to consume one extra argument + // whose contents were not checked in any way. + // + // Unfortunately this is a potential source of mutability, + // so optionally verify it is exactly equal to zero prior + // to removing it from the stack. + if (this.stack.length < 1) { + this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; + return false; + } + if ((this.flags & Interpreter.SCRIPT_VERIFY_NULLDUMMY) && this.stack[this.stack.length - 1].length) { + this.errstr = 'SCRIPT_ERR_SIG_NULLDUMMY'; + return false; + } + this.stack.pop(); -BN.prototype.subn = function subn(num) { - return this.clone().isubn(num); -}; + this.stack.push(fSuccess ? Interpreter.true : Interpreter.false); -BN.prototype.iabs = function iabs() { - this.sign = false; + if (opcodenum === Opcode.OP_CHECKMULTISIGVERIFY) { + if (fSuccess) { + this.stack.pop(); + } else { + this.errstr = 'SCRIPT_ERR_CHECKMULTISIGVERIFY'; + return false; + } + } + } + break; - return this -}; + default: + this.errstr = 'SCRIPT_ERR_BAD_OPCODE'; + return false; + } + } -BN.prototype.abs = function abs() { - return this.clone().iabs(); + return true; }; -BN.prototype._wordDiv = function _wordDiv(num, mode) { - var shift = this.length - num.length; - var a = this.clone(); - var b = num; +}).call(this,require("buffer").Buffer) +},{"../crypto/bn":34,"../crypto/hash":36,"../crypto/signature":39,"../opcode":51,"../publickey":53,"../transaction":57,"./script":56,"buffer":209,"lodash":95}],56:[function(require,module,exports){ +(function (Buffer){ +'use strict'; - var q = mode !== 'mod' && new BN(0); - var sign = false; - // Approximate quotient at each step - while (a.length > b.length) { - // NOTE: a.length is always >= 2, because of the condition .div() - var hi = a.words[a.length - 1] * 0x4000000 + a.words[a.length - 2]; - var sq = (hi / b.words[b.length - 1]); - var sqhi = (sq / 0x4000000) | 0; - var sqlo = sq & 0x3ffffff; - sq = new BN(null); - sq.words = [ sqlo, sqhi ]; - sq.length = 2; +var Address = require('../address'); +var BufferReader = require('../encoding/bufferreader'); +var BufferWriter = require('../encoding/bufferwriter'); +var Hash = require('../crypto/hash'); +var Opcode = require('../opcode'); +var PublicKey = require('../publickey'); +var Signature = require('../crypto/signature'); +var Networks = require('../networks'); - // Collect quotient - var shift = (a.length - b.length - 1) * 26; - if (q) { - var t = sq.shln(shift); - if (a.sign) - q.isub(t); - else - q.iadd(t); - } +var $ = require('../util/preconditions'); +var _ = require('lodash'); +var errors = require('../errors'); +var buffer = require('buffer'); +var BufferUtil = require('../util/buffer'); +var JSUtil = require('../util/js'); - sq = sq.mul(b).ishln(shift); - if (a.sign) - a.iadd(sq) - else - a.isub(sq); +/** + * A bitcoin transaction script. Each transaction's inputs and outputs + * has a script that is evaluated to validate it's spending. + * + * See https://en.bitcoin.it/wiki/Script + * + * @constructor + * @param {Object|string|Buffer} [from] optional data to populate script + */ +var Script = function Script(from) { + if (!(this instanceof Script)) { + return new Script(from); } - // At this point a.length <= b.length - while (a.ucmp(b) >= 0) { - // NOTE: a.length is always >= 2, because of the condition above - var hi = a.words[a.length - 1]; - var sq = new BN((hi / b.words[b.length - 1]) | 0); - var shift = (a.length - b.length) * 26; - - if (q) { - var t = sq.shln(shift); - if (a.sign) - q.isub(t); - else - q.iadd(t); - } - - sq = sq.mul(b).ishln(shift); - if (a.sign) - a.iadd(sq); - else - a.isub(sq); - } + this.chunks = []; - if (a.sign) { - if (q) - q.isubn(1); - a.iadd(b); + if (BufferUtil.isBuffer(from)) { + return Script.fromBuffer(from); + } else if (from instanceof Address) { + return Script.fromAddress(from); + } else if (from instanceof Script) { + return Script.fromBuffer(from.toBuffer()); + } else if (typeof from === 'string') { + return Script.fromString(from); + } else if (typeof from !== 'undefined') { + this.set(from); } - return { div: q ? q : null, mod: a }; }; -BN.prototype.divmod = function divmod(num, mode) { - assert(num.cmpn(0) !== 0); - - if (this.sign && !num.sign) { - var res = this.neg().divmod(num, mode); - var div; - var mod; - if (mode !== 'mod') - div = res.div.neg(); - if (mode !== 'div') - mod = res.mod.cmpn(0) === 0 ? res.mod : num.sub(res.mod); - return { - div: div, - mod: mod - }; - } else if (!this.sign && num.sign) { - var res = this.divmod(num.neg(), mode); - var div; - if (mode !== 'mod') - div = res.div.neg(); - return { div: div, mod: res.mod }; - } else if (this.sign && num.sign) { - return this.neg().divmod(num.neg(), mode); - } +Script.prototype.set = function(obj) { + this.chunks = obj.chunks || this.chunks; + return this; +}; - // Both numbers are positive at this point +Script.fromBuffer = function(buffer) { + var script = new Script(); + script.chunks = []; - // Strip both numbers to approximate shift value - if (num.length > this.length || this.cmp(num) < 0) - return { div: new BN(0), mod: this }; + var br = new BufferReader(buffer); + while (!br.finished()) { + var opcodenum = br.readUInt8(); - // Very short reduction - if (num.length === 1) { - if (mode === 'div') - return { div: this.divn(num.words[0]), mod: null }; - else 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])) - }; + var len, buf; + if (opcodenum > 0 && opcodenum < Opcode.OP_PUSHDATA1) { + len = opcodenum; + script.chunks.push({ + buf: br.read(len), + len: len, + opcodenum: opcodenum + }); + } else if (opcodenum === Opcode.OP_PUSHDATA1) { + len = br.readUInt8(); + buf = br.read(len); + script.chunks.push({ + buf: buf, + len: len, + opcodenum: opcodenum + }); + } else if (opcodenum === Opcode.OP_PUSHDATA2) { + len = br.readUInt16LE(); + buf = br.read(len); + script.chunks.push({ + buf: buf, + len: len, + opcodenum: opcodenum + }); + } else if (opcodenum === Opcode.OP_PUSHDATA4) { + len = br.readUInt32LE(); + buf = br.read(len); + script.chunks.push({ + buf: buf, + len: len, + opcodenum: opcodenum + }); + } else { + script.chunks.push({ + opcodenum: opcodenum + }); + } } - return this._wordDiv(num, mode); -}; - -// Find `this` / `num` -BN.prototype.div = function div(num) { - return this.divmod(num, 'div').div; + return script; }; -// Find `this` % `num` -BN.prototype.mod = function mod(num) { - return this.divmod(num, 'mod').mod; -}; +Script.prototype.toBuffer = function() { + var bw = new BufferWriter(); -// Find Round(`this` / `num`) -BN.prototype.divRound = function divRound(num) { - var dm = this.divmod(num); - - // Fast case - exact division - if (dm.mod.cmpn(0) === 0) - return dm.div; - - var mod = dm.div.sign ? dm.mod.isub(num) : dm.mod; - - var half = num.shrn(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.sign ? 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]) % 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] + carry * 0x4000000; - this.words[i] = (w / num) | 0; - carry = w % num; + for (var i = 0; i < this.chunks.length; i++) { + var chunk = this.chunks[i]; + var opcodenum = chunk.opcodenum; + bw.writeUInt8(chunk.opcodenum); + if (chunk.buf) { + if (opcodenum < Opcode.OP_PUSHDATA1) { + bw.write(chunk.buf); + } else if (opcodenum === Opcode.OP_PUSHDATA1) { + bw.writeUInt8(chunk.len); + bw.write(chunk.buf); + } else if (opcodenum === Opcode.OP_PUSHDATA2) { + bw.writeUInt16LE(chunk.len); + bw.write(chunk.buf); + } else if (opcodenum === Opcode.OP_PUSHDATA4) { + bw.writeUInt32LE(chunk.len); + bw.write(chunk.buf); + } + } } - return this.strip(); -}; - -BN.prototype.divn = function divn(num) { - return this.clone().idivn(num); + return bw.concat(); }; -BN.prototype._egcd = function _egcd(x1, p) { - assert(!p.sign); - assert(p.cmpn(0) !== 0); - - var a = this; - var b = p.clone(); +Script.fromString = function(str) { + if (JSUtil.isHexa(str) || str.length === 0) { + return new Script(new buffer.Buffer(str, 'hex')); + } + var script = new Script(); + script.chunks = []; - if (a.sign) - a = a.mod(p); - else - a = a.clone(); + var tokens = str.split(' '); + var i = 0; + while (i < tokens.length) { + var token = tokens[i]; + var opcode = Opcode(token); + var opcodenum = opcode.toNumber(); - var x2 = new BN(0); - while (b.isEven()) - b.ishrn(1); - var delta = b.clone(); - while (a.cmpn(1) > 0 && b.cmpn(1) > 0) { - while (a.isEven()) { - a.ishrn(1); - if (x1.isEven()) - x1.ishrn(1); - else - x1.iadd(delta).ishrn(1); - } - while (b.isEven()) { - b.ishrn(1); - if (x2.isEven()) - x2.ishrn(1); - else - x2.iadd(delta).ishrn(1); - } - if (a.cmp(b) >= 0) { - a.isub(b); - x1.isub(x2); + if (_.isUndefined(opcodenum)) { + opcodenum = parseInt(token); + if (opcodenum > 0 && opcodenum < Opcode.OP_PUSHDATA1) { + script.chunks.push({ + buf: new Buffer(tokens[i + 1].slice(2), 'hex'), + len: opcodenum, + opcodenum: opcodenum + }); + i = i + 2; + } else { + throw new Error('Invalid script: ' + JSON.stringify(str)); + } + } else if (opcodenum === Opcode.OP_PUSHDATA1 || + opcodenum === Opcode.OP_PUSHDATA2 || + opcodenum === Opcode.OP_PUSHDATA4) { + if (tokens[i + 2].slice(0, 2) !== '0x') { + throw new Error('Pushdata data must start with 0x'); + } + script.chunks.push({ + buf: new Buffer(tokens[i + 2].slice(2), 'hex'), + len: parseInt(tokens[i + 1]), + opcodenum: opcodenum + }); + i = i + 3; } else { - b.isub(a); - x2.isub(x1); + script.chunks.push({ + opcodenum: opcodenum + }); + i = i + 1; } } - if (a.cmpn(1) === 0) - return x1; - else - return x2; + return script; }; -BN.prototype.gcd = function gcd(num) { - if (this.cmpn(0) === 0) - return num.clone(); - if (num.cmpn(0) === 0) - return this.clone(); +Script.prototype.toString = function() { + var str = ''; + for (var i = 0; i < this.chunks.length; i++) { + var chunk = this.chunks[i]; + var opcodenum = chunk.opcodenum; + if (!chunk.buf) { + if (typeof Opcode.reverseMap[opcodenum] !== 'undefined') { + str = str + ' ' + Opcode(opcodenum).toString(); + } else { + var numstr = opcodenum.toString(16); + if (numstr.length % 2 !== 0) { + numstr = '0' + numstr; + } + str = str + ' ' + '0x' + numstr; + } + } else { + if (opcodenum === Opcode.OP_PUSHDATA1 || + opcodenum === Opcode.OP_PUSHDATA2 || + opcodenum === Opcode.OP_PUSHDATA4) { + str = str + ' ' + Opcode(opcodenum).toString(); + } + str = str + ' ' + chunk.len; + if (chunk.len > 0) { + str = str + ' ' + '0x' + chunk.buf.toString('hex'); + } + } + } - var a = this.clone(); - var b = num.clone(); - a.sign = false; - b.sign = false; + return str.substr(1); +}; - // Remove common factor of two - for (var shift = 0; a.isEven() && b.isEven(); shift++) { - a.ishrn(1); - b.ishrn(1); - } +Script.prototype.toHex = function() { + return this.toBuffer().toString('hex'); +}; - while (a.isEven()) - a.ishrn(1); +Script.prototype.inspect = function() { + return ''; +}; - do { - while (b.isEven()) - b.ishrn(1); +// script classification methods - // Swap `a` and `b` to make `a` always bigger than `b` - if (a.cmp(b) < 0) { - var t = a; - a = b; - b = t; - } - a.isub(a.div(b).mul(b)); - } while (a.cmpn(0) !== 0 && b.cmpn(0) !== 0); - if (a.cmpn(0) === 0) - return b.ishln(shift); - else - return a.ishln(shift); +/** + * @returns {boolean} if this is a pay to pubkey hash output script + */ +Script.prototype.isPublicKeyHashOut = function() { + return !!(this.chunks.length === 5 && + this.chunks[0].opcodenum === Opcode.OP_DUP && + this.chunks[1].opcodenum === Opcode.OP_HASH160 && + this.chunks[2].buf && + this.chunks[3].opcodenum === Opcode.OP_EQUALVERIFY && + this.chunks[4].opcodenum === Opcode.OP_CHECKSIG); }; -// Invert number in the field F(num) -BN.prototype.invm = function invm(num) { - return this._egcd(new BN(1), num).mod(num); +/** + * @returns {boolean} if this is a pay to public key hash input script + */ +Script.prototype.isPublicKeyHashIn = function() { + return this.chunks.length === 2 && + this.chunks[0].buf && + this.chunks[0].buf.length >= 0x47 && + this.chunks[0].buf.length <= 0x49 && + PublicKey.isValid(this.chunks[1].buf); }; -BN.prototype.isEven = function isEven(num) { - return (this.words[0] & 1) === 0; +Script.prototype.getPublicKeyHash = function() { + $.checkState(this.isPublicKeyHashOut(), 'Can\'t retrieve PublicKeyHash from a non-PKH output'); + return this.chunks[2].buf; }; -BN.prototype.isOdd = function isOdd(num) { - return (this.words[0] & 1) === 1; +/** + * @returns {boolean} if this is a public key output script + */ +Script.prototype.isPublicKeyOut = function() { + return this.chunks.length === 2 && + BufferUtil.isBuffer(this.chunks[0].buf) && + PublicKey.isValid(this.chunks[0].buf) && + this.chunks[1].opcodenum === Opcode.OP_CHECKSIG; }; -// And first word and num -BN.prototype.andln = function andln(num) { - return this.words[0] & num; +/** + * @returns {boolean} if this is a pay to public key input script + */ +Script.prototype.isPublicKeyIn = function() { + return this.chunks.length === 1 && + BufferUtil.isBuffer(this.chunks[0].buf) && + this.chunks[0].buf.length === 0x47; }; -// 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) { - for (var i = this.length; i < s + 1; i++) - this.words[i] = 0; - this.words[s] |= q; - this.length = s + 1; - return this; - } +/** + * @returns {boolean} if this is a p2sh output script + */ +Script.prototype.isScriptHashOut = function() { + var buf = this.toBuffer(); + return (buf.length === 23 && + buf[0] === Opcode.OP_HASH160 && + buf[1] === 0x14 && + buf[buf.length - 1] === Opcode.OP_EQUAL); +}; - // Add bit and propagate, if needed - var carry = q; - for (var i = s; carry !== 0 && i < this.length; i++) { - var w = this.words[i]; - w += carry; - carry = w >>> 26; - w &= 0x3ffffff; - this.words[i] = w; +/** + * @returns {boolean} if this is a p2sh input script + * Note that these are frequently indistinguishable from pubkeyhashin + */ +Script.prototype.isScriptHashIn = function() { + if (this.chunks.length === 0) { + return false; } - if (carry !== 0) { - this.words[i] = carry; - this.length++; + var chunk = this.chunks[this.chunks.length - 1]; + if (!chunk) { + return false; } - return this; + var scriptBuf = chunk.buf; + if (!scriptBuf) { + return false; + } + var redeemScript = new Script(scriptBuf); + var type = redeemScript.classify(); + return type !== Script.types.UNKNOWN; }; -BN.prototype.cmpn = function cmpn(num) { - var sign = num < 0; - if (sign) - num = -num; - - if (this.sign && !sign) - return -1; - else if (!this.sign && sign) - return 1; - - num &= 0x3ffffff; - this.strip(); - - var res; - if (this.length > 1) { - res = 1; - } else { - var w = this.words[0]; - res = w === num ? 0 : w < num ? -1 : 1; - } - if (this.sign) - res = -res; - return res; +/** + * @returns {boolean} if this is a mutlsig output script + */ +Script.prototype.isMultisigOut = function() { + return (this.chunks.length > 3 && + Opcode.isSmallIntOp(this.chunks[0].opcodenum) && + this.chunks.slice(1, this.chunks.length - 2).every(function(obj) { + return obj.buf && BufferUtil.isBuffer(obj.buf); + }) && + Opcode.isSmallIntOp(this.chunks[this.chunks.length - 2].opcodenum) && + this.chunks[this.chunks.length - 1].opcodenum === Opcode.OP_CHECKMULTISIG); }; -// 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.sign && !num.sign) - return -1; - else if (!this.sign && num.sign) - return 1; - var res = this.ucmp(num); - if (this.sign) - return -res; - else - return res; +/** + * @returns {boolean} if this is a multisig input script + */ +Script.prototype.isMultisigIn = function() { + return this.chunks.length >= 2 && + this.chunks[0].opcodenum === 0 && + this.chunks.slice(1, this.chunks.length).every(function(obj) { + return obj.buf && + BufferUtil.isBuffer(obj.buf) && + obj.buf.length === 0x47; + }); }; -// Unsigned comparison -BN.prototype.ucmp = function ucmp(num) { - // At this point both numbers have the same sign - if (this.length > num.length) - return 1; - else if (this.length < num.length) - return -1; - - var res = 0; - for (var i = this.length - 1; i >= 0; i--) { - var a = this.words[i]; - var b = num.words[i]; +/** + * @returns {boolean} true if this is a valid standard OP_RETURN output + */ +Script.prototype.isDataOut = function() { + return this.chunks.length >= 1 && + this.chunks[0].opcodenum === Opcode.OP_RETURN && + (this.chunks.length === 1 || + (this.chunks.length === 2 && + this.chunks[1].buf && + this.chunks[1].buf.length <= Script.OP_RETURN_STANDARD_SIZE && + this.chunks[1].length === this.chunks.len)); +}; - if (a === b) - continue; - if (a < b) - res = -1; - else if (a > b) - res = 1; - break; +/** + * Retrieve the associated data for this script. + * In the case of a pay to public key hash or P2SH, return the hash. + * In the case of a standard OP_RETURN, return the data + * @returns {Buffer} + */ +Script.prototype.getData = function() { + if (this.isDataOut() || this.isScriptHashOut()) { + return new Buffer(this.chunks[1].buf); } - return res; + if (this.isPublicKeyHashOut()) { + return new Buffer(this.chunks[2].buf); + } + throw new Error('Unrecognized script type to get data from'); }; -// -// A reduce context, could be using montgomery or something better, depending -// on the `m` itself. -// -BN.red = function red(num) { - return new Red(num); +/** + * @returns {boolean} if the script is only composed of data pushing + * opcodes or small int opcodes (OP_0, OP_1, ..., OP_16) + */ +Script.prototype.isPushOnly = function() { + return _.every(this.chunks, function(chunk) { + return chunk.opcodenum <= Opcode.OP_16; + }); }; -BN.prototype.toRed = function toRed(ctx) { - assert(!this.red, 'Already a number in reduction context'); - assert(!this.sign, '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); -}; +Script.types = {}; +Script.types.UNKNOWN = 'Unknown'; +Script.types.PUBKEY_OUT = 'Pay to public key'; +Script.types.PUBKEY_IN = 'Spend from public key'; +Script.types.PUBKEYHASH_OUT = 'Pay to public key hash'; +Script.types.PUBKEYHASH_IN = 'Spend from public key hash'; +Script.types.SCRIPTHASH_OUT = 'Pay to script hash'; +Script.types.SCRIPTHASH_IN = 'Spend from script hash'; +Script.types.MULTISIG_OUT = 'Pay to multisig'; +Script.types.MULTISIG_IN = 'Spend from multisig'; +Script.types.DATA_OUT = 'Data push'; -BN.prototype._forceRed = function _forceRed(ctx) { - this.red = ctx; - return this; -}; +Script.OP_RETURN_STANDARD_SIZE = 80; -BN.prototype.forceRed = function forceRed(ctx) { - assert(!this.red, 'Already a number in reduction context'); - return this._forceRed(ctx); -}; +Script.identifiers = {}; +Script.identifiers.PUBKEY_OUT = Script.prototype.isPublicKeyOut; +Script.identifiers.PUBKEY_IN = Script.prototype.isPublicKeyIn; +Script.identifiers.PUBKEYHASH_OUT = Script.prototype.isPublicKeyHashOut; +Script.identifiers.PUBKEYHASH_IN = Script.prototype.isPublicKeyHashIn; +Script.identifiers.MULTISIG_OUT = Script.prototype.isMultisigOut; +Script.identifiers.MULTISIG_IN = Script.prototype.isMultisigIn; +Script.identifiers.SCRIPTHASH_OUT = Script.prototype.isScriptHashOut; +Script.identifiers.SCRIPTHASH_IN = Script.prototype.isScriptHashIn; +Script.identifiers.DATA_OUT = Script.prototype.isDataOut; -BN.prototype.redAdd = function redAdd(num) { - assert(this.red, 'redAdd works only with red numbers'); - return this.red.add(this, num); +/** + * @returns {object} The Script type if it is a known form, + * or Script.UNKNOWN if it isn't + */ +Script.prototype.classify = function() { + for (var type in Script.identifiers) { + if (Script.identifiers[type].bind(this)()) { + return Script.types[type]; + } + } + return Script.types.UNKNOWN; }; -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); +/** + * @returns {boolean} if script is one of the known types + */ +Script.prototype.isStandard = function() { + // TODO: Add BIP62 compliance + return this.classify() !== Script.types.UNKNOWN; }; -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); +// Script construction methods + +/** + * Adds a script element at the start of the script. + * @param {*} obj a string, number, Opcode, Bufer, or object to add + * @returns {Script} this script instance + */ +Script.prototype.prepend = function(obj) { + this._addByType(obj, true); + return this; }; -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); +/** + * Compares a script with another script + */ +Script.prototype.equals = function(script) { + $.checkState(script instanceof Script, 'Must provide another script'); + if (this.chunks.length !== script.chunks.length) { + return false; + } + var i; + for (i = 0; i < this.chunks.length; i++) { + if (BufferUtil.isBuffer(this.chunks[i]) && !BufferUtil.isBuffer(script.chunks[i])) { + return false; + } else if (this.chunks[i] instanceof Opcode && !(script.chunks[i] instanceof Opcode)) { + return false; + } + if (BufferUtil.isBuffer(this.chunks[i]) && !BufferUtil.equals(this.chunks[i], script.chunks[i])) { + return false; + } else if (this.chunks[i].num !== script.chunks[i].num) { + return false; + } + } + return true; }; -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); +/** + * Adds a script element to the end of the script. + * + * @param {*} obj a string, number, Opcode, Bufer, or object to add + * @returns {Script} this script instance + * + */ +Script.prototype.add = function(obj) { + this._addByType(obj, false); + return this; }; -BN.prototype.redSqr = function redSqr() { - assert(this.red, 'redSqr works only with red numbers'); - this.red._verify1(this); - return this.red.sqr(this); +Script.prototype._addByType = function(obj, prepend) { + if (typeof obj === 'string') { + this._addOpcode(obj, prepend); + } else if (typeof obj === 'number') { + this._addOpcode(obj, prepend); + } else if (obj instanceof Opcode) { + this._addOpcode(obj, prepend); + } else if (BufferUtil.isBuffer(obj)) { + this._addBuffer(obj, prepend); + } else if (typeof obj === 'object') { + this._insertAtPosition(obj, prepend); + } else if (obj instanceof Script) { + this.chunks = this.chunks.concat(obj.chunks); + } else { + throw new Error('Invalid script chunk'); + } }; -BN.prototype.redISqr = function redISqr() { - assert(this.red, 'redISqr works only with red numbers'); - this.red._verify1(this); - return this.red.isqr(this); +Script.prototype._insertAtPosition = function(op, prepend) { + if (prepend) { + this.chunks.unshift(op); + } else { + this.chunks.push(op); + } }; -// 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); +Script.prototype._addOpcode = function(opcode, prepend) { + var op; + if (typeof opcode === 'number') { + op = opcode; + } else if (opcode instanceof Opcode) { + op = opcode.toNumber(); + } else { + op = Opcode(opcode).toNumber(); + } + this._insertAtPosition({ + opcodenum: op + }, prepend); + return this; }; -BN.prototype.redInvm = function redInvm() { - assert(this.red, 'redInvm works only with red numbers'); - this.red._verify1(this); - return this.red.invm(this); +Script.prototype._addBuffer = function(buf, prepend) { + var opcodenum; + var len = buf.length; + if (len >= 0 && len < Opcode.OP_PUSHDATA1) { + opcodenum = len; + } else if (len < Math.pow(2, 8)) { + opcodenum = Opcode.OP_PUSHDATA1; + } else if (len < Math.pow(2, 16)) { + opcodenum = Opcode.OP_PUSHDATA2; + } else if (len < Math.pow(2, 32)) { + opcodenum = Opcode.OP_PUSHDATA4; + } else { + throw new Error('You can\'t push that much data'); + } + this._insertAtPosition({ + buf: buf, + len: len, + opcodenum: opcodenum + }, prepend); + return 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); +Script.prototype.removeCodeseparators = function() { + var chunks = []; + for (var i = 0; i < this.chunks.length; i++) { + if (this.chunks[i].opcodenum !== Opcode.OP_CODESEPARATOR) { + chunks.push(this.chunks[i]); + } + } + this.chunks = chunks; + return this; }; -BN.prototype.redPow = function redPow(num) { - assert(this.red && !num.red, 'redPow(normalNum)'); - this.red._verify1(this); - return this.red.pow(this, num); -}; +// high level script builder methods -// Prime numbers with efficient reduction -var primes = { - k256: null, - p224: null, - p192: null, - p25519: null +/** + * @returns {Script} a new Multisig output script for given public keys, + * requiring m of those public keys to spend + * @param {PublicKey[]} publicKeys - list of all public keys controlling the output + * @param {number} threshold - amount of required signatures to spend the output + * @param {Object} [opts] - Several options: + * - noSorting: defaults to false, if true, don't sort the given + * public keys before creating the script + */ +Script.buildMultisigOut = function(publicKeys, threshold, opts) { + $.checkArgument(threshold <= publicKeys.length, + 'Number of required signatures must be less than or equal to the number of public keys'); + opts = opts || {}; + var script = new Script(); + script.add(Opcode.smallInt(threshold)); + publicKeys = _.map(publicKeys, PublicKey); + var sorted = publicKeys; + if (!opts.noSorting) { + sorted = _.sortBy(publicKeys, function(publicKey) { + return publicKey.toString('hex'); + }); + } + for (var i = 0; i < sorted.length; i++) { + var publicKey = sorted[i]; + script.add(publicKey.toBuffer()); + } + script.add(Opcode.smallInt(publicKeys.length)); + script.add(Opcode.OP_CHECKMULTISIG); + return script; }; -// 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).ishln(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; +/** + * A new P2SH Multisig input script for the given public keys, requiring m of those public keys to spend + * + * @param {PublicKey[]} pubkeys list of all public keys controlling the output + * @param {number} threshold amount of required signatures to spend the output + * @param {Array} signatures signatures to append to the script + * @param {Object=} opts + * @param {boolean=} opts.noSorting don't sort the given public keys before creating the script (false by default) + * @param {Script=} opts.cachedMultisig don't recalculate the redeemScript + * + * @returns {Script} + */ +Script.buildP2SHMultisigIn = function(pubkeys, threshold, signatures, opts) { + $.checkArgument(_.isArray(pubkeys)); + $.checkArgument(_.isNumber(threshold)); + $.checkArgument(_.isArray(signatures)); + opts = opts || {}; + var s = new Script(); + s.add(Opcode.OP_0); + _.each(signatures, function(signature) { + s.add(signature); + }); + s.add((opts.cachedMultisig || Script.buildMultisigOut(pubkeys, threshold, opts)).toBuffer()); + return s; }; -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 { - var pair = r.ishrn(this.n, 0, this.tmp); - r = this.imulK(pair.hi); - r = r.iadd(pair.lo); - rlen = r.bitLength(); - } while (rlen > this.n); - - var cmp = rlen < this.n ? -1 : r.cmp(this.p); - if (cmp === 0) { - r.words[0] = 0; - r.length = 1; - } else if (cmp > 0) { - r.isub(this.p); - } else { - r.strip(); +/** + * @returns {Script} a new pay to public key hash output for the given + * address or public key + * @param {(Address|PublicKey)} to - destination address or public key + */ +Script.buildPublicKeyHashOut = function(to) { + $.checkArgument(!_.isUndefined(to)); + $.checkArgument(to instanceof PublicKey || to instanceof Address || _.isString(to)); + if (to instanceof PublicKey) { + to = to.toAddress(); + } else if (_.isString(to)) { + to = new Address(to); } - - return r; + var s = new Script(); + s.add(Opcode.OP_DUP) + .add(Opcode.OP_HASH160) + .add(to.hashBuffer) + .add(Opcode.OP_EQUALVERIFY) + .add(Opcode.OP_CHECKSIG); + s._network = to.network; + return s; }; -MPrime.prototype.imulK = function imulK(num) { - return num.imul(this.k); +/** + * @returns {Script} a new pay to public key output for the given + * public key + */ +Script.buildPublicKeyOut = function(pubkey) { + $.checkArgument(pubkey instanceof PublicKey); + var s = new Script(); + s.add(pubkey.toBuffer()) + .add(Opcode.OP_CHECKSIG); + return s; }; -function K256() { - MPrime.call( - this, - 'k256', - 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f'); -} -inherits(K256, MPrime); - -K256.prototype.imulK = function imulK(num) { - // K = 0x1000003d1 = [ 0x40, 0x3d1 ] - num.words[num.length] = 0; - num.words[num.length + 1] = 0; - num.length += 2; - - var uhi = 0; - var hi = 0; - var lo = 0; - for (var i = 0; i < num.length; i++) { - var w = num.words[i]; - hi += w * 0x40; - lo += w * 0x3d1; - hi += (lo / 0x4000000) | 0; - uhi += (hi / 0x4000000) | 0; - hi &= 0x3ffffff; - lo &= 0x3ffffff; - - num.words[i] = lo; - - lo = hi; - hi = uhi; - uhi = 0; +/** + * @returns {Script} a new OP_RETURN script with data + * @param {(string|Buffer)} to - the data to embed in the output + */ +Script.buildDataOut = function(data) { + $.checkArgument(_.isUndefined(data) || _.isString(data) || BufferUtil.isBuffer(data)); + if (typeof data === 'string') { + data = new Buffer(data); } - - // 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] * 0x13 + carry; - var lo = hi & 0x3ffffff; - hi >>>= 26; - - num.words[i] = lo; - carry = hi; + var s = new Script(); + s.add(Opcode.OP_RETURN); + if (!_.isUndefined(data)) { + s.add(data); } - if (carry !== 0) - num.words[num.length++] = carry; - return num; + return s; }; -// 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; +/** + * @param {Script|Address} script - the redeemScript for the new p2sh output. + * It can also be a p2sh address + * @returns {Script} new pay to script hash script for given script + */ +Script.buildScriptHashOut = function(script) { + $.checkArgument(script instanceof Script || + (script instanceof Address && script.isPayToScriptHash())); + var s = new Script(); + s.add(Opcode.OP_HASH160) + .add(script instanceof Address ? script.hashBuffer : Hash.sha256ripemd160(script.toBuffer())) + .add(Opcode.OP_EQUAL); - return prime; -} + s._network = script._network || script.network; + return s; +}; -// -// Base reduction engine -// -function Red(m) { - if (typeof m === 'string') { - var prime = BN._prime(m); - this.m = prime.p; - this.prime = prime; - } else { - this.m = m; - this.prime = null; +/** + * Builds a scriptSig (a script for an input) that signs a public key hash + * output script. + * + * @param {Buffer|string|PublicKey} publicKey + * @param {Signature|Buffer} signature - a Signature object, or the signature in DER cannonical encoding + * @param {number=} sigtype - the type of the signature (defaults to SIGHASH_ALL) + */ +Script.buildPublicKeyHashIn = function(publicKey, signature, sigtype) { + $.checkArgument(signature instanceof Signature || BufferUtil.isBuffer(signature)); + $.checkArgument(_.isUndefined(sigtype) || _.isNumber(sigtype)); + if (signature instanceof Signature) { + signature = signature.toBuffer(); } -} - -Red.prototype._verify1 = function _verify1(a) { - assert(!a.sign, 'red works only with positives'); - assert(a.red, 'red works only with red numbers'); + var script = new Script() + .add(BufferUtil.concat([ + signature, + BufferUtil.integerAsSingleByteBuffer(sigtype || Signature.SIGHASH_ALL) + ])) + .add(new PublicKey(publicKey).toBuffer()); + return script; }; -Red.prototype._verify2 = function _verify2(a, b) { - assert(!a.sign && !b.sign, 'red works only with positives'); - assert(a.red && a.red === b.red, - 'red works only with red numbers'); +/** + * @returns {Script} an empty script + */ +Script.empty = function() { + return new Script(); }; -Red.prototype.imod = function imod(a) { - if (this.prime) - return this.prime.ireduce(a)._forceRed(this); - return a.mod(this.m)._forceRed(this); +/** + * @returns {Script} a new pay to script hash script that pays to this script + */ +Script.prototype.toScriptHashOut = function() { + return Script.buildScriptHashOut(this); }; -Red.prototype.neg = function neg(a) { - var r = a.clone(); - r.sign = !r.sign; - return r.iadd(this.m)._forceRed(this); +/** + * @return {Script} a script built from the address + */ +Script.fromAddress = function(address) { + address = Address(address); + if (address.isPayToScriptHash()) { + return Script.buildScriptHashOut(address); + } else if (address.isPayToPublicKeyHash()) { + return Script.buildPublicKeyHashOut(address); + } + throw new errors.Script.UnrecognizedAddress(address); }; -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); +/** + * @param {Network} [network] + * @return {Address} the associated address for this script + */ +Script.prototype.toAddress = function(network) { + network = Networks.get(network) || this._network || Networks.defaultNetwork; + if (this.isPublicKeyHashOut() || this.isScriptHashOut()) { + return new Address(this, network); + } + throw new Error('The script type needs to be PayToPublicKeyHash or PayToScriptHash'); }; -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; +/** + * @return {Script} + */ +Script.prototype.toScriptHashOut = function() { + return Script.buildScriptHashOut(this); }; -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); +/** + * Analagous to bitcoind's FindAndDelete. Find and delete equivalent chunks, + * typically used with push data chunks. Note that this will find and delete + * not just the same data, but the same data with the same push data op as + * produced by default. i.e., if a pushdata in a tx does not use the minimal + * pushdata op, then when you try to remove the data it is pushing, it will not + * be removed, because they do not use the same pushdata op. + */ +Script.prototype.findAndDelete = function(script) { + var buf = script.toBuffer(); + var hex = buf.toString('hex'); + for (var i = 0; i < this.chunks.length; i++) { + var script2 = Script({ + chunks: [this.chunks[i]] + }); + var buf2 = script2.toBuffer(); + var hex2 = buf2.toString('hex'); + if (hex === hex2) { + this.chunks.splice(i, 1); + } + } + return 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; +/** + * Comes from bitcoind's script interpreter CheckMinimalPush function + * @returns {boolean} if the chunk {i} is the smallest way to push that particular data. + */ +Script.prototype.checkMinimalPush = function(i) { + var chunk = this.chunks[i]; + var buf = chunk.buf; + var opcodenum = chunk.opcodenum; + if (!buf) { + return true; + } + if (buf.length === 0) { + // Could have used OP_0. + return opcodenum === Opcode.OP_0; + } else if (buf.length === 1 && buf[0] >= 1 && buf[0] <= 16) { + // Could have used OP_1 .. OP_16. + return opcodenum === Opcode.OP_1 + (buf[0] - 1); + } else if (buf.length === 1 && buf[0] === 0x81) { + // Could have used OP_1NEGATE + return opcodenum === Opcode.OP_1NEGATE; + } else if (buf.length <= 75) { + // Could have used a direct push (opcode indicating number of bytes pushed + those bytes). + return opcodenum === buf.length; + } else if (buf.length <= 255) { + // Could have used OP_PUSHDATA. + return opcodenum === Opcode.OP_PUSHDATA1; + } else if (buf.length <= 65535) { + // Could have used OP_PUSHDATA2. + return opcodenum === Opcode.OP_PUSHDATA2; + } + return true; }; -Red.prototype.shl = function shl(a, num) { - this._verify1(a); - return this.imod(a.shln(num)); -}; +module.exports = Script; -Red.prototype.imul = function imul(a, b) { - this._verify2(a, b); - return this.imod(a.imul(b)); -}; +}).call(this,require("buffer").Buffer) +},{"../address":31,"../crypto/hash":36,"../crypto/signature":39,"../encoding/bufferreader":42,"../encoding/bufferwriter":43,"../errors":45,"../networks":50,"../opcode":51,"../publickey":53,"../util/buffer":69,"../util/js":70,"../util/preconditions":71,"buffer":209,"lodash":95}],57:[function(require,module,exports){ +module.exports = require('./transaction'); -Red.prototype.mul = function mul(a, b) { - this._verify2(a, b); - return this.imod(a.mul(b)); -}; +module.exports.Input = require('./input'); +module.exports.Output = require('./output'); +module.exports.UnspentOutput = require('./unspentoutput'); +module.exports.Signature = require('./signature'); -Red.prototype.isqr = function isqr(a) { - return this.imul(a, a); -}; +},{"./input":58,"./output":62,"./signature":64,"./transaction":65,"./unspentoutput":66}],58:[function(require,module,exports){ +module.exports = require('./input'); -Red.prototype.sqr = function sqr(a) { - return this.mul(a, a); -}; +module.exports.PublicKeyHash = require('./publickeyhash'); +module.exports.MultiSigScriptHash = require('./multisigscripthash.js'); -Red.prototype.sqrt = function sqrt(a) { - if (a.cmpn(0) === 0) - return a.clone(); +},{"./input":59,"./multisigscripthash.js":60,"./publickeyhash":61}],59:[function(require,module,exports){ +'use strict'; - var mod3 = this.m.andln(3); - assert(mod3 % 2 === 1); +var _ = require('lodash'); +var errors = require('../../errors'); +var BufferWriter = require('../../encoding/bufferwriter'); +var buffer = require('buffer'); +var BufferUtil = require('../../util/buffer'); +var JSUtil = require('../../util/js'); +var Script = require('../../script'); +var Sighash = require('../sighash'); +var Output = require('../output'); - // Fast case - if (mod3 === 3) { - var pow = this.m.add(new BN(1)).ishrn(2); - var r = this.pow(a, pow); - return r; +function Input(params) { + if (!(this instanceof Input)) { + return new Input(params); + } + if (params) { + return this._fromObject(params); } +} - // 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.cmpn(0) !== 0 && q.andln(1) === 0) { - s++; - q.ishrn(1); +Object.defineProperty(Input.prototype, 'script', { + configurable: false, + writeable: false, + enumerable: true, + get: function() { + if (!this._script) { + this._script = new Script(this._scriptBuffer); + } + return this._script; } - assert(q.cmpn(0) !== 0); +}); - var one = new BN(1).toRed(this); - var nOne = one.redNeg(); +Input.prototype._fromObject = function(params) { + if (_.isString(params.prevTxId) && JSUtil.isHexa(params.prevTxId)) { + params.prevTxId = new buffer.Buffer(params.prevTxId, 'hex'); + } + this.output = params.output ? + (params.output instanceof Output ? params.output : new Output(params.output)) : undefined; + this.prevTxId = params.prevTxId; + this.outputIndex = params.outputIndex; + this.sequenceNumber = params.sequenceNumber; + if (_.isUndefined(params.script) && _.isUndefined(params.scriptBuffer)) { + throw new errors.Transaction.Input.MissingScript(); + } + this.setScript(params.scriptBuffer || params.script); + return this; +}; - // Find quadratic non-residue - // NOTE: Max is such because of generalized Riemann hypothesis. - var lpow = this.m.subn(1).ishrn(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); +Input.prototype.toObject = function toObject() { + return { + prevTxId: this.prevTxId.toString('hex'), + outputIndex: this.outputIndex, + sequenceNumber: this.sequenceNumber, + script: this.script.toString(), + output: this.output ? this.output.toObject() : undefined + }; +}; - var c = this.pow(z, q); - var r = this.pow(a, q.addn(1).ishrn(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).ishln(m - i - 1)); +Input.prototype.toJSON = function toJSON() { + return JSON.stringify(this.toObject()); +}; - r = r.redMul(b); - c = b.redSqr(); - t = t.redMul(c); - m = i; +Input.fromJSON = function(json) { + if (JSUtil.isValidJSON(json)) { + json = JSON.parse(json); } + return new Input({ + output: json.output ? new Output(json.output) : undefined, + prevTxId: json.prevTxId || json.txidbuf, + outputIndex: _.isUndefined(json.outputIndex) ? json.txoutnum : json.outputIndex, + sequenceNumber: json.sequenceNumber || json.seqnum, + scriptBuffer: new Script(json.script, 'hex') + }); +}; - return r; +Input.fromBufferReader = function(br) { + var input = new Input(); + input.prevTxId = br.readReverse(32); + input.outputIndex = br.readUInt32LE(); + input._scriptBuffer = br.readVarLengthBuffer(); + input.sequenceNumber = br.readUInt32LE(); + return input; }; -Red.prototype.invm = function invm(a) { - var inv = a._egcd(new BN(1), this.m); - if (inv.sign) { - inv.sign = false; - return this.imod(inv).redNeg(); - } else { - return this.imod(inv); +Input.prototype.toBufferWriter = function(writer) { + if (!writer) { + writer = new BufferWriter(); } + writer.writeReverse(this.prevTxId); + writer.writeUInt32LE(this.outputIndex); + var script = this._scriptBuffer; + writer.writeVarintNum(script.length); + writer.write(script); + writer.writeUInt32LE(this.sequenceNumber); + return writer; }; -Red.prototype.pow = function pow(a, num) { - var w = []; - var q = num.clone(); - while (q.cmpn(0) !== 0) { - w.push(q.andln(1)); - q.ishrn(1); +Input.prototype.setScript = function(script) { + if (script instanceof Script) { + this._script = script; + this._scriptBuffer = script.toBuffer(); + } else if (_.isString(script)) { + this._script = new Script(script); + this._scriptBuffer = this._script.toBuffer(); + } else if (BufferUtil.isBuffer(script)) { + this._script = null; + this._scriptBuffer = new buffer.Buffer(script); + } else { + throw new TypeError('Invalid Argument'); } + return this; +}; - // Skip leading zeroes - var res = a; - for (var i = 0; i < w.length; i++, res = this.sqr(res)) - if (w[i] !== 0) - break; +/** + * Retrieve signatures for the provided PrivateKey. + * + * @param {Transaction} transaction - the transaction to be signed + * @param {PrivateKey} privateKey - the private key to use when signing + * @param {number} inputIndex - the index of this input in the provided transaction + * @param {number} sigType - defaults to Signature.SIGHASH_ALL + * @param {Buffer} addressHash - if provided, don't calculate the hash of the + * public key associated with the private key provided + * @abstract + */ +Input.prototype.getSignatures = function() { + throw new errors.AbstractMethodInvoked( + 'Trying to sign unsupported output type (only P2PKH and P2SH multisig inputs are supported)' + + ' for input: ' + this.toJSON() + ); +}; - if (++i < w.length) { - for (var q = this.sqr(res); i < w.length; i++, q = this.sqr(q)) { - if (w[i] === 0) - continue; - res = this.mul(res, q); - } - } +Input.prototype.isFullySigned = function() { + throw new errors.AbstractMethodInvoked('Input#isFullySigned'); +}; - return res; +Input.prototype.addSignature = function() { + throw new errors.AbstractMethodInvoked('Input#addSignature'); }; -Red.prototype.convertTo = function convertTo(num) { - return num.clone(); +Input.prototype.clearSignatures = function() { + throw new errors.AbstractMethodInvoked('Input#clearSignatures'); }; -Red.prototype.convertFrom = function convertFrom(num) { - var res = num.clone(); - res.red = null; - return res; +Input.prototype.isValidSignature = function(transaction, signature) { + // FIXME: Refactor signature so this is not necessary + signature.signature.nhashtype = signature.sigtype; + return Sighash.verify( + transaction, + signature.signature, + signature.publicKey, + signature.inputIndex, + this.output.script + ); }; -// -// Montgomery method engine -// +/** + * @returns true if this is a coinbase input (represents no input) + */ +Input.prototype.isNull = function() { + return this.prevTxId.toString('hex') === '0000000000000000000000000000000000000000000000000000000000000000' && + this.outputIndex === 0xffffffff; +}; -BN.mont = function mont(num) { - return new Mont(num); +Input.prototype._estimateSize = function() { + var bufferWriter = new BufferWriter(); + this.toBufferWriter(bufferWriter); + return bufferWriter.toBuffer().length; }; -function Mont(m) { - Red.call(this, m); +module.exports = Input; - this.shift = this.m.bitLength(); - if (this.shift % 26 !== 0) - this.shift += 26 - (this.shift % 26); - this.r = new BN(1).ishln(this.shift); - this.r2 = this.imod(this.r.sqr()); - this.rinv = this.r.invm(this.m); +},{"../../encoding/bufferwriter":43,"../../errors":45,"../../script":54,"../../util/buffer":69,"../../util/js":70,"../output":62,"../sighash":63,"buffer":209,"lodash":95}],60:[function(require,module,exports){ +'use strict'; - // TODO(indutny): simplify it - this.minv = this.rinv.mul(this.r) - .sub(new BN(1)) - .div(this.m) - .neg() - .mod(this.r); +var _ = require('lodash'); +var inherits = require('inherits'); +var Input = require('./input'); +var Output = require('../output'); +var $ = require('../../util/preconditions'); + +var Script = require('../../script'); +var Signature = require('../../crypto/signature'); +var Sighash = require('../sighash'); +var PublicKey = require('../../publickey'); +var BufferUtil = require('../../util/buffer'); +var TransactionSignature = require('../signature'); + +/** + * @constructor + */ +function MultiSigScriptHashInput(input, pubkeys, threshold, signatures) { + Input.apply(this, arguments); + var self = this; + pubkeys = pubkeys || input.publicKeys; + threshold = threshold || input.threshold; + signatures = signatures || input.signatures; + this.publicKeys = _.sortBy(pubkeys, function(publicKey) { return publicKey.toString('hex'); }); + this.redeemScript = Script.buildMultisigOut(this.publicKeys, threshold); + $.checkState(Script.buildScriptHashOut(this.redeemScript).equals(this.output.script), + 'Provided public keys don\'t hash to the provided output'); + this.publicKeyIndex = {}; + _.each(this.publicKeys, function(publicKey, index) { + self.publicKeyIndex[publicKey.toString()] = index; + }); + this.threshold = threshold; + // Empty array of signatures + this.signatures = signatures ? this._deserializeSignatures(signatures) : new Array(this.publicKeys.length); } -inherits(Mont, Red); +inherits(MultiSigScriptHashInput, Input); -Mont.prototype.convertTo = function convertTo(num) { - return this.imod(num.shln(this.shift)); +MultiSigScriptHashInput.prototype.toObject = function() { + var obj = Input.prototype.toObject.apply(this, arguments); + obj.threshold = this.threshold; + obj.publicKeys = _.map(this.publicKeys, function(publicKey) { return publicKey.toString(); }); + obj.signatures = this._serializeSignatures(); + return obj; }; -Mont.prototype.convertFrom = function convertFrom(num) { - var r = this.imod(num.mul(this.rinv)); - r.red = null; - return r; +MultiSigScriptHashInput.prototype._deserializeSignatures = function(signatures) { + return _.map(signatures, function(signature) { + if (!signature) { + return undefined; + } + return new TransactionSignature(signature); + }); }; -Mont.prototype.imul = function imul(a, b) { - if (a.cmpn(0) === 0 || b.cmpn(0) === 0) { - a.words[0] = 0; - a.length = 1; - return a; - } +MultiSigScriptHashInput.prototype._serializeSignatures = function() { + return _.map(this.signatures, function(signature) { + if (!signature) { + return undefined; + } + return signature.toObject(); + }); +}; - 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).ishrn(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); +MultiSigScriptHashInput.prototype.getSignatures = function(transaction, privateKey, index, sigtype) { + $.checkState(this.output instanceof Output); + sigtype = sigtype || Signature.SIGHASH_ALL; - return res._forceRed(this); + var self = this; + var results = []; + _.each(this.publicKeys, function(publicKey) { + if (publicKey.toString() === privateKey.publicKey.toString()) { + results.push(new TransactionSignature({ + publicKey: privateKey.publicKey, + prevTxId: self.prevTxId, + outputIndex: self.outputIndex, + inputIndex: index, + signature: Sighash.sign(transaction, privateKey, sigtype, index, self.redeemScript), + sigtype: sigtype + })); + } + }); + return results; }; -Mont.prototype.mul = function mul(a, b) { - if (a.cmpn(0) === 0 || b.cmpn(0) === 0) - 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).ishrn(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); +MultiSigScriptHashInput.prototype.addSignature = function(transaction, signature) { + $.checkState(!this.isFullySigned(), 'All needed signatures have already been added'); + $.checkArgument(!_.isUndefined(this.publicKeyIndex[signature.publicKey.toString()]), + 'Signature has no matching public key'); + $.checkState(this.isValidSignature(transaction, signature)); + this.signatures[this.publicKeyIndex[signature.publicKey.toString()]] = signature; + this._updateScript(); + return this; +}; - return res._forceRed(this); +MultiSigScriptHashInput.prototype._updateScript = function() { + this.setScript(Script.buildP2SHMultisigIn( + this.publicKeys, + this.threshold, + this._createSignatures(), + { cachedMultisig: this.redeemScript } + )); + return 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.invm(this.m).mul(this.r2)); - return res._forceRed(this); +MultiSigScriptHashInput.prototype._createSignatures = function() { + return _.map( + _.filter(this.signatures, function(signature) { return !_.isUndefined(signature); }), + function(signature) { + return BufferUtil.concat([ + signature.signature.toDER(), + BufferUtil.integerAsSingleByteBuffer(signature.sigtype) + ]); + } + ); }; -},{}],57:[function(require,module,exports){ -// Base58 encoding/decoding -// Originally written by Mike Hearn for BitcoinJ -// Copyright (c) 2011 Google Inc -// Ported to JavaScript by Stefan Thomas -// Merged Buffer refactorings from base58-native by Stephen Pair -// Copyright (c) 2013 BitPay Inc +MultiSigScriptHashInput.prototype.clearSignatures = function() { + this.signatures = new Array(this.publicKeys.length); + this._updateScript(); +}; -var ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' -var ALPHABET_MAP = {} -for(var i = 0; i < ALPHABET.length; i++) { - ALPHABET_MAP[ALPHABET.charAt(i)] = i -} -var BASE = 58 +MultiSigScriptHashInput.prototype.isFullySigned = function() { + return this.countSignatures() === this.threshold; +}; -function encode(buffer) { - if (buffer.length === 0) return '' +MultiSigScriptHashInput.prototype.countMissingSignatures = function() { + return this.threshold - this.countSignatures(); +}; - var i, j, digits = [0] - for (i = 0; i < buffer.length; i++) { - for (j = 0; j < digits.length; j++) digits[j] <<= 8 +MultiSigScriptHashInput.prototype.countSignatures = function() { + return _.reduce(this.signatures, function(sum, signature) { + return sum + (!!signature); + }, 0); +}; - digits[0] += buffer[i] +MultiSigScriptHashInput.prototype.publicKeysWithoutSignature = function() { + var self = this; + return _.filter(this.publicKeys, function(publicKey) { + return !(self.signatures[self.publicKeyIndex[publicKey.toString()]]); + }); +}; - var carry = 0 - for (j = 0; j < digits.length; ++j) { - digits[j] += carry +MultiSigScriptHashInput.prototype.isValidSignature = function(transaction, signature) { + // FIXME: Refactor signature so this is not necessary + signature.signature.nhashtype = signature.sigtype; + return Sighash.verify( + transaction, + signature.signature, + signature.publicKey, + signature.inputIndex, + this.redeemScript + ); +}; - carry = (digits[j] / BASE) | 0 - digits[j] %= BASE - } +MultiSigScriptHashInput.OPCODES_SIZE = 7; // serialized size (<=3) + 0 .. N .. M OP_CHECKMULTISIG +MultiSigScriptHashInput.SIGNATURE_SIZE = 74; // size (1) + DER (<=72) + sighash (1) +MultiSigScriptHashInput.PUBKEY_SIZE = 34; // size (1) + DER (<=33) - while (carry) { - digits.push(carry % BASE) +MultiSigScriptHashInput.prototype._estimateSize = function() { + return MultiSigScriptHashInput.OPCODES_SIZE + + this.threshold * MultiSigScriptHashInput.SIGNATURE_SIZE + + this.publicKeys.length * MultiSigScriptHashInput.PUBKEY_SIZE; +}; - carry = (carry / BASE) | 0 - } - } +module.exports = MultiSigScriptHashInput; - // deal with leading zeros - for (i = 0; buffer[i] === 0 && i < buffer.length - 1; i++) digits.push(0) +},{"../../crypto/signature":39,"../../publickey":53,"../../script":54,"../../util/buffer":69,"../../util/preconditions":71,"../output":62,"../sighash":63,"../signature":64,"./input":59,"inherits":94,"lodash":95}],61:[function(require,module,exports){ +'use strict'; - return digits.reverse().map(function(digit) { return ALPHABET[digit] }).join('') -} +var inherits = require('inherits'); -function decode(string) { - if (string.length === 0) return [] +var $ = require('../../util/preconditions'); +var BufferUtil = require('../../util/buffer'); - var i, j, bytes = [0] - for (i = 0; i < string.length; i++) { - var c = string[i] - if (!(c in ALPHABET_MAP)) throw new Error('Non-base58 character') - - for (j = 0; j < bytes.length; j++) bytes[j] *= BASE - bytes[0] += ALPHABET_MAP[c] - - var carry = 0 - for (j = 0; j < bytes.length; ++j) { - bytes[j] += carry +var Hash = require('../../crypto/hash'); +var Input = require('./input'); +var Output = require('../output'); +var Sighash = require('../sighash'); +var Script = require('../../script'); +var Signature = require('../../crypto/signature'); +var TransactionSignature = require('../signature'); - carry = bytes[j] >> 8 - bytes[j] &= 0xff - } +/** + * Represents a special kind of input of PayToPublicKeyHash kind. + * @constructor + */ +function PublicKeyHashInput() { + Input.apply(this, arguments); +} +inherits(PublicKeyHashInput, Input); - while (carry) { - bytes.push(carry & 0xff) +/* jshint maxparams: 5 */ +/** + * @param {Transaction} transaction - the transaction to be signed + * @param {PrivateKey} privateKey - the private key with which to sign the transaction + * @param {number} index - the index of the input in the transaction input vector + * @param {number=} sigtype - the type of signature, defaults to Signature.SIGHASH_ALL + * @param {Buffer=} hashData - the precalculated hash of the public key associated with the privateKey provided + * @return {Array} of objects that can be + */ +PublicKeyHashInput.prototype.getSignatures = function(transaction, privateKey, index, sigtype, hashData) { + $.checkState(this.output instanceof Output); + hashData = hashData || Hash.sha256ripemd160(privateKey.publicKey.toBuffer()); + sigtype = sigtype || Signature.SIGHASH_ALL; - carry >>= 8 - } + if (BufferUtil.equals(hashData, this.output.script.getPublicKeyHash())) { + return [new TransactionSignature({ + publicKey: privateKey.publicKey, + prevTxId: this.prevTxId, + outputIndex: this.outputIndex, + inputIndex: index, + signature: Sighash.sign(transaction, privateKey, sigtype, index, this.output.script), + sigtype: sigtype + })]; } + return []; +}; +/* jshint maxparams: 3 */ - // deal with leading zeros - for (i = 0; string[i] === '1' && i < string.length - 1; i++) bytes.push(0) +/** + * Add the provided signature + * + * @param {Object} signature + * @param {PublicKey} signature.publicKey + * @param {Signature} signature.signature + * @param {number=} signature.sigtype + * @return {PublicKeyHashInput} this, for chaining + */ +PublicKeyHashInput.prototype.addSignature = function(transaction, signature) { + $.checkState(this.isValidSignature(transaction, signature), 'Signature is invalid'); + this.setScript(Script.buildPublicKeyHashIn( + signature.publicKey, + signature.signature.toDER(), + signature.sigtype + )); + return this; +}; - return bytes.reverse() -} +/** + * Clear the input's signature + * @return {PublicKeyHashInput} this, for chaining + */ +PublicKeyHashInput.prototype.clearSignatures = function() { + this.setScript(Script.empty()); + return this; +}; -module.exports = { - encode: encode, - decode: decode -} +/** + * Query whether the input is signed + * @return {boolean} + */ +PublicKeyHashInput.prototype.isFullySigned = function() { + return this.script.isPublicKeyHashIn(); +}; -},{}],58:[function(require,module,exports){ -var elliptic = exports; +PublicKeyHashInput.SCRIPT_MAX_SIZE = 73 + 34; // sigsize (1 + 72) + pubkey (1 + 33) -elliptic.version = require('../package.json').version; -elliptic.utils = require('./elliptic/utils'); -elliptic.rand = require('brorand'); -elliptic.hmacDRBG = require('./elliptic/hmac-drbg'); -elliptic.curve = require('./elliptic/curve'); -elliptic.curves = require('./elliptic/curves'); +PublicKeyHashInput.prototype._estimateSize = function() { + return PublicKeyHashInput.SCRIPT_MAX_SIZE; +}; -// Protocols -elliptic.ec = require('./elliptic/ec'); +module.exports = PublicKeyHashInput; -},{"../package.json":71,"./elliptic/curve":61,"./elliptic/curves":64,"./elliptic/ec":65,"./elliptic/hmac-drbg":68,"./elliptic/utils":69,"brorand":70}],59:[function(require,module,exports){ -var assert = require('assert'); -var bn = require('bn.js'); -var elliptic = require('../../elliptic'); +},{"../../crypto/hash":36,"../../crypto/signature":39,"../../script":54,"../../util/buffer":69,"../../util/preconditions":71,"../output":62,"../sighash":63,"../signature":64,"./input":59,"inherits":94}],62:[function(require,module,exports){ +'use strict'; -var getNAF = elliptic.utils.getNAF; -var getJSF = elliptic.utils.getJSF; +var _ = require('lodash'); +var BN = require('../crypto/bn'); +var buffer = require('buffer'); +var bufferUtil = require('../util/buffer'); +var JSUtil = require('../util/js'); +var BufferWriter = require('../encoding/bufferwriter'); +var Script = require('../script'); -function BaseCurve(type, conf) { - this.type = type; - this.p = new bn(conf.p, 16); +function Output(params) { + if (!(this instanceof Output)) { + return new Output(params); + } + if (params) { + if (JSUtil.isValidJSON(params)) { + return Output.fromJSON(params); + } + return this._fromObject(params); + } +} - // Use Montgomery, when there is no fast reduction for the prime - this.red = conf.prime ? bn.red(conf.prime) : bn.mont(this.p); +Object.defineProperty(Output.prototype, 'script', { + configurable: false, + writeable: false, + enumerable: true, + get: function() { + if (!this._script) { + this._script = new Script(this._scriptBuffer); + } + return this._script; + } +}); - // Useful for many curves - this.zero = new bn(0).toRed(this.red); - this.one = new bn(1).toRed(this.red); - this.two = new bn(2).toRed(this.red); +Object.defineProperty(Output.prototype, 'satoshis', { + configurable: false, + writeable: true, + enumerable: true, + get: function() { + return this._satoshis; + }, + set: function(num) { + if (num instanceof BN) { + this._satoshisBN = num; + this._satoshis = num.toNumber(); + } else if (_.isString(num)) { + this._satoshis = parseInt(num); + this._satoshisBN = BN.fromNumber(this._satoshis); + } else { + this._satoshisBN = BN.fromNumber(num); + this._satoshis = num; + } + } +}); - // Curve configuration, optional - this.n = conf.n && new bn(conf.n, 16); - this.g = conf.g && this.pointFromJSON(conf.g, conf.gRed); +Output.prototype._fromObject = function(param) { + this.satoshis = param.satoshis; + if (param.script || param.scriptBuffer) { + this.setScript(param.script || param.scriptBuffer); + } + return this; +}; - // Temporary arrays - this._wnafT1 = new Array(4); - this._wnafT2 = new Array(4); - this._wnafT3 = new Array(4); - this._wnafT4 = new Array(4); -} -module.exports = BaseCurve; +Output.prototype.toObject = function toObject() { + return { + satoshis: this.satoshis, + script: this.script.toString() + }; +}; -BaseCurve.prototype.point = function point() { - throw new Error('Not implemented'); +Output.prototype.toJSON = function toJSON() { + return JSON.stringify(this.toObject()); }; -BaseCurve.prototype.validate = function validate(point) { - throw new Error('Not implemented'); +Output.fromJSON = function(json) { + if (JSUtil.isValidJSON(json)) { + json = JSON.parse(json); + } + return new Output({ + satoshis: json.satoshis || -(-json.valuebn), + script: new Script(json.script) + }); }; -BaseCurve.prototype._fixedNafMul = function _fixedNafMul(p, k) { - var doubles = p._getDoubles(); +Output.prototype.setScript = function(script) { + if (script instanceof Script) { + this._scriptBuffer = script.toBuffer(); + this._script = script; + } else if (_.isString(script)) { + this._script = new Script(script); + this._scriptBuffer = this._script.toBuffer(); + } else if (bufferUtil.isBuffer(script)) { + this._scriptBuffer = script; + this._script = null; + } else { + throw new TypeError('Unrecognized Argument'); + } + return this; +}; - var naf = getNAF(k, 1); - var I = (1 << (doubles.step + 1)) - (doubles.step % 2 === 0 ? 2 : 1); - I /= 3; +Output.prototype.inspect = function() { + return ''; +}; - // Translate into more windowed form - var repr = []; - for (var j = 0; j < naf.length; j += doubles.step) { - var nafW = 0; - for (var k = j + doubles.step - 1; k >= j; k--) - nafW = (nafW << 1) + naf[k]; - repr.push(nafW); +Output.fromBufferReader = function(br) { + var output = new Output(); + output.satoshis = br.readUInt64LEBN(); + var size = br.readVarintNum(); + if (size !== 0) { + output._scriptBuffer = br.read(size); + } else { + output._scriptBuffer = new buffer.Buffer([]); } + return output; +}; - var a = this.jpoint(null, null, null); - var b = this.jpoint(null, null, null); - for (var i = I; i > 0; i--) { - for (var j = 0; j < repr.length; j++) { - var nafW = repr[j]; - if (nafW === i) - b = b.mixedAdd(doubles.points[j]); - else if (nafW === -i) - b = b.mixedAdd(doubles.points[j].neg()); - } - a = a.add(b); +Output.prototype.toBufferWriter = function(writer) { + if (!writer) { + writer = new BufferWriter(); } - return a.toP(); + writer.writeUInt64LEBN(this._satoshisBN); + var script = this._scriptBuffer; + writer.writeVarintNum(script.length); + writer.write(script); + return writer; }; -BaseCurve.prototype._wnafMul = function _wnafMul(p, k) { - var w = 4; - - // Precompute window - var nafPoints = p._getNAFPoints(w); - w = nafPoints.wnd; - var wnd = nafPoints.points; +module.exports = Output; - // Get NAF form - var naf = getNAF(k, w); +},{"../crypto/bn":34,"../encoding/bufferwriter":43,"../script":54,"../util/buffer":69,"../util/js":70,"buffer":209,"lodash":95}],63:[function(require,module,exports){ +(function (Buffer){ +'use strict'; - // Add `this`*(N+1) for every w-NAF index - var acc = this.jpoint(null, null, null); - for (var i = naf.length - 1; i >= 0; i--) { - // Count zeroes - for (var k = 0; i >= 0 && naf[i] === 0; i--) - k++; - if (i >= 0) - k++; - acc = acc.dblp(k); +var buffer = require('buffer'); - if (i < 0) - break; - var z = naf[i]; - assert(z !== 0); - if (p.type === 'affine') { - // J +- P - if (z > 0) - acc = acc.mixedAdd(wnd[(z - 1) >> 1]); - else - acc = acc.mixedAdd(wnd[(-z - 1) >> 1].neg()); - } else { - // J +- J - if (z > 0) - acc = acc.add(wnd[(z - 1) >> 1]); - else - acc = acc.add(wnd[(-z - 1) >> 1].neg()); - } - } - return p.type === 'affine' ? acc.toP() : acc; -}; +var Signature = require('../crypto/signature'); +var Script = require('../script'); +var Output = require('./output'); +var BufferReader = require('../encoding/bufferreader'); +var BufferWriter = require('../encoding/bufferwriter'); +var BN = require('../crypto/bn'); +var Hash = require('../crypto/hash'); +var ECDSA = require('../crypto/ecdsa'); +var $ = require('../util/preconditions'); +var _ = require('lodash'); -BaseCurve.prototype._wnafMulAdd = function _wnafMulAdd(defW, - points, - coeffs, - len) { - var wndWidth = this._wnafT1; - var wnd = this._wnafT2; - var naf = this._wnafT3; +var SIGHASH_SINGLE_BUG = '0000000000000000000000000000000000000000000000000000000000000001'; +var BITS_64_ON = 'ffffffffffffffff'; - // Fill all arrays - var max = 0; - for (var i = 0; i < len; i++) { - var p = points[i]; - var nafPoints = p._getNAFPoints(defW); - wndWidth[i] = nafPoints.wnd; - wnd[i] = nafPoints.points; - } +/** + * Returns a buffer of length 32 bytes with the hash that needs to be signed + * for OP_CHECKSIG. + * + * @name Signing.sighash + * @param {Transaction} transaction the transaction to sign + * @param {number} sighashType the type of the hash + * @param {number} inputNumber the input index for the signature + * @param {Script} subscript the script that will be signed + */ +var sighash = function sighash(transaction, sighashType, inputNumber, subscript) { + var Transaction = require('./transaction'); + var Input = require('./input'); - // Comb small window NAFs - for (var i = len - 1; i >= 1; i -= 2) { - var a = i - 1; - var b = i; - if (wndWidth[a] !== 1 || wndWidth[b] !== 1) { - naf[a] = getNAF(coeffs[a], wndWidth[a]); - naf[b] = getNAF(coeffs[b], wndWidth[b]); - max = Math.max(naf[a].length, max); - max = Math.max(naf[b].length, max); - continue; - } + var i; + // Copy transaction + var txcopy = Transaction.shallowCopy(transaction); - var comb = [ - points[a], /* 1 */ - null, /* 3 */ - null, /* 5 */ - points[b] /* 7 */ - ]; + // Copy script + subscript = new Script(subscript); + subscript.removeCodeseparators(); - // Try to avoid Projective points, if possible - if (points[a].y.cmp(points[b].y) === 0) { - comb[1] = points[a].add(points[b]); - comb[2] = points[a].toJ().mixedAdd(points[b].neg()); - } else if (points[a].y.cmp(points[b].y.redNeg()) === 0) { - comb[1] = points[a].toJ().mixedAdd(points[b]); - comb[2] = points[a].add(points[b].neg()); - } else { - comb[1] = points[a].toJ().mixedAdd(points[b]); - comb[2] = points[a].toJ().mixedAdd(points[b].neg()); - } + for (i = 0; i < txcopy.inputs.length; i++) { + // Blank signatures for other inputs + txcopy.inputs[i] = new Input(txcopy.inputs[i]).setScript(Script.empty()); + } - var index = [ - -3, /* -1 -1 */ - -1, /* -1 0 */ - -5, /* -1 1 */ - -7, /* 0 -1 */ - 0, /* 0 0 */ - 7, /* 0 1 */ - 5, /* 1 -1 */ - 1, /* 1 0 */ - 3 /* 1 1 */ - ]; + txcopy.inputs[inputNumber] = new Input(txcopy.inputs[inputNumber]).setScript(subscript); - var jsf = getJSF(coeffs[a], coeffs[b]); - max = Math.max(jsf[0].length, max); - naf[a] = new Array(max); - naf[b] = new Array(max); - for (var j = 0; j < max; j++) { - var ja = jsf[0][j] | 0; - var jb = jsf[1][j] | 0; + if ((sighashType & 31) === Signature.SIGHASH_NONE || + (sighashType & 31) === Signature.SIGHASH_SINGLE) { - naf[a][j] = index[(ja + 1) * 3 + (jb + 1)]; - naf[b][j] = 0; - wnd[a] = comb; + // clear all sequenceNumbers + for (i = 0; i < txcopy.inputs.length; i++) { + if (i !== inputNumber) { + txcopy.inputs[i].sequenceNumber = 0; + } } } - var acc = this.jpoint(null, null, null); - var tmp = this._wnafT4; - for (var i = max; i >= 0; i--) { - var k = 0; + if ((sighashType & 31) === Signature.SIGHASH_NONE) { + txcopy.outputs = []; - while (i >= 0) { - var zero = true; - for (var j = 0; j < len; j++) { - tmp[j] = naf[j][i] | 0; - if (tmp[j] !== 0) - zero = false; - } - if (!zero) - break; - k++; - i--; + } else if ((sighashType & 31) === Signature.SIGHASH_SINGLE) { + // The SIGHASH_SINGLE bug. + // https://bitcointalk.org/index.php?topic=260595.0 + if (inputNumber > txcopy.outputs.length - 1) { + return new Buffer(SIGHASH_SINGLE_BUG, 'hex'); + } + if (txcopy.outputs.length <= inputNumber) { + throw new Error('Missing output to sign'); } - if (i >= 0) - k++; - acc = acc.dblp(k); - if (i < 0) - break; - for (var j = 0; j < len; j++) { - var z = tmp[j]; - var p; - if (z === 0) - continue; - else if (z > 0) - p = wnd[j][(z - 1) >> 1]; - else if (z < 0) - p = wnd[j][(-z - 1) >> 1].neg(); + txcopy.outputs.length = inputNumber + 1; - if (p.type === 'affine') - acc = acc.mixedAdd(p); - else - acc = acc.add(p); + for (i = 0; i < inputNumber; i++) { + txcopy.outputs[i] = new Output({ + satoshis: BN.fromBuffer(new buffer.Buffer(BITS_64_ON, 'hex')), + script: Script.empty() + }); } } - // Zeroify references - for (var i = 0; i < len; i++) - wnd[i] = null; - return acc.toP(); -}; -BaseCurve.BasePoint = BasePoint; - -function BasePoint(curve, type) { - this.curve = curve; - this.type = type; - this.precomputed = null; -} + if (sighashType & Signature.SIGHASH_ANYONECANPAY) { + txcopy.inputs = [txcopy.inputs[inputNumber]]; + } -BasePoint.prototype.validate = function validate() { - return this.curve.validate(this); + var buf = new BufferWriter() + .write(txcopy.toBuffer()) + .writeInt32LE(sighashType) + .toBuffer(); + var ret = Hash.sha256sha256(buf); + ret = new BufferReader(ret).readReverse(); + return ret; }; -BasePoint.prototype.precompute = function precompute(power, _beta) { - if (this.precomputed) - return this; +/** + * Create a signature + * + * @name Signing.sign + * @param {Transaction} transaction + * @param {PrivateKey} privateKey + * @param {number} sighash + * @param {number} inputIndex + * @param {Script} subscript + * @return {Signature} + */ +function sign(transaction, privateKey, sighashType, inputIndex, subscript) { + var hashbuf = sighash(transaction, sighashType, inputIndex, subscript); + var sig = ECDSA.sign(hashbuf, privateKey, 'little').set({ + nhashtype: sighashType + }); + return sig; +} - var precomputed = { - doubles: null, - naf: null, - beta: null - }; - precomputed.naf = this._getNAFPoints(8); - precomputed.doubles = this._getDoubles(4, power); - precomputed.beta = this._getBeta(); - this.precomputed = precomputed; +/** + * Verify a signature + * + * @name Signing.verify + * @param {Transaction} transaction + * @param {Signature} signature + * @param {PublicKey} publicKey + * @param {number} inputIndex + * @param {Script} subscript + * @return {boolean} + */ +function verify(transaction, signature, publicKey, inputIndex, subscript) { + $.checkArgument(!_.isUndefined(transaction)); + $.checkArgument(!_.isUndefined(signature) && !_.isUndefined(signature.nhashtype)); + var hashbuf = sighash(transaction, signature.nhashtype, inputIndex, subscript); + return ECDSA.verify(hashbuf, signature, publicKey, 'little'); +} - return this; +/** + * @namespace Signing + */ +module.exports = { + sighash: sighash, + sign: sign, + verify: verify }; -BasePoint.prototype._getDoubles = function _getDoubles(step, power) { - if (this.precomputed && this.precomputed.doubles) - return this.precomputed.doubles; +}).call(this,require("buffer").Buffer) +},{"../crypto/bn":34,"../crypto/ecdsa":35,"../crypto/hash":36,"../crypto/signature":39,"../encoding/bufferreader":42,"../encoding/bufferwriter":43,"../script":54,"../util/preconditions":71,"./input":58,"./output":62,"./transaction":65,"buffer":209,"lodash":95}],64:[function(require,module,exports){ +(function (Buffer){ +'use strict'; - var doubles = [ this ]; - var acc = this; - for (var i = 0; i < power; i += step) { - for (var j = 0; j < step; j++) - acc = acc.dbl(); - doubles.push(acc); +var _ = require('lodash'); +var $ = require('../util/preconditions'); +var inherits = require('inherits'); +var BufferUtil = require('../util/buffer'); +var JSUtil = require('../util/js'); + +var PublicKey = require('../publickey'); +var errors = require('../errors'); +var Signature = require('../crypto/signature'); + +/** + * @desc + * Wrapper around Signature with fields related to signing a transaction specifically + * + * @param {Object|string|TransactionSignature} arg + * @constructor + */ +function TransactionSignature(arg) { + if (!(this instanceof TransactionSignature)) { + return new TransactionSignature(arg); } - return { - step: step, - points: doubles - }; + if (arg instanceof TransactionSignature) { + return arg; + } + if (_.isString(arg)) { + if (JSUtil.isValidJSON(arg)) { + return TransactionSignature.fromJSON(arg); + } + } + if (_.isObject(arg)) { + return this._fromObject(arg); + } + throw new errors.InvalidArgument('TransactionSignatures must be instantiated from an object'); +} +inherits(TransactionSignature, Signature); + +TransactionSignature.prototype._fromObject = function(arg) { + this._checkObjectArgs(arg); + this.publicKey = new PublicKey(arg.publicKey); + this.prevTxId = BufferUtil.isBuffer(arg.prevTxId) ? arg.prevTxId : new Buffer(arg.prevTxId, 'hex'); + this.outputIndex = arg.outputIndex; + this.inputIndex = arg.inputIndex; + this.signature = (arg.signature instanceof Signature) ? arg.signature : + BufferUtil.isBuffer(arg.signature) ? Signature.fromBuffer(arg.signature) : + Signature.fromString(arg.signature); + this.sigtype = arg.sigtype; + return this; }; -BasePoint.prototype._getNAFPoints = function _getNAFPoints(wnd) { - if (this.precomputed && this.precomputed.naf) - return this.precomputed.naf; +TransactionSignature.prototype._checkObjectArgs = function(arg) { + $.checkArgument(PublicKey(arg.publicKey), 'publicKey'); + $.checkArgument(!_.isUndefined(arg.inputIndex), 'inputIndex'); + $.checkArgument(!_.isUndefined(arg.outputIndex), 'outputIndex'); + $.checkState(_.isNumber(arg.inputIndex), 'inputIndex must be a number'); + $.checkState(_.isNumber(arg.outputIndex), 'outputIndex must be a number'); + $.checkArgument(arg.signature, 'signature'); + $.checkArgument(arg.prevTxId, 'prevTxId'); + $.checkState(arg.signature instanceof Signature || + BufferUtil.isBuffer(arg.signature) || + JSUtil.isHexa(arg.signature), 'signature must be a buffer or hexa value'); + $.checkState(BufferUtil.isBuffer(arg.prevTxId) || + JSUtil.isHexa(arg.prevTxId), 'prevTxId must be a buffer or hexa value'); + $.checkArgument(arg.sigtype, 'sigtype'); + $.checkState(_.isNumber(arg.sigtype), 'sigtype must be a number'); +}; - var res = [ this ]; - var max = (1 << wnd) - 1; - var dbl = max === 1 ? null : this.dbl(); - for (var i = 1; i < max; i++) - res[i] = res[i - 1].add(dbl); +/** + * Serializes a transaction to a plain JS object + * @return {Object} + */ +TransactionSignature.prototype.toObject = function() { return { - wnd: wnd, - points: res + publicKey: this.publicKey.toString(), + prevTxId: this.prevTxId.toString('hex'), + outputIndex: this.outputIndex, + inputIndex: this.inputIndex, + signature: this.signature.toString(), + sigtype: this.sigtype }; }; -BasePoint.prototype._getBeta = function _getBeta() { - return null; +/** + * Serializes a transaction to a JSON string + * @return {string} + */ +TransactionSignature.prototype.toJSON = function() { + return JSON.stringify(this.toObject()); }; -BasePoint.prototype.dblp = function dblp(k) { - var r = this; - for (var i = 0; i < k; i++) - r = r.dbl(); - return r; +/** + * Builds a TransactionSignature from a JSON string + * @param {string} json + * @return {TransactionSignature} + */ +TransactionSignature.fromJSON = function(json) { + return new TransactionSignature(JSON.parse(json)); }; -},{"../../elliptic":58,"assert":89,"bn.js":56}],60:[function(require,module,exports){ -var assert = require('assert'); -var curve = require('../curve'); -var elliptic = require('../../elliptic'); -var bn = require('bn.js'); -var inherits = require('inherits'); -var Base = curve.base; - -var getNAF = elliptic.utils.getNAF; +/** + * Builds a TransactionSignature from an object + * @param {Object} object + * @return {TransactionSignature} + */ +TransactionSignature.fromObject = function(object) { + $.checkArgument(object); + return new TransactionSignature(object); +}; -function EdwardsCurve(conf) { - // NOTE: Important as we are creating point in Base.call() - this.twisted = conf.a != 1; - this.mOneA = this.twisted && conf.a == -1; - this.extended = this.mOneA; +module.exports = TransactionSignature; - Base.call(this, 'mont', conf); +}).call(this,require("buffer").Buffer) +},{"../crypto/signature":39,"../errors":45,"../publickey":53,"../util/buffer":69,"../util/js":70,"../util/preconditions":71,"buffer":209,"inherits":94,"lodash":95}],65:[function(require,module,exports){ +'use strict'; - this.a = new bn(conf.a, 16).mod(this.red.m).toRed(this.red); - this.c = new bn(conf.c, 16).toRed(this.red); - this.c2 = this.c.redSqr(); - this.d = new bn(conf.d, 16).toRed(this.red); - this.dd = this.d.redAdd(this.d); +var _ = require('lodash'); +var $ = require('../util/preconditions'); +var buffer = require('buffer'); - assert(!this.twisted || this.c.fromRed().cmpn(1) === 0); - this.oneC = conf.c == 1; -} -inherits(EdwardsCurve, Base); -module.exports = EdwardsCurve; +var errors = require('../errors'); +var BufferUtil = require('../util/buffer'); +var JSUtil = require('../util/js'); +var BufferReader = require('../encoding/bufferreader'); +var BufferWriter = require('../encoding/bufferwriter'); +var Hash = require('../crypto/hash'); +var Signature = require('../crypto/signature'); +var Sighash = require('./sighash'); -EdwardsCurve.prototype._mulA = function _mulA(num) { - if (this.mOneA) - return num.redNeg(); - else - return this.a.redMul(num); -}; +var Address = require('../address'); +var UnspentOutput = require('./unspentoutput'); +var Input = require('./input'); +var PublicKeyHashInput = Input.PublicKeyHash; +var MultiSigScriptHashInput = Input.MultiSigScriptHash; +var Output = require('./output'); +var Script = require('../script'); +var PrivateKey = require('../privatekey'); +var Block = require('../block'); +var BN = require('../crypto/bn'); -EdwardsCurve.prototype._mulC = function _mulC(num) { - if (this.oneC) - return num; - else - return this.c.redMul(num); -}; +var CURRENT_VERSION = 1; +var DEFAULT_NLOCKTIME = 0; +var DEFAULT_SEQNUMBER = 0xFFFFFFFF; -EdwardsCurve.prototype.point = function point(x, y, z, t) { - return new Point(this, x, y, z, t); -}; +/** + * Represents a transaction, a set of inputs and outputs to change ownership of tokens + * + * @param {*} serialized + * @constructor + */ +function Transaction(serialized) { + if (!(this instanceof Transaction)) { + return new Transaction(serialized); + } + this.inputs = []; + this.outputs = []; + this._inputAmount = 0; + this._outputAmount = 0; -// Just for compatibility with Short curve -EdwardsCurve.prototype.jpoint = function jpoint(x, y, z, t) { - return this.point(x, y, z, t); -}; + if (serialized) { + if (serialized instanceof Transaction) { + return Transaction.shallowCopy(serialized); + } else if (JSUtil.isHexa(serialized)) { + this.fromString(serialized); + } else if (JSUtil.isValidJSON(serialized)) { + this.fromJSON(serialized); + } else if (BufferUtil.isBuffer(serialized)) { + this.fromBuffer(serialized); + } else if (_.isObject(serialized)) { + this.fromObject(serialized); + } else { + throw new errors.InvalidArgument('Must provide an object or string to deserialize a transaction'); + } + } else { + this._newTransaction(); + } +} -EdwardsCurve.prototype.pointFromJSON = function pointFromJSON(obj) { - return Point.fromJSON(this, obj); -}; +// max amount of satoshis in circulation +Transaction.MAX_MONEY = 21000000 * 1e8; -EdwardsCurve.prototype.pointFromX = function pointFromX(odd, x) { - x = new bn(x, 16); - if (!x.red) - x = x.toRed(this.red); +// nlocktime limit to be considered block height rather than a timestamp +Transaction.NLOCKTIME_BLOCKHEIGHT_LIMIT = 5e8; - var x2 = x.redSqr(); - var rhs = this.c2.redSub(this.a.redMul(x2)); - var lhs = this.one.redSub(this.c2.redMul(this.d).redMul(x2)); +// Max value for an unsigned 32 bit value +Transaction.NLOCKTIME_MAX_VALUE = 4294967295; - var y = rhs.redMul(lhs.redInvm()).redSqrt(); - var isOdd = y.fromRed().isOdd(); - if (odd && !isOdd || !odd && isOdd) - y = y.redNeg(); +/* Constructors and Serialization */ - return this.point(x, y, curve.one); +/** + * Create a 'shallow' copy of the transaction, by serializing and deserializing + * it dropping any additional information that inputs and outputs may have hold + * + * @param {Transaction} transaction + * @return {Transaction} + */ +Transaction.shallowCopy = function(transaction) { + var copy = new Transaction(transaction.toBuffer()); + return copy; }; -EdwardsCurve.prototype.validate = function validate(point) { - if (point.isInfinity()) - return true; - - // Curve: A * X^2 + Y^2 = C^2 * (1 + D * X^2 * Y^2) - point.normalize(); - - var x2 = point.x.redSqr(); - var y2 = point.y.redSqr(); - var lhs = x2.redMul(this.a).redAdd(y2); - var rhs = this.c2.redMul(this.one.redAdd(this.d.redMul(x2).redMul(y2))); +var hashProperty = { + configurable: false, + writeable: false, + enumerable: true, + get: function() { + return new BufferReader(this._getHash()).readReverse().toString('hex'); + } +}; +Object.defineProperty(Transaction.prototype, 'hash', hashProperty); +Object.defineProperty(Transaction.prototype, 'id', hashProperty); - return lhs.cmp(rhs) === 0; +/** + * Retrieve the little endian hash of the transaction (used for serialization) + * @return {Buffer} + */ +Transaction.prototype._getHash = function() { + return Hash.sha256sha256(this.toBuffer()); }; -function Point(curve, x, y, z, t) { - Base.BasePoint.call(this, curve, 'projective'); - if (x === null && y === null && z === null) { - this.x = this.curve.zero; - this.y = this.curve.one; - this.z = this.curve.one; - this.t = this.curve.zero; - this.zOne = true; +/** + * Retrieve a hexa string that can be used with bitcoind's CLI interface + * (decoderawtransaction, sendrawtransaction) + * + * @param {boolean=} unsafe if true, skip testing for fees that are too high + * @return {string} + */ +Transaction.prototype.serialize = function(unsafe) { + if (unsafe) { + return this.uncheckedSerialize(); } else { - this.x = new bn(x, 16); - this.y = new bn(y, 16); - this.z = z ? new bn(z, 16) : this.curve.one; - this.t = t && new bn(t, 16); - if (!this.x.red) - this.x = this.x.toRed(this.curve.red); - if (!this.y.red) - this.y = this.y.toRed(this.curve.red); - if (!this.z.red) - this.z = this.z.toRed(this.curve.red); - if (this.t && !this.t.red) - this.t = this.t.toRed(this.curve.red); - this.zOne = this.z === this.curve.one; - - // Use extended coordinates - if (this.curve.extended && !this.t) { - this.t = this.x.redMul(this.y); - if (!this.zOne) - this.t = this.t.redMul(this.z.redInvm()); - } + return this.checkedSerialize(); } -} -inherits(Point, Base.BasePoint); - -Point.fromJSON = function fromJSON(curve, obj) { - return new Point(curve, obj[0], obj[1], obj[2]); }; -Point.prototype.inspect = function inspect() { - if (this.isInfinity()) - return ''; - return ''; +Transaction.prototype.uncheckedSerialize = Transaction.prototype.toString = function() { + return this.toBuffer().toString('hex'); }; -Point.prototype.isInfinity = function isInfinity() { - // XXX This code assumes that zero is always zero in red - return this.x.cmpn(0) === 0 && - this.y.cmp(this.z) === 0; +Transaction.prototype.checkedSerialize = function() { + var feeError = this._validateFees(); + var missingChange = this._missingChange(); + if (feeError && missingChange) { + throw new errors.Transaction.ChangeAddressMissing(); + } + if (feeError && !missingChange) { + throw new errors.Transaction.FeeError(feeError); + } + if (this._hasDustOutputs()) { + throw new errors.Transaction.DustOutputs(); + } + return this.uncheckedSerialize(); }; -Point.prototype._extDbl = function _extDbl() { - // http://hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html#doubling-dbl-2008-hwcd - // 4M + 4S +Transaction.FEE_SECURITY_MARGIN = 15; - // A = X1^2 - var a = this.x.redSqr(); - // B = Y1^2 - var b = this.y.redSqr(); - // C = 2 * Z1^2 - var c = this.z.redSqr(); - c = c.redIAdd(c); - // D = a * A - var d = this.curve._mulA(a); - // E = (X1 + Y1)^2 - A - B - var e = this.x.redAdd(this.y).redSqr().redISub(a).redISub(b); - // G = D + B - var g = d.redAdd(b); - // F = G - C - var f = g.redSub(c); - // H = D - B - var h = d.redSub(b); - // X3 = E * F - var nx = e.redMul(f); - // Y3 = G * H - var ny = g.redMul(h); - // T3 = E * H - var nt = e.redMul(h); - // Z3 = F * G - var nz = f.redMul(g); - return this.curve.point(nx, ny, nz, nt); +Transaction.prototype._validateFees = function() { + if (this._getUnspentValue() > Transaction.FEE_SECURITY_MARGIN * this._estimateFee()) { + return 'Fee is more than ' + Transaction.FEE_SECURITY_MARGIN + ' times the suggested amount'; + } + if (this._getUnspentValue() < this._estimateFee() / Transaction.FEE_SECURITY_MARGIN) { + return 'Fee is less than ' + Transaction.FEE_SECURITY_MARGIN + ' times the suggested amount'; + } }; -Point.prototype._projDbl = function _projDbl() { - // http://hyperelliptic.org/EFD/g1p/auto-twisted-projective.html#doubling-dbl-2008-bbjlp - // http://hyperelliptic.org/EFD/g1p/auto-edwards-projective.html#doubling-dbl-2007-bl - // and others - // Generally 3M + 4S or 2M + 4S +Transaction.prototype._missingChange = function() { + return !this._changeScript; +}; - // B = (X1 + Y1)^2 - var b = this.x.redAdd(this.y).redSqr(); - // C = X1^2 - var c = this.x.redSqr(); - // D = Y1^2 - var d = this.y.redSqr(); +Transaction.DUST_AMOUNT = 5460; - if (this.curve.twisted) { - // E = a * C - var e = this.curve._mulA(c); - // F = E + D - var f = e.redAdd(d); - if (this.zOne) { - // X3 = (B - C - D) * (F - 2) - var nx = b.redSub(c).redSub(d).redMul(f.redSub(this.curve.two)); - // Y3 = F * (E - D) - var ny = f.redMul(e.redSub(d)); - // Z3 = F^2 - 2 * F - var nz = f.redSqr().redSub(f).redSub(f); - } else { - // H = Z1^2 - var h = this.z.redSqr(); - // J = F - 2 * H - var j = f.redSub(h).redISub(h); - // X3 = (B-C-D)*J - var nx = b.redSub(c).redISub(d).redMul(j); - // Y3 = F * (E - D) - var ny = f.redMul(e.redSub(d)); - // Z3 = F * J - var nz = f.redMul(j); +Transaction.prototype._hasDustOutputs = function() { + var index, output; + for (index in this.outputs) { + output = this.outputs[index]; + if (output.satoshis < Transaction.DUST_AMOUNT && !output.script.isDataOut()) { + return true; } - } else { - // E = C + D - var e = c.redAdd(d); - // H = (c * Z1)^2 - var h = this.curve._mulC(redMul(this.z)).redSqr(); - // J = E - 2 * H - var j = e.redSub(h).redSub(h); - // X3 = c * (B - E) * J - var nx = this.curve._mulC(b.redISub(e)).redMul(j); - // Y3 = c * E * (C - D) - var ny = this.curve._mulC(e).redMul(c.redISub(d)); - // Z3 = E * J - var nz = e.redMul(j); } - return this.curve.point(nx, ny, nz); + return false; }; -Point.prototype.dbl = function dbl() { - if (this.isInfinity()) - return this; +Transaction.prototype.inspect = function() { + return ''; +}; - // Double in extended coordinates - if (this.curve.extended) - return this._extDbl(); - else - return this._projDbl(); +Transaction.prototype.toBuffer = function() { + var writer = new BufferWriter(); + return this.toBufferWriter(writer).toBuffer(); }; -Point.prototype._extAdd = function _extAdd(p) { - // http://hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html#addition-add-2008-hwcd-3 - // 8M +Transaction.prototype.toBufferWriter = function(writer) { + writer.writeUInt32LE(this.version); + writer.writeVarintNum(this.inputs.length); + _.each(this.inputs, function(input) { + input.toBufferWriter(writer); + }); + writer.writeVarintNum(this.outputs.length); + _.each(this.outputs, function(output) { + output.toBufferWriter(writer); + }); + writer.writeUInt32LE(this.nLockTime); + return writer; +}; - // A = (Y1 - X1) * (Y2 - X2) - var a = this.y.redSub(this.x).redMul(p.y.redSub(p.x)); - // B = (Y1 + X1) * (Y2 + X2) - var b = this.y.redAdd(this.x).redMul(p.y.redAdd(p.x)); - // C = T1 * k * T2 - var c = this.t.redMul(this.curve.dd).redMul(p.t); - // D = Z1 * 2 * Z2 - var d = this.z.redMul(p.z.redAdd(p.z)); - // E = B - A - var e = b.redSub(a); - // F = D - C - var f = d.redSub(c); - // G = D + C - var g = d.redAdd(c); - // H = B + A - var h = b.redAdd(a); - // X3 = E * F - var nx = e.redMul(f); - // Y3 = G * H - var ny = g.redMul(h); - // T3 = E * H - var nt = e.redMul(h); - // Z3 = F * G - var nz = f.redMul(g); - return this.curve.point(nx, ny, nz, nt); +Transaction.prototype.fromBuffer = function(buffer) { + var reader = new BufferReader(buffer); + return this.fromBufferReader(reader); }; -Point.prototype._projAdd = function _projAdd(p) { - // http://hyperelliptic.org/EFD/g1p/auto-twisted-projective.html#addition-add-2008-bbjlp - // http://hyperelliptic.org/EFD/g1p/auto-edwards-projective.html#addition-add-2007-bl - // 10M + 1S +Transaction.prototype.fromBufferReader = function(reader) { + $.checkArgument(!reader.finished(), 'No transaction data received'); + var i, sizeTxIns, sizeTxOuts; - // A = Z1 * Z2 - var a = this.z.redMul(p.z); - // B = A^2 - var b = a.redSqr(); - // C = X1 * X2 - var c = this.x.redMul(p.x); - // D = Y1 * Y2 - var d = this.y.redMul(p.y); - // E = d * C * D - var e = this.curve.d.redMul(c).redMul(d); - // F = B - E - var f = b.redSub(e); - // G = B + E - var g = b.redAdd(e); - // X3 = A * F * ((X1 + Y1) * (X2 + Y2) - C - D) - var tmp = this.x.redAdd(this.y).redMul(p.x.redAdd(p.y)).redISub(c).redISub(d); - var nx = a.redMul(f).redMul(tmp); - if (this.curve.twisted) { - // Y3 = A * G * (D - a * C) - var ny = a.redMul(g).redMul(d.redSub(this.curve._mulA(c))); - // Z3 = F * G - var nz = f.redMul(g); - } else { - // Y3 = A * G * (D - C) - var ny = a.redMul(g).redMul(d.redSub(c)); - // Z3 = c * F * G - var nz = this.curve._mulC(f).redMul(g); + this.version = reader.readUInt32LE(); + sizeTxIns = reader.readVarintNum(); + for (i = 0; i < sizeTxIns; i++) { + var input = Input.fromBufferReader(reader); + this.inputs.push(input); } - return this.curve.point(nx, ny, nz); + sizeTxOuts = reader.readVarintNum(); + for (i = 0; i < sizeTxOuts; i++) { + this.outputs.push(Output.fromBufferReader(reader)); + } + this.nLockTime = reader.readUInt32LE(); + return this; }; -Point.prototype.add = function add(p) { - if (this.isInfinity()) - return p; - if (p.isInfinity()) - return this; - - if (this.curve.extended) - return this._extAdd(p); - else - return this._projAdd(p); +Transaction.prototype.fromJSON = function(json) { + if (JSUtil.isValidJSON(json)) { + json = JSON.parse(json); + } + return this.fromObject(json); }; -Point.prototype.mul = function mul(k) { - if (this.precomputed && this.precomputed.doubles) - return this.curve._fixedNafMul(this, k); - else - return this.curve._wnafMul(this, k); +Transaction.prototype.toObject = function toObject() { + var inputs = []; + this.inputs.forEach(function(input) { + inputs.push(input.toObject()); + }); + var outputs = []; + this.outputs.forEach(function(output) { + outputs.push(output.toObject()); + }); + var obj = { + version: this.version, + inputs: inputs, + outputs: outputs, + nLockTime: this.nLockTime + }; + if (this._changeScript) { + obj.changeScript = this._changeScript.toString(); + } + if (!_.isUndefined(this._changeIndex)) { + obj.changeIndex = this._changeIndex; + } + if (!_.isUndefined(this._fee)) { + obj.fee = this._fee; + } + return obj; }; -Point.prototype.mulAdd = function mulAdd(k1, p, k2) { - return this.curve._wnafMulAdd(1, [ this, p ], [ k1, k2 ], 2); +Transaction.prototype.fromObject = function(transaction) { + var self = this; + _.each(transaction.inputs, function(input) { + if (!input.output || !input.output.script) { + self.uncheckedAddInput(new Input(input)); + return; + } + input.output.script = new Script(input.output.script); + var txin; + if (input.output.script.isPublicKeyHashOut()) { + txin = new Input.PublicKeyHash(input); + } else if (input.output.script.isScriptHashOut() && input.publicKeys && input.threshold) { + txin = new Input.MultiSigScriptHash( + input, input.publicKeys, input.threshold, input.signatures + ); + } else { + throw new errors.Transaction.Input.UnsupportedScript(input.output.script); + } + self.addInput(txin); + }); + _.each(transaction.outputs, function(output) { + self.addOutput(new Output(output)); + }); + if (transaction.changeIndex) { + this._changeIndex = transaction.changeIndex; + } + if (transaction.changeScript) { + this._changeScript = new Script(transaction.changeScript); + } + if (transaction.fee) { + this.fee(transaction.fee); + } + this.nLockTime = transaction.nLockTime; + this.version = transaction.version; + this._checkConsistency(); + return this; }; -Point.prototype.normalize = function normalize() { - if (this.zOne) - return this; +Transaction.prototype._checkConsistency = function() { + if (!_.isUndefined(this._changeIndex)) { + $.checkState(this._changeScript); + $.checkState(this.outputs[this._changeIndex]); + $.checkState(this.outputs[this._changeIndex].script.toString() === + this._changeScript.toString()); + } + // TODO: add other checks +}; - // Normalize coordinates - var zi = this.z.redInvm(); - this.x = this.x.redMul(zi); - this.y = this.y.redMul(zi); - if (this.t) - this.t = this.t.redMul(zi); - this.z = this.curve.one; - this.zOne = true; +/** + * Sets nLockTime so that transaction is not valid until the desired date(a + * timestamp in seconds since UNIX epoch is also accepted) + * + * @param {Date | Number} time + * @return {Transaction} this + */ +Transaction.prototype.lockUntilDate = function(time) { + $.checkArgument(time); + if (_.isNumber(time) && time < Transaction.NLOCKTIME_BLOCKHEIGHT_LIMIT) { + throw new errors.Transaction.LockTimeTooEarly(); + } + if (_.isDate(time)) { + time = time.getTime() / 1000; + } + this.nLockTime = time; return this; }; -Point.prototype.neg = function neg() { - return this.curve.point(this.x.redNeg(), - this.y, - this.z, - this.t && this.t.redNeg()); +/** + * Sets nLockTime so that transaction is not valid until the desired block + * height. + * + * @param {Number} height + * @return {Transaction} this + */ +Transaction.prototype.lockUntilBlockHeight = function(height) { + $.checkArgument(_.isNumber(height)); + if (height >= Transaction.NLOCKTIME_BLOCKHEIGHT_LIMIT) { + throw new errors.Transaction.BlockHeightTooHigh(); + } + if (height < 0) { + throw new errors.Transaction.NLockTimeOutOfRange(); + } + this.nLockTime = height; + return this; }; -Point.prototype.getX = function getX() { - this.normalize(); - return this.x.fromRed(); +/** + * Returns a semantic version of the transaction's nLockTime. + * @return {Number|Date} + * If nLockTime is 0, it returns null, + * if it is < 500000000, it returns a block height (number) + * else it returns a Date object. + */ +Transaction.prototype.getLockTime = function() { + if (!this.nLockTime) { + return null; + } + if (this.nLockTime < Transaction.NLOCKTIME_BLOCKHEIGHT_LIMIT) { + return this.nLockTime; + } + return new Date(1000 * this.nLockTime); }; -Point.prototype.getY = function getY() { - this.normalize(); - return this.y.fromRed(); +Transaction.prototype.toJSON = function toJSON() { + return JSON.stringify(this.toObject()); }; -// Compatibility with BaseCurve -Point.prototype.toP = Point.prototype.normalize; -Point.prototype.mixedAdd = Point.prototype.add; - -},{"../../elliptic":58,"../curve":61,"assert":89,"bn.js":56,"inherits":78}],61:[function(require,module,exports){ -var curve = exports; - -curve.base = require('./base'); -curve.short = require('./short'); -curve.mont = require('./mont'); -curve.edwards = require('./edwards'); - -},{"./base":59,"./edwards":60,"./mont":62,"./short":63}],62:[function(require,module,exports){ -var assert = require('assert'); -var curve = require('../curve'); -var elliptic = require('../../elliptic'); -var bn = require('bn.js'); -var inherits = require('inherits'); -var Base = curve.base; - -var getNAF = elliptic.utils.getNAF; - -function MontCurve(conf) { - Base.call(this, 'mont', conf); - - this.a = new bn(conf.a, 16).toRed(this.red); - this.b = new bn(conf.b, 16).toRed(this.red); - this.i4 = new bn(4).toRed(this.red).redInvm(); - this.two = new bn(2).toRed(this.red); - this.a24 = this.i4.redMul(this.a.redAdd(this.two)); -} -inherits(MontCurve, Base); -module.exports = MontCurve; - -MontCurve.prototype.point = function point(x, z) { - return new Point(this, x, z); +Transaction.prototype.fromString = function(string) { + this.fromBuffer(new buffer.Buffer(string, 'hex')); }; -MontCurve.prototype.pointFromJSON = function pointFromJSON(obj) { - return Point.fromJSON(this, obj); -} +Transaction.prototype._newTransaction = function() { + this.version = CURRENT_VERSION; + this.nLockTime = DEFAULT_NLOCKTIME; +}; -MontCurve.prototype.validate = function validate(point) { - var x = point.normalize().x; - var x2 = x.redSqr(); - var rhs = x2.redMul(x).redAdd(x2.redMul(this.a)).redAdd(x); - var y = rhs.redSqrt(); +/* Transaction creation interface */ - return y.redSqr().cmp(rhs) === 0; +/** + * Add an input to this transaction. This is a high level interface + * to add an input, for more control, use @{link Transaction#addInput}. + * + * Can receive, as output information, the output of bitcoind's `listunspent` command, + * and a slightly fancier format recognized by bitcore: + * + * ``` + * { + * address: 'mszYqVnqKoQx4jcTdJXxwKAissE3Jbrrc1', + * txId: 'a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458', + * outputIndex: 0, + * script: Script.empty(), + * satoshis: 1020000 + * } + * ``` + * Where `address` can be either a string or a bitcore Address object. The + * same is true for `script`, which can be a string or a bitcore Script. + * + * Beware that this resets all the signatures for inputs (in further versions, + * SIGHASH_SINGLE or SIGHASH_NONE signatures will not be reset). + * + * @example + * ```javascript + * var transaction = new Transaction(); + * + * // From a pay to public key hash output from bitcoind's listunspent + * transaction.from({'txid': '0000...', vout: 0, amount: 0.1, scriptPubKey: 'OP_DUP ...'}); + * + * // From a pay to public key hash output + * transaction.from({'txId': '0000...', outputIndex: 0, satoshis: 1000, script: 'OP_DUP ...'}); + * + * // From a multisig P2SH output + * transaction.from({'txId': '0000...', inputIndex: 0, satoshis: 1000, script: '... OP_HASH'}, + * ['03000...', '02000...'], 2); + * ``` + * + * @param {Object} utxo + * @param {Array=} pubkeys + * @param {number=} threshold + */ +Transaction.prototype.from = function(utxo, pubkeys, threshold) { + if (_.isArray(utxo)) { + var self = this; + _.each(utxo, function(utxo) { + self.from(utxo, pubkeys, threshold); + }); + return this; + } + var exists = _.any(this.inputs, function(input) { + // TODO: Maybe prevTxId should be a string? Or defined as read only property? + return input.prevTxId.toString('hex') === utxo.txId && input.outputIndex === utxo.outputIndex; + }); + if (exists) { + return; + } + if (pubkeys && threshold) { + this._fromMultisigUtxo(utxo, pubkeys, threshold); + } else { + this._fromNonP2SH(utxo); + } + return this; }; -function Point(curve, x, z) { - Base.BasePoint.call(this, curve, 'projective'); - if (x === null && z === null) { - this.x = this.curve.one; - this.z = this.curve.zero; +Transaction.prototype._fromNonP2SH = function(utxo) { + var clazz; + utxo = new UnspentOutput(utxo); + if (utxo.script.isPublicKeyHashOut()) { + clazz = PublicKeyHashInput; } else { - this.x = new bn(x, 16); - this.z = new bn(z, 16); - if (!this.x.red) - this.x = this.x.toRed(this.curve.red); - if (!this.z.red) - this.z = this.z.toRed(this.curve.red); + clazz = Input; } -} -inherits(Point, Base.BasePoint); - -Point.prototype.precompute = function precompute() { - // No-op + this.addInput(new clazz({ + output: new Output({ + script: utxo.script, + satoshis: utxo.satoshis + }), + prevTxId: utxo.txId, + outputIndex: utxo.outputIndex, + sequenceNumber: DEFAULT_SEQNUMBER, + script: Script.empty() + })); }; -Point.fromJSON = function fromJSON(curve, obj) { - return new Point(curve, obj[0], obj[1] || curve.one); +Transaction.prototype._fromMultisigUtxo = function(utxo, pubkeys, threshold) { + $.checkArgument(threshold <= pubkeys.length, + 'Number of required signatures must be greater than the number of public keys'); + utxo = new UnspentOutput(utxo); + this.addInput(new MultiSigScriptHashInput({ + output: new Output({ + script: utxo.script, + satoshis: utxo.satoshis + }), + prevTxId: utxo.txId, + outputIndex: utxo.outputIndex, + sequenceNumber: DEFAULT_SEQNUMBER, + script: Script.empty() + }, pubkeys, threshold)); }; -Point.prototype.inspect = function inspect() { - if (this.isInfinity()) - return ''; - return ''; +/** + * Add an input to this transaction. The input must be an instance of the `Input` class. + * It should have information about the Output that it's spending, but if it's not already + * set, two additional parameters, `outputScript` and `satoshis` can be provided. + * + * @param {Input} input + * @param {String|Script} outputScript + * @param {number} satoshis + * @return Transaction this, for chaining + */ +Transaction.prototype.addInput = function(input, outputScript, satoshis) { + $.checkArgumentType(input, Input, 'input'); + if (!input.output && (_.isUndefined(outputScript) || _.isUndefined(satoshis))) { + throw new errors.Transaction.NeedMoreInfo('Need information about the UTXO script and satoshis'); + } + if (!input.output && outputScript && !_.isUndefined(satoshis)) { + outputScript = outputScript instanceof Script ? outputScript : new Script(outputScript); + $.checkArgumentType(satoshis, 'number', 'satoshis'); + input.output = new Output({ + script: outputScript, + satoshis: satoshis + }); + } + return this.uncheckedAddInput(input); }; -Point.prototype.isInfinity = function isInfinity() { - // XXX This code assumes that zero is always zero in red - return this.z.cmpn(0) === 0; +/** + * Add an input to this transaction, without checking that the input has information about + * the output that it's spending. + * + * @param {Input} input + * @return Transaction this, for chaining + */ +Transaction.prototype.uncheckedAddInput = function(input) { + $.checkArgumentType(input, Input, 'input'); + this.inputs.push(input); + if (input.output) { + this._inputAmount += input.output.satoshis; + } + this._updateChangeOutput(); + return this; }; -Point.prototype.dbl = function dbl() { - // http://hyperelliptic.org/EFD/g1p/auto-montgom-xz.html#doubling-dbl-1987-m-3 - // 2M + 2S + 4A - - // A = X1 + Z1 - var a = this.x.redAdd(this.z); - // AA = A^2 - var aa = a.redSqr(); - // B = X1 - Z1 - var b = this.x.redSub(this.z); - // BB = B^2 - var bb = b.redSqr(); - // C = AA - BB - var c = aa.redSub(bb); - // X3 = AA * BB - var nx = aa.redMul(bb); - // Z3 = C * (BB + A24 * C) - var nz = c.redMul(bb.redAdd(this.curve.a24.redMul(c))); - return this.curve.point(nx, nz); +/** + * Returns true if the transaction has enough info on all inputs to be correctly validated + * + * @return {boolean} + */ +Transaction.prototype.hasAllUtxoInfo = function() { + return _.all(this.inputs.map(function(input) { + return !!input.output; + })); }; -Point.prototype.add = function add(p) { - throw new Error('Not supported on Montgomery curve'); +/** + * Manually set the fee for this transaction. Beware that this resets all the signatures + * for inputs (in further versions, SIGHASH_SINGLE or SIGHASH_NONE signatures will not + * be reset). + * + * @param {number} amount satoshis to be sent + * @return {Transaction} this, for chaining + */ +Transaction.prototype.fee = function(amount) { + this._fee = amount; + this._updateChangeOutput(); + return this; }; -Point.prototype.diffAdd = function diffAdd(p, diff) { - // http://hyperelliptic.org/EFD/g1p/auto-montgom-xz.html#diffadd-dadd-1987-m-3 - // 4M + 2S + 6A +/* Output management */ - // A = X2 + Z2 - var a = this.x.redAdd(this.z); - // B = X2 - Z2 - var b = this.x.redSub(this.z); - // C = X3 + Z3 - var c = p.x.redAdd(p.z); - // D = X3 - Z3 - var d = p.x.redSub(p.z); - // DA = D * A - var da = d.redMul(a); - // CB = C * B - var cb = c.redMul(b); - // X5 = Z1 * (DA + CB)^2 - var nx = diff.z.redMul(da.redAdd(cb).redSqr()); - // Z5 = X1 * (DA - CB)^2 - var nz = diff.x.redMul(da.redISub(cb).redSqr()); - return this.curve.point(nx, nz); +/** + * Set the change address for this transaction + * + * Beware that this resets all the signatures for inputs (in further versions, + * SIGHASH_SINGLE or SIGHASH_NONE signatures will not be reset). + * + * @param {address} An address for change to be sent to. + * @return {Transaction} this, for chaining + */ +Transaction.prototype.change = function(address) { + this._changeScript = Script.fromAddress(address); + this._updateChangeOutput(); + return this; }; -Point.prototype.mul = function mul(k) { - var t = k.clone(); - var a = this; // (N / 2) * Q + Q - var b = this.curve.point(null, null); // (N / 2) * Q - var c = this; // Q - - for (var bits = []; t.cmpn(0) !== 0; t.ishrn(1)) - bits.push(t.andln(1)); - for (var i = bits.length - 1; i >= 0; i--) { - if (bits[i] === 0) { - // N * Q + Q = ((N / 2) * Q + Q)) + (N / 2) * Q - a = a.diffAdd(b, c); - // N * Q = 2 * ((N / 2) * Q + Q)) - b = b.dbl(); - } else { - // N * Q = ((N / 2) * Q + Q) + ((N / 2) * Q) - b = a.diffAdd(b, c); - // N * Q + Q = 2 * ((N / 2) * Q + Q) - a = a.dbl(); - } +/** + * @return {Output} change output, if it exists + */ +Transaction.prototype.getChangeOutput = function() { + if (!_.isUndefined(this._changeIndex)) { + return this.outputs[this._changeIndex]; } - return b; + return null; }; -Point.prototype.mulAdd = function mulAdd() { - throw new Error('Not supported on Montgomery curve'); +/** + * Add an output to the transaction. + * + * Beware that this resets all the signatures for inputs (in further versions, + * SIGHASH_SINGLE or SIGHASH_NONE signatures will not be reset). + * + * @param {string|Address} address + * @param {number} amount in satoshis + * @return {Transaction} this, for chaining + */ +Transaction.prototype.to = function(address, amount) { + this.addOutput(new Output({ + script: Script(new Address(address)), + satoshis: amount + })); + return this; }; -Point.prototype.normalize = function normalize() { - this.x = this.x.redMul(this.z.redInvm()); - this.z = this.curve.one; +/** + * Add an OP_RETURN output to the transaction. + * + * Beware that this resets all the signatures for inputs (in further versions, + * SIGHASH_SINGLE or SIGHASH_NONE signatures will not be reset). + * + * @param {Buffer|string} value the data to be stored in the OP_RETURN output. + * In case of a string, the UTF-8 representation will be stored + * @return {Transaction} this, for chaining + */ +Transaction.prototype.addData = function(value) { + this.addOutput(new Output({ + script: Script.buildDataOut(value), + satoshis: 0 + })); return this; }; -Point.prototype.getX = function getX() { - // Normalize coordinates - this.normalize(); - - return this.x.fromRed(); +Transaction.prototype.addOutput = function(output) { + $.checkArgumentType(output, Output, 'output'); + this._addOutput(output); + this._updateChangeOutput(); }; -},{"../../elliptic":58,"../curve":61,"assert":89,"bn.js":56,"inherits":78}],63:[function(require,module,exports){ -var assert = require('assert'); -var curve = require('../curve'); -var elliptic = require('../../elliptic'); -var bn = require('bn.js'); -var inherits = require('inherits'); -var Base = curve.base; - -var getNAF = elliptic.utils.getNAF; - -function ShortCurve(conf) { - Base.call(this, 'short', conf); - - this.a = new bn(conf.a, 16).toRed(this.red); - this.b = new bn(conf.b, 16).toRed(this.red); - this.tinv = this.two.redInvm(); - - this.zeroA = this.a.fromRed().cmpn(0) === 0; - this.threeA = this.a.fromRed().sub(this.p).cmpn(-3) === 0; - - // If the curve is endomorphic, precalculate beta and lambda - this.endo = this._getEndomorphism(conf); - this._endoWnafT1 = new Array(4); - this._endoWnafT2 = new Array(4); -} -inherits(ShortCurve, Base); -module.exports = ShortCurve; +Transaction.prototype._addOutput = function(output) { + this.outputs.push(output); + this._outputAmount += output.satoshis; +}; -ShortCurve.prototype._getEndomorphism = function _getEndomorphism(conf) { - // No efficient endomorphism - if (!this.zeroA || !this.g || !this.n || this.p.modn(3) !== 1) +Transaction.prototype._updateChangeOutput = function() { + if (!this._changeScript) { return; - - // Compute beta and lambda, that lambda * P = (beta * Px; Py) - var beta; - var lambda; - if (conf.beta) { - beta = new bn(conf.beta, 16).toRed(this.red); - } else { - var betas = this._getEndoRoots(this.p); - // Choose the smallest beta - beta = betas[0].cmp(betas[1]) < 0 ? betas[0] : betas[1]; - beta = beta.toRed(this.red); } - if (conf.lambda) { - lambda = new bn(conf.lambda, 16); - } else { - // Choose the lambda that is matching selected beta - var lambdas = this._getEndoRoots(this.n); - if (this.g.mul(lambdas[0]).x.cmp(this.g.x.redMul(beta)) === 0) { - lambda = lambdas[0]; - } else { - lambda = lambdas[1]; - assert(this.g.mul(lambda).x.cmp(this.g.x.redMul(beta)) === 0); - } + this._clearSignatures(); + if (!_.isUndefined(this._changeIndex)) { + this._removeOutput(this._changeIndex); } - - // Get basis vectors, used for balanced length-two representation - var basis; - if (conf.basis) { - basis = conf.basis.map(function(vec) { - return { - a: new bn(vec.a, 16), - b: new bn(vec.b, 16), - }; - }); + var available = this._getUnspentValue(); + var fee = this.getFee(); + var changeAmount = available - fee; + if (changeAmount > 0) { + this._changeIndex = this.outputs.length; + this._addOutput(new Output({ + script: this._changeScript, + satoshis: changeAmount + })); } else { - basis = this._getEndoBasis(lambda); + this._changeIndex = undefined; } - - return { - beta: beta, - lambda: lambda, - basis: basis - }; +}; +/** + * Calculates the fees for the transaction. + * + * If there is no change output set, the fee will be the + * output amount minus the input amount. + * If there's a fixed fee set, return that + * If there's no fee set, estimate it based on size + * @return {Number} miner fee for this transaction in satoshis + */ +Transaction.prototype.getFee = function() { + // if no change output is set, fees should equal all the unspent amount + if (!this._changeScript) { + return this._getUnspentValue(); + } + return _.isUndefined(this._fee) ? this._estimateFee() : this._fee; }; -ShortCurve.prototype._getEndoRoots = function _getEndoRoots(num) { - // Find roots of for x^2 + x + 1 in F - // Root = (-1 +- Sqrt(-3)) / 2 - // - var red = num === this.p ? this.red : bn.mont(num); - var tinv = new bn(2).toRed(red).redInvm(); - var ntinv = tinv.redNeg(); - var one = new bn(1).toRed(red); - - var s = new bn(3).toRed(red).redNeg().redSqrt().redMul(tinv); +/** + * Estimates fee from serialized transaction size in bytes. + */ +Transaction.prototype._estimateFee = function() { + var estimatedSize = this._estimateSize(); + var available = this._getUnspentValue(); + return Transaction._estimateFee(estimatedSize, available); +}; - var l1 = ntinv.redAdd(s).fromRed(); - var l2 = ntinv.redSub(s).fromRed(); - return [ l1, l2 ]; +Transaction.prototype._getUnspentValue = function() { + return this._inputAmount - this._outputAmount; }; -ShortCurve.prototype._getEndoBasis = function _getEndoBasis(lambda) { - // aprxSqrt >= sqrt(this.n) - var aprxSqrt = this.n.shrn(Math.floor(this.n.bitLength() / 2)); +Transaction.prototype._clearSignatures = function() { + _.each(this.inputs, function(input) { + input.clearSignatures(); + }); +}; - // 3.74 - // Run EGCD, until r(L + 1) < aprxSqrt - var u = lambda; - var v = this.n.clone(); - var x1 = new bn(1); - var y1 = new bn(0); - var x2 = new bn(0); - var y2 = new bn(1); +Transaction.FEE_PER_KB = 10000; +// Safe upper bound for change address script +Transaction.CHANGE_OUTPUT_MAX_SIZE = 20 + 4 + 34 + 4; - // NOTE: all vectors are roots of: a + b * lambda = 0 (mod n) - var a0; - var b0; - // First vector - var a1; - var b1; - // Second vector - var a2; - var b2; +Transaction._estimateFee = function(size, amountAvailable) { + var fee = Math.ceil(size / Transaction.FEE_PER_KB); + if (amountAvailable > fee) { + size += Transaction.CHANGE_OUTPUT_MAX_SIZE; + } + return Math.ceil(size / 1000) * Transaction.FEE_PER_KB; +}; - var prevR; - var i = 0; - while (u.cmpn(0) !== 0) { - var q = v.div(u); - var r = v.sub(q.mul(u)); - var x = x2.sub(q.mul(x1)); - var y = y2.sub(q.mul(y1)); +Transaction.MAXIMUM_EXTRA_SIZE = 4 + 9 + 9 + 4; - if (!a1 && r.cmp(aprxSqrt) < 0) { - a0 = prevR.neg(); - b0 = x1; - a1 = r.neg(); - b1 = x; - } else if (a1 && ++i === 2) { - break; - } - prevR = r; +Transaction.prototype._estimateSize = function() { + var result = Transaction.MAXIMUM_EXTRA_SIZE; + _.each(this.inputs, function(input) { + result += input._estimateSize(); + }); + _.each(this.outputs, function(output) { + result += output.script.toBuffer().length + 9; + }); + return result; +}; - v = u; - u = r; - x2 = x1; - x1 = x; - y2 = y1; - y1 = y; - } - a2 = r.neg(); - b2 = x; +Transaction.prototype._removeOutput = function(index) { + var output = this.outputs[index]; + this._outputAmount -= output.satoshis; + this.outputs = _.without(this.outputs, output); +}; - var len1 = a1.sqr().add(b1.sqr()); - var len2 = a2.sqr().add(b2.sqr()); - if (len2.cmp(len1) >= 0) { - a2 = a0; - b2 = b0; - } +Transaction.prototype.removeOutput = function(index) { + this._removeOutput(index); + this._updateChangeOutput(); +}; - // Normalize signs - if (a1.sign) { - a1 = a1.neg(); - b1 = b1.neg(); +Transaction.prototype.removeInput = function(txId, outputIndex) { + var index; + if (!outputIndex && _.isNumber(txId)) { + index = txId; + } else { + index = _.findIndex(this.inputs, function(input) { + return input.prevTxId.toString('hex') === txId && input.outputIndex === outputIndex; + }); } - if (a2.sign) { - a2 = a2.neg(); - b2 = b2.neg(); + if (index < 0 || index >= this.inputs.length) { + throw new errors.Transaction.InvalidIndex(index, this.inputs.length); } - - return [ - { a: a1, b: b1 }, - { a: a2, b: b2 } - ]; + var input = this.inputs[index]; + this._inputAmount -= input.output.satoshis; + this.inputs = _.without(this.inputs, input); + this._updateChangeOutput(); }; -ShortCurve.prototype._endoSplit = function _endoSplit(k) { - var basis = this.endo.basis; - var v1 = basis[0]; - var v2 = basis[1]; - - var c1 = v2.b.mul(k).divRound(this.n); - var c2 = v1.b.neg().mul(k).divRound(this.n); - - var p1 = c1.mul(v1.a); - var p2 = c2.mul(v2.a); - var q1 = c1.mul(v1.b); - var q2 = c2.mul(v2.b); +/* Signature handling */ - // Calculate answer - var k1 = k.sub(p1).sub(p2); - var k2 = q1.add(q2).neg(); - return { k1: k1, k2: k2 }; +/** + * Sign the transaction using one or more private keys. + * + * It tries to sign each input, verifying that the signature will be valid + * (matches a public key). + * + * @param {Array|String|PrivateKey} privateKey + * @param {number} sigtype + * @return {Transaction} this, for chaining + */ +Transaction.prototype.sign = function(privateKey, sigtype) { + $.checkState(this.hasAllUtxoInfo()); + var self = this; + if (_.isArray(privateKey)) { + _.each(privateKey, function(privateKey) { + self.sign(privateKey, sigtype); + }); + return this; + } + _.each(this.getSignatures(privateKey, sigtype), function(signature) { + self.applySignature(signature); + }); + return this; }; -ShortCurve.prototype.point = function point(x, y, isRed) { - return new Point(this, x, y, isRed); +Transaction.prototype.getSignatures = function(privKey, sigtype) { + privKey = new PrivateKey(privKey); + sigtype = sigtype || Signature.SIGHASH_ALL; + var transaction = this; + var results = []; + var hashData = Hash.sha256ripemd160(privKey.publicKey.toBuffer()); + _.each(this.inputs, function forEachInput(input, index) { + _.each(input.getSignatures(transaction, privKey, index, sigtype, hashData), function(signature) { + results.push(signature); + }); + }); + return results; }; -ShortCurve.prototype.pointFromX = function pointFromX(odd, x) { - x = new bn(x, 16); - if (!x.red) - x = x.toRed(this.red); - - var y2 = x.redSqr().redMul(x).redIAdd(x.redMul(this.a)).redIAdd(this.b); - var y = y2.redSqrt(); - - // XXX Is there any way to tell if the number is odd without converting it - // to non-red form? - var isOdd = y.fromRed().isOdd(); - if (odd && !isOdd || !odd && isOdd) - y = y.redNeg(); - - return this.point(x, y); +/** + * Add a signature to the transaction + * + * @param {Object} signature + * @param {number} signature.inputIndex + * @param {number} signature.sigtype + * @param {PublicKey} signature.publicKey + * @param {Signature} signature.signature + * @return {Transaction} this, for chaining + */ +Transaction.prototype.applySignature = function(signature) { + this.inputs[signature.inputIndex].addSignature(this, signature); + return this; }; -ShortCurve.prototype.jpoint = function jpoint(x, y, z) { - return new JPoint(this, x, y, z); +Transaction.prototype.isFullySigned = function() { + _.each(this.inputs, function(input) { + if (input.isFullySigned === Input.prototype.isFullySigned) { + throw new errors.Transaction.UnableToVerifySignature( + 'Unrecognized script kind, or not enough information to execute script.' + + 'This usually happens when creating a transaction from a serialized transaction' + ); + } + }); + return _.all(_.map(this.inputs, function(input) { + return input.isFullySigned(); + })); }; -ShortCurve.prototype.pointFromJSON = function pointFromJSON(obj, red) { - return Point.fromJSON(this, obj, red); +Transaction.prototype.isValidSignature = function(signature) { + var self = this; + if (this.inputs[signature.inputIndex].isValidSignature === Input.prototype.isValidSignature) { + throw new errors.Transaction.UnableToVerifySignature( + 'Unrecognized script kind, or not enough information to execute script.' + + 'This usually happens when creating a transaction from a serialized transaction' + ); + } + return this.inputs[signature.inputIndex].isValidSignature(self, signature); }; -ShortCurve.prototype.validate = function validate(point) { - if (point.inf) - return true; +/** + * @returns {bool} whether the signature is valid for this transaction input + */ +Transaction.prototype.verifySignature = function(sig, pubkey, nin, subscript) { + return Sighash.verify(this, sig, pubkey, nin, subscript); +}; - var x = point.x; - var y = point.y; +/** + * Check that a transaction passes basic sanity tests. If not, return a string + * describing the error. This function contains the same logic as + * CheckTransaction in bitcoin core. + */ +Transaction.prototype.verify = function() { + // Basic checks that don't depend on any context + if (this.inputs.length === 0) { + return 'transaction txins empty'; + } - var ax = this.a.redMul(x); - var rhs = x.redSqr().redMul(x).redIAdd(ax).redIAdd(this.b); - return y.redSqr().redISub(rhs).cmpn(0) === 0; -}; + if (this.outputs.length === 0) { + return 'transaction txouts empty'; + } -ShortCurve.prototype._endoWnafMulAdd = function _endoWnafMulAdd(points, coeffs) { - var npoints = this._endoWnafT1; - var ncoeffs = this._endoWnafT2; - for (var i = 0; i < points.length; i++) { - var split = this._endoSplit(coeffs[i]); - var p = points[i]; - var beta = p._getBeta(); + // Size limits + if (this.toBuffer().length > Block.MAX_BLOCK_SIZE) { + return 'transaction over the maximum block size'; + } - if (split.k1.sign) { - split.k1.sign = !split.k1.sign; - p = p.neg(true); + // Check for negative or overflow output values + var valueoutbn = new BN(0); + for (var i = 0; i < this.outputs.length; i++) { + var txout = this.outputs[i]; + var valuebn = txout._satoshisBN; + if (valuebn.lt(BN.Zero)) { + return 'transaction txout ' + i + ' negative'; } - if (split.k2.sign) { - split.k2.sign = !split.k2.sign; - beta = beta.neg(true); + if (valuebn.gt(new BN(Transaction.MAX_MONEY, 10))) { + return 'transaction txout ' + i + ' greater than MAX_MONEY'; + } + valueoutbn = valueoutbn.add(valuebn); + if (valueoutbn.gt(new BN(Transaction.MAX_MONEY))) { + return 'transaction txout ' + i + ' total output greater than MAX_MONEY'; } - - npoints[i * 2] = p; - npoints[i * 2 + 1] = beta; - ncoeffs[i * 2] = split.k1; - ncoeffs[i * 2 + 1] = split.k2; } - var res = this._wnafMulAdd(1, npoints, ncoeffs, i * 2); - // Clean-up references to points and coefficients - for (var j = 0; j < i * 2; j++) { - npoints[j] = null; - ncoeffs[j] = null; + // Check for duplicate inputs + var txinmap = {}; + for (i = 0; i < this.inputs.length; i++) { + var txin = this.inputs[i]; + + var inputid = txin.prevTxId + ':' + txin.outputIndex; + if (!_.isUndefined(txinmap[inputid])) { + return 'transaction input ' + i + ' duplicate input'; + } + txinmap[inputid] = true; } - return res; -}; -function Point(curve, x, y, isRed) { - Base.BasePoint.call(this, curve, 'affine'); - if (x === null && y === null) { - this.x = null; - this.y = null; - this.inf = true; + var isCoinbase = this.isCoinbase(); + if (isCoinbase) { + var buf = this.inputs[0]._script.toBuffer(); + if (buf.length < 2 || buf.length > 100) { + return 'coinbase trasaction script size invalid'; + } } else { - this.x = new bn(x, 16); - this.y = new bn(y, 16); - // Force redgomery representation when loading from JSON - if (isRed) { - this.x.forceRed(this.curve.red); - this.y.forceRed(this.curve.red); + for (i = 0; i < this.inputs.length; i++) { + if (this.inputs[i].isNull()) { + return 'tranasction input ' + i + ' has null input'; + } } - if (!this.x.red) - this.x = this.x.toRed(this.curve.red); - if (!this.y.red) - this.y = this.y.toRed(this.curve.red); - this.inf = false; } -} -inherits(Point, Base.BasePoint); + return true; +}; -Point.prototype._getBeta = function _getBeta() { - if (!this.curve.endo) - return; +/** + * Analagous to bitcoind's IsCoinBase function in transaction.h + */ +Transaction.prototype.isCoinbase = function() { + return (this.inputs.length === 1 && this.inputs[0].isNull()); +}; - var pre = this.precomputed; - if (pre && pre.beta) - return pre.beta; - var beta = this.curve.point(this.x.redMul(this.curve.endo.beta), this.y); - if (pre) { - var curve = this.curve; - function endoMul(p) { - return curve.point(p.x.redMul(curve.endo.beta), p.y); - } - pre.beta = beta; - beta.precomputed = { - beta: null, - naf: pre.naf && { - wnd: pre.naf.wnd, - points: pre.naf.points.map(endoMul) - }, - doubles: pre.doubles && { - step: pre.doubles.step, - points: pre.doubles.points.map(endoMul) - } - }; - } - return beta; -}; +module.exports = Transaction; -Point.prototype.toJSON = function toJSON() { - if (!this.precomputed) - return [ this.x, this.y ]; +},{"../address":31,"../block":32,"../crypto/bn":34,"../crypto/hash":36,"../crypto/signature":39,"../encoding/bufferreader":42,"../encoding/bufferwriter":43,"../errors":45,"../privatekey":52,"../script":54,"../util/buffer":69,"../util/js":70,"../util/preconditions":71,"./input":58,"./output":62,"./sighash":63,"./unspentoutput":66,"buffer":209,"lodash":95}],66:[function(require,module,exports){ +'use strict'; - return [ this.x, this.y, this.precomputed && { - doubles: this.precomputed.doubles && { - step: this.precomputed.doubles.step, - points: this.precomputed.doubles.points.slice(1) - }, - naf: this.precomputed.naf && { - wnd: this.precomputed.naf.wnd, - points: this.precomputed.naf.points.slice(1) - } - }]; -}; +var _ = require('lodash'); +var $ = require('../util/preconditions'); +var JSUtil = require('../util/js'); -Point.fromJSON = function fromJSON(curve, obj, red) { - if (typeof obj === 'string') - obj = JSON.parse(obj); - var res = curve.point(obj[0], obj[1], red); - if (!obj[2]) - return res; +var Script = require('../script'); +var Address = require('../address'); +var Unit = require('../unit'); - function obj2point(obj) { - return curve.point(obj[0], obj[1], red); +/** + * Represents an unspent output information: its script, associated amount and address, + * transaction id and output index. + * + * @constructor + * @param {object} data + * @param {string} data.txid the previous transaction id + * @param {string=} data.txId alias for `txid` + * @param {number} data.vout the index in the transaction + * @param {number=} data.outputIndex alias for `vout` + * @param {string|Script} data.scriptPubKey the script that must be resolved to release the funds + * @param {string|Script=} data.script alias for `scriptPubKey` + * @param {number} data.amount amount of bitcoins associated + * @param {number=} data.satoshis alias for `amount`, but expressed in satoshis (1 BTC = 1e8 satoshis) + * @param {string|Address=} data.address the associated address to the script, if provided + */ +function UnspentOutput(data) { + /* jshint maxcomplexity: 20 */ + /* jshint maxstatements: 20 */ + if (!(this instanceof UnspentOutput)) { + return new UnspentOutput(data); + } + $.checkArgument(_.isObject(data), 'Must provide an object from where to extract data'); + var address = data.address ? new Address(data.address) : undefined; + var txId = data.txid ? data.txid : data.txId; + if (!txId || !JSUtil.isHexaString(txId) || txId.length > 64) { + // TODO: Use the errors library + throw new Error('Invalid TXID in object', data); + } + var outputIndex = _.isUndefined(data.vout) ? data.outputIndex : data.vout; + if (!_.isNumber(outputIndex)) { + throw new Error('Invalid outputIndex, received ' + outputIndex); } + $.checkArgument(!_.isUndefined(data.scriptPubKey) || !_.isUndefined(data.script), + 'Must provide the scriptPubKey for that output!'); + var script = new Script(data.scriptPubKey || data.script); + $.checkArgument(!_.isUndefined(data.amount) || !_.isUndefined(data.satoshis), + 'Must provide an amount for the output'); + var amount = !_.isUndefined(data.amount) ? new Unit.fromBTC(data.amount).toSatoshis() : data.satoshis; + $.checkArgument(_.isNumber(amount), 'Amount must be a number'); + JSUtil.defineImmutable(this, { + address: address, + txId: txId, + outputIndex: outputIndex, + script: script, + satoshis: amount + }); +} - var pre = obj[2]; - res.precomputed = { - beta: null, - doubles: pre.doubles && { - step: pre.doubles.step, - points: [ res ].concat(pre.doubles.points.map(obj2point)) - }, - naf: pre.naf && { - wnd: pre.naf.wnd, - points: [ res ].concat(pre.naf.points.map(obj2point)) - } - }; - return res; +/** + * Provide an informative output when displaying this object in the console + * @returns string + */ +UnspentOutput.prototype.inspect = function() { + return ''; }; -Point.prototype.inspect = function inspect() { - if (this.isInfinity()) - return ''; - return ''; +/** + * String representation: just "txid:index" + * @returns string + */ +UnspentOutput.prototype.toString = function() { + return this.txId + ':' + this.outputIndex; }; -Point.prototype.isInfinity = function isInfinity() { - return this.inf; +/** + * Deserialize an UnspentOutput from an object or JSON string + * @param {object|string} data + * @return UnspentOutput + */ +UnspentOutput.fromJSON = UnspentOutput.fromObject = function(data) { + if (JSUtil.isValidJSON(data)) { + data = JSON.parse(data); + } + return new UnspentOutput(data); }; -Point.prototype.add = function add(p) { - // O + P = P - if (this.inf) - return p; +/** + * Retrieve a string representation of this object + * @return {string} + */ +UnspentOutput.prototype.toJSON = function() { + return JSON.stringify(this.toObject()); +}; - // P + O = P - if (p.inf) - return this; +/** + * Returns a plain object (no prototype or methods) with the associated infor for this output + * @return {object} + */ +UnspentOutput.prototype.toObject = function() { + return { + address: this.address ? this.address.toString() : undefined, + txid: this.txId, + vout: this.outputIndex, + scriptPubKey: this.script.toBuffer().toString('hex'), + amount: Unit.fromSatoshis(this.satoshis).toBTC() + }; +}; - // P + P = 2P - if (this.eq(p)) - return this.dbl(); +module.exports = UnspentOutput; - // P + (-P) = O - if (this.neg().eq(p)) - return this.curve.point(null, null); +},{"../address":31,"../script":54,"../unit":67,"../util/js":70,"../util/preconditions":71,"lodash":95}],67:[function(require,module,exports){ +'use strict'; - // P + Q = O - if (this.x.cmp(p.x) === 0) - return this.curve.point(null, null); +var _ = require('lodash'); - var c = this.y.redSub(p.y); - if (c.cmpn(0) !== 0) - c = c.redMul(this.x.redSub(p.x).redInvm()); - var nx = c.redSqr().redISub(this.x).redISub(p.x); - var ny = c.redMul(this.x.redSub(nx)).redISub(this.y); - return this.curve.point(nx, ny); +var errors = require('./errors'); +var JSUtil = require('./util/js'); + +var UNITS = { + 'BTC' : [1e8, 8], + 'mBTC' : [1e5, 5], + 'uBTC' : [1e2, 2], + 'bits' : [1e2, 2], + 'satoshis' : [1, 0] }; -Point.prototype.dbl = function dbl() { - if (this.inf) - return this; +/** + * Utility for handling and converting bitcoins units. The supported units are + * BTC, mBTC, bits (also named uBTC) and satoshis. A unit instance can be created with an + * amount and a unit code, or alternatively using static methods like {fromBTC}. + * It also allows to be created from a fiat amount and the exchange rate, or + * alternatively using the {fromFiat} static method. + * You can consult for different representation of a unit instance using it's + * {to} method, the fixed unit methods like {toSatoshis} or alternatively using + * the unit accessors. It also can be converted to a fiat amount by providing the + * corresponding BTC/fiat exchange rate. + * + * @example + * ```javascript + * var sats = Unit.fromBTC(1.3).toSatoshis(); + * var mili = Unit.fromBits(1.3).to(Unit.mBTC); + * var bits = Unit.fromFiat(1.3, 350).bits; + * var btc = new Unit(1.3, Unit.bits).BTC; + * ``` + * + * @param {Number} amount - The amount to be represented + * @param {String|Number} code - The unit of the amount or the exchange rate + * @returns {Unit} A new instance of an Unit + * @constructor + */ +function Unit(amount, code) { + if (!(this instanceof Unit)) { + return new Unit(amount, code); + } - // 2P = O - var ys1 = this.y.redAdd(this.y); - if (ys1.cmpn(0) === 0) - return this.curve.point(null, null); + // convert fiat to BTC + if (_.isNumber(code)) { + if (code <= 0) { + throw new errors.Unit.InvalidRate(code); + } + amount = amount / code; + code = Unit.BTC; + } - var a = this.curve.a; + this._value = this._from(amount, code); - var x2 = this.x.redSqr(); - var dyinv = ys1.redInvm(); - var c = x2.redAdd(x2).redIAdd(x2).redIAdd(a).redMul(dyinv); + var self = this; + var defineAccesor = function(key) { + Object.defineProperty(self, key, { + get: function() { return self.to(key); }, + enumerable: true, + }); + }; - var nx = c.redSqr().redISub(this.x.redAdd(this.x)); - var ny = c.redMul(this.x.redSub(nx)).redISub(this.y); - return this.curve.point(nx, ny); -}; + Object.keys(UNITS).forEach(defineAccesor); +} -Point.prototype.getX = function getX() { - return this.x.fromRed(); +Object.keys(UNITS).forEach(function(key) { + Unit[key] = key; +}); + +/** + * Returns a Unit instance created from JSON string or object + * + * @param {String|Object} json - JSON with keys: amount and code + * @returns {Unit} A Unit instance + */ +Unit.fromJSON = function fromJSON(json){ + if (JSUtil.isValidJSON(json)) { + json = JSON.parse(json); + } + return new Unit(json.amount, json.code); }; -Point.prototype.getY = function getY() { - return this.y.fromRed(); +/** + * Returns a Unit instance created from an amount in BTC + * + * @param {Number} amount - The amount in BTC + * @returns {Unit} A Unit instance + */ +Unit.fromBTC = function(amount) { + return new Unit(amount, Unit.BTC); }; -Point.prototype.mul = function mul(k) { - k = new bn(k, 16); +/** + * Returns a Unit instance created from an amount in mBTC + * + * @param {Number} amount - The amount in mBTC + * @returns {Unit} A Unit instance + */ +Unit.fromMilis = function(amount) { + return new Unit(amount, Unit.mBTC); +}; - if (this.precomputed && this.precomputed.doubles) - return this.curve._fixedNafMul(this, k); - else if (this.curve.endo) - return this.curve._endoWnafMulAdd([ this ], [ k ]); - else - return this.curve._wnafMul(this, k); +/** + * Returns a Unit instance created from an amount in bits + * + * @param {Number} amount - The amount in bits + * @returns {Unit} A Unit instance + */ +Unit.fromMicros = Unit.fromBits = function(amount) { + return new Unit(amount, Unit.bits); }; -Point.prototype.mulAdd = function mulAdd(k1, p2, k2) { - var points = [ this, p2 ]; - var coeffs = [ k1, k2 ]; - if (this.curve.endo) - return this.curve._endoWnafMulAdd(points, coeffs); - else - return this.curve._wnafMulAdd(1, points, coeffs, 2); +/** + * Returns a Unit instance created from an amount in satoshis + * + * @param {Number} amount - The amount in satoshis + * @returns {Unit} A Unit instance + */ +Unit.fromSatoshis = function(amount) { + return new Unit(amount, Unit.satoshis); }; -Point.prototype.eq = function eq(p) { - return this === p || - this.inf === p.inf && - (this.inf || this.x.cmp(p.x) === 0 && this.y.cmp(p.y) === 0); +/** + * Returns a Unit instance created from a fiat amount and exchange rate. + * + * @param {Number} amount - The amount in fiat + * @param {Number} rate - The exchange rate BTC/fiat + * @returns {Unit} A Unit instance + */ +Unit.fromFiat = function(amount, rate) { + return new Unit(amount, rate); }; -Point.prototype.neg = function neg(_precompute) { - if (this.inf) - return this; +Unit.prototype._from = function(amount, code) { + if (!UNITS[code]) { + throw new errors.Unit.UnknownCode(code); + } + return parseInt((amount * UNITS[code][0]).toFixed()); +}; - var res = this.curve.point(this.x, this.y.redNeg()); - if (_precompute && this.precomputed) { - var pre = this.precomputed; - function negate(p) { - return p.neg(); +/** + * Returns the value represented in the specified unit + * + * @param {String|Number} code - The unit code or exchange rate + * @returns {Number} The converted value + */ +Unit.prototype.to = function(code) { + if (_.isNumber(code)) { + if (code <= 0) { + throw new errors.Unit.InvalidRate(code); } - res.precomputed = { - naf: pre.naf && { - wnd: pre.naf.wnd, - points: pre.naf.points.map(negate) - }, - doubles: pre.doubles && { - step: pre.doubles.step, - points: pre.doubles.points.map(negate) - } - }; + return parseFloat((this.BTC * code).toFixed(2)); } - return res; + + if (!UNITS[code]) { + throw new errors.Unit.UnknownCode(code); + } + + var value = this._value / UNITS[code][0]; + return parseFloat(value.toFixed(UNITS[code][1])); }; -Point.prototype.toJ = function toJ() { - if (this.inf) - return this.curve.jpoint(null, null, null); +/** + * Returns the value represented in BTC + * + * @returns {Number} The value converted to BTC + */ +Unit.prototype.toBTC = function() { + return this.to(Unit.BTC); +}; - var res = this.curve.jpoint(this.x, this.y, this.curve.one); - return res; +/** + * Returns the value represented in mBTC + * + * @returns {Number} The value converted to mBTC + */ +Unit.prototype.toMilis = function() { + return this.to(Unit.mBTC); }; -function JPoint(curve, x, y, z) { - Base.BasePoint.call(this, curve, 'jacobian'); - if (x === null && y === null && z === null) { - this.x = this.curve.one; - this.y = this.curve.one; - this.z = new bn(0); - } else { - this.x = new bn(x, 16); - this.y = new bn(y, 16); - this.z = new bn(z, 16); - } - if (!this.x.red) - this.x = this.x.toRed(this.curve.red); - if (!this.y.red) - this.y = this.y.toRed(this.curve.red); - if (!this.z.red) - this.z = this.z.toRed(this.curve.red); +/** + * Returns the value represented in bits + * + * @returns {Number} The value converted to bits + */ +Unit.prototype.toMicros = Unit.prototype.toBits = function() { + return this.to(Unit.bits); +}; - this.zOne = this.z === this.curve.one; -} -inherits(JPoint, Base.BasePoint); +/** + * Returns the value represented in satoshis + * + * @returns {Number} The value converted to satoshis + */ +Unit.prototype.toSatoshis = function() { + return this.to(Unit.satoshis); +}; -JPoint.prototype.toP = function toP() { - if (this.isInfinity()) - return this.curve.point(null, null); +/** + * Returns the value represented in fiat + * + * @param {string} rate - The exchange rate between BTC/currency + * @returns {Number} The value converted to satoshis + */ +Unit.prototype.atRate = function(rate) { + return this.to(rate); +}; - var zinv = this.z.redInvm(); - var zinv2 = zinv.redSqr(); - var ax = this.x.redMul(zinv2); - var ay = this.y.redMul(zinv2).redMul(zinv); +/** + * Returns a the string representation of the value in satoshis + * + * @returns {String} the value in satoshis + */ +Unit.prototype.toString = function() { + return this.satoshis + ' satoshis'; +}; - return this.curve.point(ax, ay); +/** + * Returns a plain object representation of the Unit + * + * @returns {Object} An object with the keys: amount and code + */ +Unit.prototype.toObject = function toObject() { + return { + amount: this.BTC, + code: Unit.BTC + }; }; -JPoint.prototype.neg = function neg() { - return this.curve.jpoint(this.x, this.y.redNeg(), this.z); +Unit.prototype.toJSON = function toJSON() { + return JSON.stringify(this.toObject()); }; -JPoint.prototype.add = function add(p) { - // O + P = P - if (this.isInfinity()) - return p; +/** + * Returns a string formatted for the console + * + * @returns {String} the value in satoshis + */ +Unit.prototype.inspect = function() { + return ''; +}; - // P + O = P - if (p.isInfinity()) - return this; +module.exports = Unit; - // 12M + 4S + 7A - var pz2 = p.z.redSqr(); - var z2 = this.z.redSqr(); - var u1 = this.x.redMul(pz2); - var u2 = p.x.redMul(z2); - var s1 = this.y.redMul(pz2.redMul(p.z)); - var s2 = p.y.redMul(z2.redMul(this.z)); +},{"./errors":45,"./util/js":70,"lodash":95}],68:[function(require,module,exports){ +'use strict'; - var h = u1.redSub(u2); - var r = s1.redSub(s2); - if (h.cmpn(0) === 0) { - if (r.cmpn(0) !== 0) - return this.curve.jpoint(null, null, null); - else - return this.dbl(); +var _ = require('lodash'); +var URL = require('url'); + +var Address = require('./address'); +var Unit = require('./unit'); +var JSUtil = require('./util/js'); + +/** + * Bitcore URI + * + * Instantiate an URI from a bitcoin URI String or an Object. An URI instance + * can be created with a bitcoin uri string or an object. All instances of + * URI are valid, the static method isValid allows checking before instanciation. + * + * All standard parameters can be found as members of the class, the address + * is represented using an {Address} instance and the amount is represented in + * satoshis. Any other non-standard parameters can be found under the extra member. + * + * @example + * ```javascript + * + * var uri = new URI('bitcoin:12A1MyfXbW6RhdRAZEqofac5jCQQjwEPBu?amount=1.2'); + * console.log(uri.address, uri.amount); + * ``` + * + * @param {string|Object} data - A bitcoin URI string or an Object + * @param {Array.} [knownParams] - Required non-standard params + * @throws {TypeError} Invalid bitcoin address + * @throws {TypeError} Invalid amount + * @throws {Error} Unknown required argument + * @returns {URI} A new valid and frozen instance of URI + * @constructor + */ +var URI = function(data, knownParams) { + if (!(this instanceof URI)) { + return new URI(data, knownParams); } - var h2 = h.redSqr(); - var h3 = h2.redMul(h); - var v = u1.redMul(h2); + this.extras = {}; + this.knownParams = knownParams || []; + this.address = this.network = this.amount = this.message = null; - var nx = r.redSqr().redIAdd(h3).redISub(v).redISub(v); - var ny = r.redMul(v.redISub(nx)).redISub(s1.redMul(h3)); - var nz = this.z.redMul(p.z).redMul(h); + if (typeof(data) === 'string') { + var params = URI.parse(data); + if (params.amount) { + params.amount = this._parseAmount(params.amount); + } + this._fromObject(params); + } else if (typeof(data) === 'object') { + this._fromObject(data); + } else { + throw new TypeError('Unrecognized data format.'); + } +}; - return this.curve.jpoint(nx, ny, nz); +/** + * Instantiate a URI from a String + * + * @param {String} str - JSON string or object of the URI + * @returns {URI} A new instance of a URI + */ +URI.fromString = function fromString(str) { + if (typeof(str) !== 'string') { + throw new TypeError('Expected a string'); + } + return new URI(str); }; -JPoint.prototype.mixedAdd = function mixedAdd(p) { - // O + P = P - if (this.isInfinity()) - return p.toJ(); +/** + * Instantiate a URI from JSON + * + * @param {String|Object} json - JSON string or object of the URI + * @returns {URI} A new instance of a URI + */ +URI.fromJSON = function fromJSON(json) { + if (JSUtil.isValidJSON(json)) { + json = JSON.parse(json); + } + return new URI(json); +}; - // P + O = P - if (p.isInfinity()) - return this; +/** + * Check if an bitcoin URI string is valid + * + * @example + * ```javascript + * + * var valid = URI.isValid('bitcoin:12A1MyfXbW6RhdRAZEqofac5jCQQjwEPBu'); + * // true + * ``` + * + * @param {string|Object} data - A bitcoin URI string or an Object + * @param {Array.} [knownParams] - Required non-standard params + * @returns {boolean} Result of uri validation + */ +URI.isValid = function(arg, knownParams) { + try { + new URI(arg, knownParams); + } catch (err) { + return false; + } + return true; +}; - // 8M + 3S + 7A - var z2 = this.z.redSqr(); - var u1 = this.x; - var u2 = p.x.redMul(z2); - var s1 = this.y; - var s2 = p.y.redMul(z2).redMul(this.z); +/** + * Convert a bitcoin URI string into a simple object. + * + * @param {string} uri - A bitcoin URI string + * @throws {TypeError} Invalid bitcoin URI + * @returns {Object} An object with the parsed params + */ +URI.parse = function(uri) { + var info = URL.parse(uri, true); - var h = u1.redSub(u2); - var r = s1.redSub(s2); - if (h.cmpn(0) === 0) { - if (r.cmpn(0) !== 0) - return this.curve.jpoint(null, null, null); - else - return this.dbl(); + if (info.protocol !== 'bitcoin:') { + throw new TypeError('Invalid bitcoin URI'); } - var h2 = h.redSqr(); - var h3 = h2.redMul(h); - var v = u1.redMul(h2); - - var nx = r.redSqr().redIAdd(h3).redISub(v).redISub(v); - var ny = r.redMul(v.redISub(nx)).redISub(s1.redMul(h3)); - var nz = this.z.redMul(h); + // workaround to host insensitiveness + var group = /[^:]*:\/?\/?([^?]*)/.exec(uri); + info.query.address = group && group[1] || undefined; - return this.curve.jpoint(nx, ny, nz); + return info.query; }; -JPoint.prototype.dblp = function dblp(pow) { - if (pow === 0) - return this; - if (this.isInfinity()) - return this; - if (!pow) - return this.dbl(); +URI.Members = ['address', 'amount', 'message', 'label', 'r']; - if (this.curve.zeroA || this.curve.threeA) { - var r = this; - for (var i = 0; i < pow; i++) - r = r.dbl(); - return r; - } +/** + * Internal function to load the URI instance with an object. + * + * @param {Object} obj - Object with the information + * @throws {TypeError} Invalid bitcoin address + * @throws {TypeError} Invalid amount + * @throws {Error} Unknown required argument + */ +URI.prototype._fromObject = function(obj) { + /* jshint maxcomplexity: 10 */ - // 1M + 2S + 1A + N * (4S + 5M + 8A) - // N = 1 => 6M + 6S + 9A - var a = this.curve.a; - var tinv = this.curve.tinv; + if (!Address.isValid(obj.address)) { + throw new TypeError('Invalid bitcoin address'); + } - var jx = this.x; - var jy = this.y; - var jz = this.z; - var jz4 = jz.redSqr().redSqr(); + this.address = new Address(obj.address); + this.network = this.address.network; + this.amount = obj.amount; - // Reuse results - var jyd = jy.redAdd(jy); - for (var i = 0; i < pow; i++) { - var jx2 = jx.redSqr(); - var jyd2 = jyd.redSqr(); - var jyd4 = jyd2.redSqr(); - var c = jx2.redAdd(jx2).redIAdd(jx2).redIAdd(a.redMul(jz4)); + for (var key in obj) { + if (key === 'address' || key === 'amount') { + continue; + } - var t1 = jx.redMul(jyd2); - var nx = c.redSqr().redISub(t1.redAdd(t1)); - var t2 = t1.redISub(nx); - var dny = c.redMul(t2); - dny = dny.redIAdd(dny).redISub(jyd4); - var nz = jyd.redMul(jz); - if (i + 1 < pow) - jz4 = jz4.redMul(jyd4); + if (/^req-/.exec(key) && this.knownParams.indexOf(key) === -1) { + throw Error('Unknown required argument ' + key); + } - jx = nx; - jz = nz; - jyd = dny; + var destination = URI.Members.indexOf(key) > -1 ? this : this.extras; + destination[key] = obj[key]; } - - return this.curve.jpoint(jx, jyd.redMul(tinv), jz); }; -JPoint.prototype.dbl = function dbl() { - if (this.isInfinity()) - return this; - - if (this.curve.zeroA) - return this._zeroDbl(); - else if (this.curve.threeA) - return this._threeDbl(); - else - return this._dbl(); +/** + * Internal function to transform a BTC string amount into satoshis + * + * @param {String} amount - Amount BTC string + * @throws {TypeError} Invalid amount + * @returns {Object} Amount represented in satoshis + */ +URI.prototype._parseAmount = function(amount) { + amount = Number(amount); + if (isNaN(amount)) { + throw new TypeError('Invalid amount'); + } + return Unit.fromBTC(amount).toSatoshis(); }; -JPoint.prototype._zeroDbl = function _zeroDbl() { - // Z = 1 - if (this.zOne) { - // http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl - // 1M + 5S + 14A - - // XX = X1^2 - var xx = this.x.redSqr(); - // YY = Y1^2 - var yy = this.y.redSqr(); - // YYYY = YY^2 - var yyyy = yy.redSqr(); - // S = 2 * ((X1 + YY)^2 - XX - YYYY) - var s = this.x.redAdd(yy).redSqr().redISub(xx).redISub(yyyy); - s = s.redIAdd(s); - // M = 3 * XX + a; a = 0 - var m = xx.redAdd(xx).redIAdd(xx); - // T = M ^ 2 - 2*S - var t = m.redSqr().redISub(s).redISub(s); - - // 8 * YYYY - var yyyy8 = yyyy.redIAdd(yyyy); - yyyy8 = yyyy8.redIAdd(yyyy8); - yyyy8 = yyyy8.redIAdd(yyyy8); - - // X3 = T - var nx = t; - // Y3 = M * (S - T) - 8 * YYYY - var ny = m.redMul(s.redISub(t)).redISub(yyyy8); - // Z3 = 2*Y1 - var nz = this.y.redAdd(this.y); - } else { - // http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l - // 2M + 5S + 13A - - // A = X1^2 - var a = this.x.redSqr(); - // B = Y1^2 - var b = this.y.redSqr(); - // C = B^2 - var c = b.redSqr(); - // D = 2 * ((X1 + B)^2 - A - C) - var d = this.x.redAdd(b).redSqr().redISub(a).redISub(c); - d = d.redIAdd(d); - // E = 3 * A - var e = a.redAdd(a).redIAdd(a); - // F = E^2 - var f = e.redSqr(); +URI.prototype.toObject = function toObject() { + var json = {}; + for (var i = 0; i < URI.Members.length; i++) { + var m = URI.Members[i]; + if (this.hasOwnProperty(m) && typeof(this[m]) !== 'undefined') { + json[m] = this[m].toString(); + } + } + _.extend(json, this.extras); + return json; +}; - // 8 * C - var c8 = c.redIAdd(c); - c8 = c8.redIAdd(c8); - c8 = c8.redIAdd(c8); +URI.prototype.toJSON = function toJSON() { + return JSON.stringify(this.toObject()); +}; - // X3 = F - 2 * D - var nx = f.redISub(d).redISub(d); - // Y3 = E * (D - X3) - 8 * C - var ny = e.redMul(d.redISub(nx)).redISub(c8); - // Z3 = 2 * Y1 * Z1 - var nz = this.y.redMul(this.z); - nz = nz.redIAdd(nz); +/** + * Will return a the string representation of the URI + * + * @returns {String} Bitcoin URI string + */ +URI.prototype.toString = function() { + var query = {}; + if (this.amount) { + query.amount = Unit.fromSatoshis(this.amount).toBTC(); + } + if (this.message) { + query.message = this.message; + } + if (this.label) { + query.label = this.label; + } + if (this.r) { + query.r = this.r; } + _.extend(query, this.extras); - return this.curve.jpoint(nx, ny, nz); + return URL.format({ + protocol: 'bitcoin:', + host: this.address, + query: query + }); }; -JPoint.prototype._threeDbl = function _threeDbl() { - // Z = 1 - if (this.zOne) { - // http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-mdbl-2007-bl - // 1M + 5S + 15A - - // XX = X1^2 - var xx = this.x.redSqr(); - // YY = Y1^2 - var yy = this.y.redSqr(); - // YYYY = YY^2 - var yyyy = yy.redSqr(); - // S = 2 * ((X1 + YY)^2 - XX - YYYY) - var s = this.x.redAdd(yy).redSqr().redISub(xx).redISub(yyyy); - s = s.redIAdd(s); - // M = 3 * XX + a - var m = xx.redAdd(xx).redIAdd(xx).redIAdd(this.curve.a); - // T = M^2 - 2 * S - var t = m.redSqr().redISub(s).redISub(s); - // X3 = T - var nx = t; - // Y3 = M * (S - T) - 8 * YYYY - var yyyy8 = yyyy.redIAdd(yyyy); - yyyy8 = yyyy8.redIAdd(yyyy8); - yyyy8 = yyyy8.redIAdd(yyyy8); - var ny = m.redMul(s.redISub(t)).redISub(yyyy8); - // Z3 = 2 * Y1 - var nz = this.y.redAdd(this.y); - } else { - // http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b - // 3M + 5S +/** + * Will return a string formatted for the console + * + * @returns {String} Bitcoin URI + */ +URI.prototype.inspect = function() { + return ''; +}; - // delta = Z1^2 - var delta = this.z.redSqr(); - // gamma = Y1^2 - var gamma = this.y.redSqr(); - // beta = X1 * gamma - var beta = this.x.redMul(gamma); - // alpha = 3 * (X1 - delta) * (X1 + delta) - var alpha = this.x.redSub(delta).redMul(this.x.redAdd(delta)); - alpha = alpha.redAdd(alpha).redIAdd(alpha); - // X3 = alpha^2 - 8 * beta - var beta4 = beta.redIAdd(beta); - beta4 = beta4.redIAdd(beta4); - var beta8 = beta4.redAdd(beta4); - var nx = alpha.redSqr().redISub(beta8); - // Z3 = (Y1 + Z1)^2 - gamma - delta - var nz = this.y.redAdd(this.z).redSqr().redISub(gamma).redISub(delta); - // Y3 = alpha * (4 * beta - X3) - 8 * gamma^2 - var ggamma8 = gamma.redSqr(); - ggamma8 = ggamma8.redIAdd(ggamma8); - ggamma8 = ggamma8.redIAdd(ggamma8); - ggamma8 = ggamma8.redIAdd(ggamma8); - var ny = alpha.redMul(beta4.redISub(nx)).redISub(ggamma8); - } +module.exports = URI; - return this.curve.jpoint(nx, ny, nz); -}; +},{"./address":31,"./unit":67,"./util/js":70,"lodash":95,"url":375}],69:[function(require,module,exports){ +(function (Buffer){ +'use strict'; -JPoint.prototype._dbl = function _dbl() { - var a = this.curve.a; - var tinv = this.curve.tinv; +var buffer = require('buffer'); +var assert = require('assert'); - // 4M + 6S + 10A - var jx = this.x; - var jy = this.y; - var jz = this.z; - var jz4 = jz.redSqr().redSqr(); +var js = require('./js'); +var $ = require('./preconditions'); - var jx2 = jx.redSqr(); - var jy2 = jy.redSqr(); +function equals(a, b) { + if (a.length !== b.length) { + return false; + } + var length = a.length; + for (var i = 0; i < length; i++) { + if (a[i] !== b[i]) { + return false; + } + } + return true; +} - var c = jx2.redAdd(jx2).redIAdd(jx2).redIAdd(a.redMul(jz4)); +module.exports = { + /** + * Fill a buffer with a value. + * + * @param {Buffer} buffer + * @param {number} value + * @return {Buffer} + */ + fill: function fill(buffer, value) { + $.checkArgumentType(buffer, 'Buffer', 'buffer'); + $.checkArgumentType(value, 'number', 'value'); + var length = buffer.length; + for (var i = 0; i < length; i++) { + buffer[i] = value; + } + return buffer; + }, - var jxd4 = jx.redAdd(jx); - jxd4 = jxd4.redIAdd(jxd4); - var t1 = jxd4.redMul(jy2); - var nx = c.redSqr().redISub(t1.redAdd(t1)); - var t2 = t1.redISub(nx); + /** + * Return a copy of a buffer + * + * @param {Buffer} original + * @return {Buffer} + */ + copy: function(original) { + var buffer = new Buffer(original.length); + original.copy(buffer); + return buffer; + }, - var jyd8 = jy2.redSqr(); - jyd8 = jyd8.redIAdd(jyd8); - jyd8 = jyd8.redIAdd(jyd8); - jyd8 = jyd8.redIAdd(jyd8); - var ny = c.redMul(t2).redISub(jyd8); - var nz = jy.redAdd(jy).redMul(jz); + /** + * Returns true if the given argument is an instance of a buffer. Tests for + * both node's Buffer and Uint8Array + * + * @param {*} arg + * @return {boolean} + */ + isBuffer: function isBuffer(arg) { + return buffer.Buffer.isBuffer(arg) || arg instanceof Uint8Array; + }, - return this.curve.jpoint(nx, ny, nz); -}; + /** + * Returns a zero-filled byte array + * + * @param {number} bytes + * @return {Buffer} + */ + emptyBuffer: function emptyBuffer(bytes) { + $.checkArgumentType(bytes, 'number', 'bytes'); + var result = new buffer.Buffer(bytes); + for (var i = 0; i < bytes; i++) { + result.write('\0', i); + } + return result; + }, -JPoint.prototype.trpl = function trpl() { - if (!this.curve.zeroA) - return this.dbl().add(this); + /** + * Concatenates a buffer + * + * Shortcut for buffer.Buffer.concat + */ + concat: buffer.Buffer.concat, - // http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#tripling-tpl-2007-bl - // 5M + 10S + ... + equals: equals, + equal: equals, - // XX = X1^2 - var xx = this.x.redSqr(); - // YY = Y1^2 - var yy = this.y.redSqr(); - // ZZ = Z1^2 - var zz = this.z.redSqr(); - // YYYY = YY^2 - var yyyy = yy.redSqr(); - // M = 3 * XX + a * ZZ2; a = 0 - var m = xx.redAdd(xx).redIAdd(xx); - // MM = M^2 - var mm = m.redSqr(); - // E = 6 * ((X1 + YY)^2 - XX - YYYY) - MM - var e = this.x.redAdd(yy).redSqr().redISub(xx).redISub(yyyy); - e = e.redIAdd(e); - e = e.redAdd(e).redIAdd(e); - e = e.redISub(mm); - // EE = E^2 - var ee = e.redSqr(); - // T = 16*YYYY - var t = yyyy.redIAdd(yyyy); - t = t.redIAdd(t); - t = t.redIAdd(t); - t = t.redIAdd(t); - // U = (M + E)^2 - MM - EE - T - var u = m.redIAdd(e).redSqr().redISub(mm).redISub(ee).redISub(t); - // X3 = 4 * (X1 * EE - 4 * YY * U) - var yyu4 = yy.redMul(u); - yyu4 = yyu4.redIAdd(yyu4); - yyu4 = yyu4.redIAdd(yyu4); - var nx = this.x.redMul(ee).redISub(yyu4); - nx = nx.redIAdd(nx); - nx = nx.redIAdd(nx); - // Y3 = 8 * Y1 * (U * (T - U) - E * EE) - var ny = this.y.redMul(u.redMul(t.redISub(u)).redISub(e.redMul(ee))); - ny = ny.redIAdd(ny); - ny = ny.redIAdd(ny); - ny = ny.redIAdd(ny); - // Z3 = (Z1 + E)^2 - ZZ - EE - var nz = this.z.redAdd(e).redSqr().redISub(zz).redISub(ee); + /** + * Transforms a number from 0 to 255 into a Buffer of size 1 with that value + * + * @param {number} integer + * @return {Buffer} + */ + integerAsSingleByteBuffer: function integerAsSingleByteBuffer(integer) { + $.checkArgumentType(integer, 'number', 'integer'); + return new buffer.Buffer([integer & 0xff]); + }, - return this.curve.jpoint(nx, ny, nz); -}; + /** + * Transform a 4-byte integer into a Buffer of length 4. + * + * @param {number} integer + * @return {Buffer} + */ + integerAsBuffer: function integerAsBuffer(integer) { + $.checkArgumentType(integer, 'number', 'integer'); + var bytes = []; + bytes.push((integer >> 24) & 0xff); + bytes.push((integer >> 16) & 0xff); + bytes.push((integer >> 8) & 0xff); + bytes.push(integer & 0xff); + return new Buffer(bytes); + }, -JPoint.prototype.mul = function mul(k, kbase) { - k = new bn(k, kbase); + /** + * Transform the first 4 values of a Buffer into a number, in little endian encoding + * + * @param {Buffer} buffer + * @return {number} + */ + integerFromBuffer: function integerFromBuffer(buffer) { + $.checkArgumentType(buffer, 'Buffer', 'buffer'); + return buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3]; + }, - return this.curve._wnafMul(this, k); + /** + * Transforms the first byte of an array into a number ranging from -128 to 127 + * @param {Buffer} buffer + * @return {number} + */ + integerFromSingleByteBuffer: function integerFromBuffer(buffer) { + $.checkArgumentType(buffer, 'Buffer', 'buffer'); + return buffer[0]; + }, + + /** + * Transforms a buffer into a string with a number in hexa representation + * + * Shorthand for buffer.toString('hex') + * + * @param {Buffer} buffer + * @return {string} + */ + bufferToHex: function bufferToHex(buffer) { + $.checkArgumentType(buffer, 'Buffer', 'buffer'); + return buffer.toString('hex'); + }, + + /** + * Reverse a buffer + * @param {Buffer} param + * @return {Buffer} + */ + reverse: function reverse(param) { + $.checkArgumentType(param, 'Buffer', 'param'); + var ret = new buffer.Buffer(param.length); + for (var i = 0; i < param.length; i++) { + ret[i] = param[param.length - i - 1]; + } + return ret; + }, + + /** + * Transforms an hexa encoded string into a Buffer with binary values + * + * Shorthand for Buffer(string, 'hex') + * + * @param {string} string + * @return {Buffer} + */ + hexToBuffer: function hexToBuffer(string) { + assert(js.isHexa(string)); + return new buffer.Buffer(string, 'hex'); + } }; -JPoint.prototype.eq = function eq(p) { - if (p.type === 'affine') - return this.eq(p.toJ()); +module.exports.NULL_HASH = module.exports.fill(new Buffer(32), 0); +module.exports.EMPTY_BUFFER = new Buffer(0); - if (this === p) - return true; +}).call(this,require("buffer").Buffer) +},{"./js":70,"./preconditions":71,"assert":194,"buffer":209}],70:[function(require,module,exports){ +'use strict'; - // x1 * z2^2 == x2 * z1^2 - var z2 = this.z.redSqr(); - var pz2 = p.z.redSqr(); - if (this.x.redMul(pz2).redISub(p.x.redMul(z2)).cmpn(0) !== 0) - return false; +var _ = require('lodash'); - // y1 * z2^3 == y2 * z1^3 - var z3 = z2.redMul(this.z); - var pz3 = pz2.redMul(p.z); - return this.y.redMul(pz3).redISub(p.y.redMul(z3)).cmpn(0) === 0; +/** + * Determines whether a string contains only hexadecimal values + * + * @name JSUtil.isHexa + * @param {string} value + * @return {boolean} true if the string is the hexa representation of a number + */ +var isHexa = function isHexa(value) { + if (!_.isString(value)) { + return false; + } + return /^[0-9a-fA-F]+$/.test(value); }; -JPoint.prototype.inspect = function inspect() { - if (this.isInfinity()) - return ''; - return ''; +/** + * @namespace JSUtil + */ +module.exports = { + /** + * Test if an argument is a valid JSON object. If it is, returns a truthy + * value (the json object decoded), so no double JSON.parse call is necessary + * + * @param {string} arg + * @return {Object|boolean} false if the argument is not a JSON string. + */ + isValidJSON: function isValidJSON(arg) { + var parsed; + if (!_.isString(arg)) { + return false; + } + try { + parsed = JSON.parse(arg); + } catch (e) { + return false; + } + if (typeof(parsed) === 'object') { + return true; + } + return false; + }, + isHexa: isHexa, + isHexaString: isHexa, + + /** + * Clone an array + */ + cloneArray: function(array) { + return [].concat(array); + }, + + /** + * Define immutable properties on a target object + * + * @param {Object} target - An object to be extended + * @param {Object} values - An object of properties + * @return {Object} The target object + */ + defineImmutable: function defineImmutable(target, values){ + Object.keys(values).forEach(function(key){ + Object.defineProperty(target, key, { + configurable: false, + enumerable: true, + value: values[key] + }); + }); + return target; + } }; -JPoint.prototype.isInfinity = function isInfinity() { - // XXX This code assumes that zero is always zero in red - return this.z.cmpn(0) === 0; +},{"lodash":95}],71:[function(require,module,exports){ +'use strict'; + +var errors = require('../errors'); +var _ = require('lodash'); + +module.exports = { + checkState: function(condition, message) { + if (!condition) { + throw new errors.InvalidState(message); + } + }, + checkArgument: function(condition, argumentName, message, docsPath) { + if (!condition) { + throw new errors.InvalidArgument(argumentName, message, docsPath); + } + }, + checkArgumentType: function(argument, type, argumentName) { + argumentName = argumentName || '(unknown name)'; + if (_.isString(type)) { + if (type === 'Buffer') { + var BufferUtil = require('./buffer'); + if (!BufferUtil.isBuffer(argument)) { + throw new errors.InvalidArgumentType(argument, type, argumentName); + } + } else if (typeof argument !== type) { + throw new errors.InvalidArgumentType(argument, type, argumentName); + } + } else { + if (!(argument instanceof type)) { + throw new errors.InvalidArgumentType(argument, type.name, argumentName); + } + } + } }; -},{"../../elliptic":58,"../curve":61,"assert":89,"bn.js":56,"inherits":78}],64:[function(require,module,exports){ -var curves = exports; +},{"../errors":45,"./buffer":69,"lodash":95}],72:[function(require,module,exports){ +// Utils -var assert = require('assert'); -var hash = require('hash.js'); -var bn = require('bn.js'); -var elliptic = require('../elliptic'); +function assert(val, msg) { + if (!val) + throw new Error(msg || 'Assertion failed'); +} -function PresetCurve(options) { - if (options.type === 'short') - this.curve = new elliptic.curve.short(options); - else if (options.type === 'edwards') - this.curve = new elliptic.curve.edwards(options); - else - this.curve = new elliptic.curve.mont(options); - this.g = this.curve.g; - this.n = this.curve.n; - this.hash = options.hash; +function assertEqual(l, r, msg) { + if (l != r) + throw new Error(msg || ('Assertion failed: ' + l + ' != ' + r)); +} - assert(this.g.validate(), 'Invalid curve'); - assert(this.g.mul(this.n).isInfinity(), 'Invalid curve, G*N != O'); +// 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 } -curves.PresetCurve = PresetCurve; -function defineCurve(name, options) { - Object.defineProperty(curves, name, { - configurable: true, - enumerable: true, - get: function() { - var curve = new PresetCurve(options); - Object.defineProperty(curves, name, { - configurable: true, - enumerable: true, - value: curve - }); - return curve; - } - }); +// BN + +function BN(number, base, endian) { + // May be `new BN(bn)` ? + if (number !== null && + typeof number === 'object' && + Array.isArray(number.words)) { + return number; + } + + this.sign = false; + this.words = null; + this.length = 0; + + // Reduction context + this.red = null; + + if (base === 'le' || base === 'be') { + endian = base; + base = 10; + } + + if (number !== null) + this._init(number || 0, base || 10, endian || 'be'); } +if (typeof module === 'object') + module.exports = BN; -defineCurve('p192', { - type: 'short', - prime: 'p192', - p: 'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff', - a: 'ffffffff ffffffff ffffffff fffffffe ffffffff fffffffc', - b: '64210519 e59c80e7 0fa7e9ab 72243049 feb8deec c146b9b1', - n: 'ffffffff ffffffff ffffffff 99def836 146bc9b1 b4d22831', - hash: hash.sha256, - gRed: false, - g: [ - '188da80e b03090f6 7cbf20eb 43a18800 f4ff0afd 82ff1012', - '07192b95 ffc8da78 631011ed 6b24cdd5 73f977a1 1e794811' - ], -}); +BN.BN = BN; +BN.wordSize = 26; -defineCurve('p224', { - type: 'short', - prime: 'p224', - p: 'ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001', - a: 'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff fffffffe', - b: 'b4050a85 0c04b3ab f5413256 5044b0b7 d7bfd8ba 270b3943 2355ffb4', - n: 'ffffffff ffffffff ffffffff ffff16a2 e0b8f03e 13dd2945 5c5c2a3d', - hash: hash.sha256, - gRed: false, - g: [ - 'b70e0cbd 6bb4bf7f 321390b9 4a03c1d3 56c21122 343280d6 115c1d21', - 'bd376388 b5f723fb 4c22dfe6 cd4375a0 5a074764 44d58199 85007e34' - ], -}); +BN.prototype._init = function init(number, base, endian) { + if (typeof number === 'number') { + if (number < 0) { + this.sign = true; + number = -number; + } + if (number < 0x4000000) { + this.words = [ number & 0x3ffffff ]; + this.length = 1; + } else { + this.words = [ + number & 0x3ffffff, + (number / 0x4000000) & 0x3ffffff + ]; + this.length = 2; + } + return; + } else if (typeof number === 'object') { + return this._initArray(number, base, endian); + } + if (base === 'hex') + base = 16; + assert(base === (base | 0) && base >= 2 && base <= 36); -defineCurve('p256', { - type: 'short', - prime: null, - p: 'ffffffff 00000001 00000000 00000000 00000000 ffffffff ffffffff ffffffff', - a: 'ffffffff 00000001 00000000 00000000 00000000 ffffffff ffffffff fffffffc', - b: '5ac635d8 aa3a93e7 b3ebbd55 769886bc 651d06b0 cc53b0f6 3bce3c3e 27d2604b', - n: 'ffffffff 00000000 ffffffff ffffffff bce6faad a7179e84 f3b9cac2 fc632551', - hash: hash.sha256, - gRed: false, - g: [ - '6b17d1f2 e12c4247 f8bce6e5 63a440f2 77037d81 2deb33a0 f4a13945 d898c296', - '4fe342e2 fe1a7f9b 8ee7eb4a 7c0f9e16 2bce3357 6b315ece cbb64068 37bf51f5' - ], -}); + number = number.toString().replace(/\s+/g, ''); + var start = 0; + if (number[0] === '-') + start++; -defineCurve('curve25519', { - type: 'mont', - prime: 'p25519', - p: '7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed', - a: '76d06', - b: '0', - n: '1000000000000000 0000000000000000 14def9dea2f79cd6 5812631a5cf5d3ed', - hash: hash.sha256, - gRed: false, - g: [ - '9' - ] -}); + if (base === 16) + this._parseHex(number, start); + else + this._parseBase(number, base, start); -defineCurve('ed25519', { - type: 'edwards', - prime: 'p25519', - p: '7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed', - a: '-1', - c: '1', - // -121665 * (121666^(-1)) (mod P) - d: '52036cee2b6ffe73 8cc740797779e898 00700a4d4141d8ab 75eb4dca135978a3', - n: '1000000000000000 0000000000000000 14def9dea2f79cd6 5812631a5cf5d3ed', - hash: hash.sha256, - gRed: false, - g: [ - '216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51a', + if (number[0] === '-') + this.sign = true; - // 4/5 - '6666666666666666666666666666666666666666666666666666666666666658' - ] -}); + this.strip(); +}; -defineCurve('secp256k1', { - type: 'short', - prime: 'k256', - p: 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f', - a: '0', - b: '7', - n: 'ffffffff ffffffff ffffffff fffffffe baaedce6 af48a03b bfd25e8c d0364141', - h: '1', - hash: hash.sha256, +BN.prototype._initArray = function _initArray(number, base, endian) { + // Perhaps a Uint8Array + assert(typeof number.length === 'number'); + 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; - // Precomputed endomorphism - beta: '7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee', - lambda: '5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72', - basis: [ - { - a: '3086d221a7d46bcde86c90e49284eb15', - b: '-e4437ed6010e88286f547fa90abfe4c3' - }, - { - a: '114ca50f7a8e2f3f657c1108d9d44cfd8', - b: '3086d221a7d46bcde86c90e49284eb15' + var off = 0; + if (endian === 'be') { + for (var i = number.length - 1, j = 0; i >= 0; i -= 3) { + var 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 (var i = 0, j = 0; i < number.length; i += 3) { + var 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(); +}; - gRed: false, - g: [ - '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798', - '483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8', - { - 'doubles': { - 'step': 4, - 'points': [ - [ - 'e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a', - 'f7e3507399e595929db99f34f57937101296891e44d23f0be1f32cce69616821' - ], - [ - '8282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508', - '11f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf' - ], - [ - '175e159f728b865a72f99cc6c6fc846de0b93833fd2222ed73fce5b551e5b739', - 'd3506e0d9e3c79eba4ef97a51ff71f5eacb5955add24345c6efa6ffee9fed695' - ], - [ - '363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640', - '4e273adfc732221953b445397f3363145b9a89008199ecb62003c7f3bee9de9' - ], - [ - '8b4b5f165df3c2be8c6244b5b745638843e4a781a15bcd1b69f79a55dffdf80c', +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; + + // Scan 24-bit chunks and add them to the number + var off = 0; + for (var i = number.length - 6, j = 0; i >= start; i -= 6) { + var w = parseInt(number.slice(i, i + 6), 16); + this.words[j] |= (w << off) & 0x3ffffff; + this.words[j + 1] |= w >>> (26 - off) & 0x3fffff; + off += 24; + if (off >= 26) { + off -= 26; + j++; + } + } + if (i + 6 !== start) { + var w = parseInt(number.slice(start, i + 6), 16); + this.words[j] |= (w << off) & 0x3ffffff; + this.words[j + 1] |= w >>> (26 - off) & 0x3fffff; + } + this.strip(); +}; + +BN.prototype._parseBase = function parseBase(number, base, start) { + // Initialize as zero + this.words = [ 0 ]; + this.length = 1; + + var word = 0; + var q = 1; + var p = 0; + var bigQ = null; + for (var i = start; i < number.length; i++) { + var digit; + var ch = number[i]; + if (base === 10 || ch <= '9') + digit = ch | 0; + else if (ch >= 'a') + digit = ch.charCodeAt(0) - 97 + 10; + else + digit = ch.charCodeAt(0) - 65 + 10; + word *= base; + word += digit; + q *= base; + p++; + + if (q > 0xfffff) { + assert(q <= 0x3ffffff); + if (!bigQ) + bigQ = new BN(q); + this.mul(bigQ).copy(this); + this.iadd(new BN(word)); + word = 0; + q = 1; + p = 0; + } + } + if (p !== 0) { + this.mul(new BN(q)).copy(this); + this.iadd(new BN(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.sign = this.sign; + dest.red = this.red; +}; + +BN.prototype.clone = function clone() { + var r = new BN(null); + this.copy(r); + return r; +}; + +// 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.sign = false; + return this; +}; + +BN.prototype.inspect = function inspect() { + return (this.red ? ''; +}; + +/* + +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; + // TODO: <= + 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; + if (base === 16 || base === 'hex') { + var out = ''; + var off = 0; + var padding = padding | 0 || 1; + 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.sign) + out = '-' + out; + return out; + } else 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]; + var out = ''; + var c = this.clone(); + c.sign = false; + while (c.cmpn(0) !== 0) { + var r = c.modn(groupBase).toString(base); + c = c.idivn(groupBase); + + if (c.cmpn(0) !== 0) + out = zeros[groupSize - r.length] + r + out; + else + out = r + out; + } + if (this.cmpn(0) === 0) + out = '0' + out; + if (this.sign) + out = '-' + out; + return out; + } else { + assert(false, 'Base should be between 2 and 36'); + } +}; + +BN.prototype.toJSON = function toJSON() { + return this.toString(16); +}; + +BN.prototype.toArray = function toArray() { + this.strip(); + var res = new Array(this.byteLength()); + res[0] = 0; + + var q = this.clone(); + for (var i = 0; q.cmpn(0) !== 0; i++) { + var b = q.andln(0xff); + q.ishrn(8); + + // Assume big-endian + res[res.length - i - 1] = b; + } + + return res; +}; + +/* +function genCountBits(bits) { + var arr = []; + + for (var i = bits - 1; i >= 0; i--) { + var bit = '0x' + (1 << i).toString(16); + arr.push('w >= ' + bit + ' ? ' + (i + 1)); + } + + return new Function('w', 'return ' + arr.join(' :\n') + ' :\n0;'); +}; + +BN.prototype._countBits = genCountBits(26); +*/ + +// Sadly chrome apps could not contain `new Function()` calls +BN.prototype._countBits = function _countBits(w) { + return w >= 0x2000000 ? 26 : + w >= 0x1000000 ? 25 : + w >= 0x800000 ? 24 : + w >= 0x400000 ? 23 : + w >= 0x200000 ? 22 : + w >= 0x100000 ? 21 : + w >= 0x80000 ? 20 : + w >= 0x40000 ? 19 : + w >= 0x20000 ? 18 : + w >= 0x10000 ? 17 : + w >= 0x8000 ? 16 : + w >= 0x4000 ? 15 : + w >= 0x2000 ? 14 : + w >= 0x1000 ? 13 : + w >= 0x800 ? 12 : + w >= 0x400 ? 11 : + w >= 0x200 ? 10 : + w >= 0x100 ? 9 : + w >= 0x80 ? 8 : + w >= 0x40 ? 7 : + w >= 0x20 ? 6 : + w >= 0x10 ? 5 : + w >= 0x8 ? 4 : + w >= 0x4 ? 3 : + w >= 0x2 ? 2 : + w >= 0x1 ? 1 : + 0; +}; + +// Return number of used bits in a BN +BN.prototype.bitLength = function bitLength() { + var hi = 0; + var w = this.words[this.length - 1]; + var hi = this._countBits(w); + return (this.length - 1) * 26 + hi; +}; + +BN.prototype.byteLength = function byteLength() { + var hi = 0; + var w = this.words[this.length - 1]; + return Math.ceil(this.bitLength() / 8); +}; + +// Return negative clone of `this` +BN.prototype.neg = function neg() { + if (this.cmpn(0) === 0) + return this.clone(); + + var r = this.clone(); + r.sign = !this.sign; + return r; +}; + +// Add `num` to `this` in-place +BN.prototype.iadd = function iadd(num) { + // negative + positive + if (this.sign && !num.sign) { + this.sign = false; + var r = this.isub(num); + this.sign = !this.sign; + return this._normSign(); + + // positive + negative + } else if (!this.sign && num.sign) { + num.sign = false; + var r = this.isub(num); + num.sign = true; + return r._normSign(); + } + + // a.length > b.length + var a; + var 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++) { + var r = a.words[i] + b.words[i] + carry; + this.words[i] = r & 0x3ffffff; + carry = r >>> 26; + } + for (; carry !== 0 && i < a.length; i++) { + var r = a.words[i] + 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) { + if (num.sign && !this.sign) { + num.sign = false; + var res = this.sub(num); + num.sign = true; + return res; + } else if (!num.sign && this.sign) { + this.sign = false; + var res = num.sub(this); + this.sign = true; + return res; + } + + if (this.length > num.length) + return this.clone().iadd(num); + else + return num.clone().iadd(this); +}; + +// Subtract `num` from `this` in-place +BN.prototype.isub = function isub(num) { + // this - (-num) = this + num + if (num.sign) { + num.sign = false; + var r = this.iadd(num); + num.sign = true; + return r._normSign(); + + // -this - num = -(this + num) + } else if (this.sign) { + this.sign = false; + this.iadd(num); + this.sign = true; + return this._normSign(); + } + + // At this point both numbers are positive + var cmp = this.cmp(num); + + // Optimization - zeroify + if (cmp === 0) { + this.sign = false; + this.length = 1; + this.words[0] = 0; + return this; + } + + // a > b + if (cmp > 0) { + var a = this; + var b = num; + } else { + var a = num; + var b = this; + } + + var carry = 0; + for (var i = 0; i < b.length; i++) { + var r = a.words[i] - b.words[i] - carry; + if (r < 0) { + r += 0x4000000; + carry = 1; + } else { + carry = 0; + } + this.words[i] = r; + } + for (; carry !== 0 && i < a.length; i++) { + var r = a.words[i] - carry; + if (r < 0) { + r += 0x4000000; + carry = 1; + } else { + carry = 0; + } + this.words[i] = r; + } + + // 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.sign = true; + + return this.strip(); +}; + +// Subtract `num` from `this` +BN.prototype.sub = function sub(num) { + return this.clone().isub(num); +}; + +/* +// NOTE: This could be potentionally used to generate loop-less multiplications +function _genCombMulTo(alen, blen) { + var len = alen + blen - 1; + var src = [ + 'var a = this.words, b = num.words, o = out.words, c = 0, w, ' + + 'mask = 0x3ffffff, shift = 0x4000000;', + 'out.length = ' + len + ';' + ]; + for (var k = 0; k < len; k++) { + var minJ = Math.max(0, k - alen + 1); + var maxJ = Math.min(k, blen - 1); + + for (var j = minJ; j <= maxJ; j++) { + var i = k - j; + var mul = 'a[' + i + '] * b[' + j + ']'; + + if (j === minJ) { + src.push('w = ' + mul + ' + c;'); + src.push('c = (w / shift) | 0;'); + } else { + src.push('w += ' + mul + ';'); + src.push('c += (w / shift) | 0;'); + } + src.push('w &= mask;'); + } + src.push('o[' + k + '] = w;'); + } + src.push('if (c !== 0) {', + ' o[' + k + '] = c;', + ' out.length++;', + '}', + 'return out;'); + + return src.join('\n'); +} +*/ + +BN.prototype._smallMulTo = function _smallMulTo(num, out) { + out.sign = num.sign !== this.sign; + out.length = this.length + num.length; + + var carry = 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 = carry >>> 26; + var rword = carry & 0x3ffffff; + var maxJ = Math.min(k, num.length - 1); + for (var j = Math.max(0, k - this.length + 1); j <= maxJ; j++) { + var i = k - j; + var a = this.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; + } + out.words[k] = rword; + carry = ncarry; + } + if (carry !== 0) { + out.words[k] = carry; + } else { + out.length--; + } + + return out.strip(); +}; + +BN.prototype._bigMulTo = function _bigMulTo(num, out) { + out.sign = num.sign !== this.sign; + out.length = this.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 - this.length + 1); j <= maxJ; j++) { + var i = k - j; + var a = this.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(); +}; + +BN.prototype.mulTo = function mulTo(num, out) { + var res; + if (this.length + num.length < 63) + res = this._smallMulTo(num, out); + else + res = this._bigMulTo(num, out); + return res; +}; + +// 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); +}; + +// In-place Multiplication +BN.prototype.imul = function imul(num) { + if (this.cmpn(0) === 0 || num.cmpn(0) === 0) { + this.words[0] = 0; + this.length = 1; + return this; + } + + var tlen = this.length; + var nlen = num.length; + + this.sign = num.sign !== this.sign; + this.length = this.length + num.length; + this.words[this.length - 1] = 0; + + var lastCarry = 0; + for (var k = this.length - 2; k >= 0; k--) { + // Sum all words with the same `i + j = k` and accumulate `carry`, + // note that carry could be >= 0x3ffffff + var carry = 0; + var rword = 0; + var maxJ = Math.min(k, nlen - 1); + for (var j = Math.max(0, k - tlen + 1); j <= maxJ; j++) { + var i = k - j; + var a = this.words[i]; + var b = num.words[j]; + var r = a * b; + + var lo = r & 0x3ffffff; + carry += (r / 0x4000000) | 0; + lo += rword; + rword = lo & 0x3ffffff; + carry += lo >>> 26; + } + this.words[k] = rword; + this.words[k + 1] += carry; + carry = 0; + } + + // Propagate overflows + var carry = 0; + for (var i = 1; i < this.length; i++) { + var w = this.words[i] + carry; + this.words[i] = w & 0x3ffffff; + carry = w >>> 26; + } + + return this.strip(); +}; + +// `this` * `this` +BN.prototype.sqr = function sqr() { + return this.mul(this); +}; + +// `this` * `this` in-place +BN.prototype.isqr = function isqr() { + return this.mul(this); +}; + +// Shift-left in-place +BN.prototype.ishln = function ishln(bits) { + assert(typeof bits === 'number' && bits >= 0); + var r = bits % 26; + var s = (bits - r) / 26; + var carryMask = (0x3ffffff >>> (26 - r)) << (26 - r); + + var o = this.clone(); + if (r !== 0) { + var carry = 0; + for (var i = 0; i < this.length; i++) { + var newCarry = this.words[i] & carryMask; + var c = (this.words[i] - newCarry) << r; + this.words[i] = c | carry; + carry = newCarry >>> (26 - r); + } + if (carry) { + this.words[i] = carry; + this.length++; + } + } + + if (s !== 0) { + for (var i = this.length - 1; i >= 0; i--) + this.words[i + s] = this.words[i]; + for (var i = 0; i < s; i++) + this.words[i] = 0; + this.length += s; + } + + return this.strip(); +}; + +// Shift-right in-place +// NOTE: `hint` is a lowest bit before trailing zeroes +// NOTE: if `extended` is true - { lo: ..., hi: } object will be returned +BN.prototype.ishrn = function ishrn(bits, hint, extended) { + assert(typeof bits === 'number' && bits >= 0); + if (hint) + hint = (hint - (hint % 26)) / 26; + else + hint = 0; + + var r = bits % 26; + var s = Math.min((bits - r) / 26, this.length); + var mask = 0x3ffffff ^ ((0x3ffffff >>> r) << r); + var maskedWords = extended; + + hint -= s; + hint = Math.max(0, hint); + + // 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 (var 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 (var i = this.length - 1; i >= 0 && (carry !== 0 || i >= hint); i--) { + var word = this.words[i]; + 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; + } + + this.strip(); + if (extended) + return { hi: this, lo: maskedWords }; + + return this; +}; + +// Shift-left +BN.prototype.shln = function shln(bits) { + return this.clone().ishln(bits); +}; + +// Shift-right +BN.prototype.shrn = function shrn(bits) { + return this.clone().ishrn(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.sign, 'imaskn works only with positive numbers'); + + 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'); + if (num < 0) + return this.isubn(-num); + + // Possible sign change + if (this.sign) { + if (this.length === 1 && this.words[0] < num) { + this.words[0] = num - this.words[0]; + this.sign = false; + return this; + } + + this.sign = false; + this.isubn(num); + this.sign = true; + return this; + } + 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'); + if (num < 0) + return this.iaddn(-num); + + if (this.sign) { + this.sign = false; + this.iaddn(num); + this.sign = true; + return this; + } + + this.words[0] -= num; + + // 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.sign = false; + + return this +}; + +BN.prototype.abs = function abs() { + return this.clone().iabs(); +}; + +BN.prototype._wordDiv = function _wordDiv(num, mode) { + var shift = this.length - num.length; + + var a = this.clone(); + var b = num; + + var q = mode !== 'mod' && new BN(0); + var sign = false; + + // Approximate quotient at each step + while (a.length > b.length) { + // NOTE: a.length is always >= 2, because of the condition .div() + var hi = a.words[a.length - 1] * 0x4000000 + a.words[a.length - 2]; + var sq = (hi / b.words[b.length - 1]); + var sqhi = (sq / 0x4000000) | 0; + var sqlo = sq & 0x3ffffff; + sq = new BN(null); + sq.words = [ sqlo, sqhi ]; + sq.length = 2; + + // Collect quotient + var shift = (a.length - b.length - 1) * 26; + if (q) { + var t = sq.shln(shift); + if (a.sign) + q.isub(t); + else + q.iadd(t); + } + + sq = sq.mul(b).ishln(shift); + if (a.sign) + a.iadd(sq) + else + a.isub(sq); + } + // At this point a.length <= b.length + while (a.ucmp(b) >= 0) { + // NOTE: a.length is always >= 2, because of the condition above + var hi = a.words[a.length - 1]; + var sq = new BN((hi / b.words[b.length - 1]) | 0); + var shift = (a.length - b.length) * 26; + + if (q) { + var t = sq.shln(shift); + if (a.sign) + q.isub(t); + else + q.iadd(t); + } + + sq = sq.mul(b).ishln(shift); + + if (a.sign) + a.iadd(sq); + else + a.isub(sq); + } + + if (a.sign) { + if (q) + q.isubn(1); + a.iadd(b); + } + return { div: q ? q : null, mod: a }; +}; + +BN.prototype.divmod = function divmod(num, mode) { + assert(num.cmpn(0) !== 0); + + if (this.sign && !num.sign) { + var res = this.neg().divmod(num, mode); + var div; + var mod; + if (mode !== 'mod') + div = res.div.neg(); + if (mode !== 'div') + mod = res.mod.cmpn(0) === 0 ? res.mod : num.sub(res.mod); + return { + div: div, + mod: mod + }; + } else if (!this.sign && num.sign) { + var res = this.divmod(num.neg(), mode); + var div; + if (mode !== 'mod') + div = res.div.neg(); + return { div: div, mod: res.mod }; + } else if (this.sign && num.sign) { + return this.neg().divmod(num.neg(), mode); + } + + // 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 }; + else 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').div; +}; + +// Find `this` % `num` +BN.prototype.mod = function mod(num) { + return this.divmod(num, 'mod').mod; +}; + +// Find Round(`this` / `num`) +BN.prototype.divRound = function divRound(num) { + var dm = this.divmod(num); + + // Fast case - exact division + if (dm.mod.cmpn(0) === 0) + return dm.div; + + var mod = dm.div.sign ? dm.mod.isub(num) : dm.mod; + + var half = num.shrn(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.sign ? 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]) % 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] + 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(x1, p) { + assert(!p.sign); + assert(p.cmpn(0) !== 0); + + var a = this; + var b = p.clone(); + + if (a.sign) + a = a.mod(p); + else + a = a.clone(); + + var x2 = new BN(0); + while (b.isEven()) + b.ishrn(1); + var delta = b.clone(); + while (a.cmpn(1) > 0 && b.cmpn(1) > 0) { + while (a.isEven()) { + a.ishrn(1); + if (x1.isEven()) + x1.ishrn(1); + else + x1.iadd(delta).ishrn(1); + } + while (b.isEven()) { + b.ishrn(1); + if (x2.isEven()) + x2.ishrn(1); + else + x2.iadd(delta).ishrn(1); + } + if (a.cmp(b) >= 0) { + a.isub(b); + x1.isub(x2); + } else { + b.isub(a); + x2.isub(x1); + } + } + if (a.cmpn(1) === 0) + return x1; + else + return x2; +}; + +BN.prototype.gcd = function gcd(num) { + if (this.cmpn(0) === 0) + return num.clone(); + if (num.cmpn(0) === 0) + return this.clone(); + + var a = this.clone(); + var b = num.clone(); + a.sign = false; + b.sign = false; + + // Remove common factor of two + for (var shift = 0; a.isEven() && b.isEven(); shift++) { + a.ishrn(1); + b.ishrn(1); + } + + while (a.isEven()) + a.ishrn(1); + + do { + while (b.isEven()) + b.ishrn(1); + + // Swap `a` and `b` to make `a` always bigger than `b` + if (a.cmp(b) < 0) { + var t = a; + a = b; + b = t; + } + a.isub(a.div(b).mul(b)); + } while (a.cmpn(0) !== 0 && b.cmpn(0) !== 0); + if (a.cmpn(0) === 0) + return b.ishln(shift); + else + return a.ishln(shift); +}; + +// Invert number in the field F(num) +BN.prototype.invm = function invm(num) { + return this._egcd(new BN(1), num).mod(num); +}; + +BN.prototype.isEven = function isEven(num) { + return (this.words[0] & 1) === 0; +}; + +BN.prototype.isOdd = function isOdd(num) { + 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) { + for (var i = this.length; i < s + 1; i++) + this.words[i] = 0; + this.words[s] |= q; + this.length = s + 1; + 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]; + w += carry; + carry = w >>> 26; + w &= 0x3ffffff; + this.words[i] = w; + } + if (carry !== 0) { + this.words[i] = carry; + this.length++; + } + return this; +}; + +BN.prototype.cmpn = function cmpn(num) { + var sign = num < 0; + if (sign) + num = -num; + + if (this.sign && !sign) + return -1; + else if (!this.sign && sign) + return 1; + + num &= 0x3ffffff; + this.strip(); + + var res; + if (this.length > 1) { + res = 1; + } else { + var w = this.words[0]; + res = w === num ? 0 : w < num ? -1 : 1; + } + if (this.sign) + res = -res; + 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.sign && !num.sign) + return -1; + else if (!this.sign && num.sign) + return 1; + + var res = this.ucmp(num); + if (this.sign) + return -res; + else + 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; + else if (this.length < num.length) + return -1; + + var res = 0; + for (var i = this.length - 1; i >= 0; i--) { + var a = this.words[i]; + var b = num.words[i]; + + if (a === b) + continue; + if (a < b) + res = -1; + else if (a > b) + res = 1; + break; + } + return res; +}; + +// +// 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.sign, '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).ishln(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 { + var pair = r.ishrn(this.n, 0, this.tmp); + r = this.imulK(pair.hi); + r = r.iadd(pair.lo); + rlen = r.bitLength(); + } while (rlen > this.n); + + var cmp = rlen < this.n ? -1 : r.cmp(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.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.imulK = function imulK(num) { + // K = 0x1000003d1 = [ 0x40, 0x3d1 ] + num.words[num.length] = 0; + num.words[num.length + 1] = 0; + num.length += 2; + + var uhi = 0; + var hi = 0; + var lo = 0; + for (var i = 0; i < num.length; i++) { + var w = num.words[i]; + hi += w * 0x40; + lo += w * 0x3d1; + hi += (lo / 0x4000000) | 0; + uhi += (hi / 0x4000000) | 0; + hi &= 0x3ffffff; + lo &= 0x3ffffff; + + num.words[i] = lo; + + lo = hi; + hi = uhi; + uhi = 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] * 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 { + this.m = m; + this.prime = null; + } +} + +Red.prototype._verify1 = function _verify1(a) { + assert(!a.sign, 'red works only with positives'); + assert(a.red, 'red works only with red numbers'); +}; + +Red.prototype._verify2 = function _verify2(a, b) { + assert(!a.sign && !b.sign, '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.mod(this.m)._forceRed(this); +}; + +Red.prototype.neg = function neg(a) { + var r = a.clone(); + r.sign = !r.sign; + return r.iadd(this.m)._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.shln(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); +}; + +Red.prototype.sqr = function sqr(a) { + return this.mul(a, a); +}; + +Red.prototype.sqrt = function sqrt(a) { + if (a.cmpn(0) === 0) + 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)).ishrn(2); + var r = this.pow(a, pow); + return r; + } + + // 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.cmpn(0) !== 0 && q.andln(1) === 0) { + s++; + q.ishrn(1); + } + assert(q.cmpn(0) !== 0); + + 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).ishrn(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).ishrn(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).ishln(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._egcd(new BN(1), this.m); + if (inv.sign) { + inv.sign = false; + return this.imod(inv).redNeg(); + } else { + return this.imod(inv); + } +}; + +Red.prototype.pow = function pow(a, num) { + var w = []; + var q = num.clone(); + while (q.cmpn(0) !== 0) { + w.push(q.andln(1)); + q.ishrn(1); + } + + // Skip leading zeroes + var res = a; + for (var i = 0; i < w.length; i++, res = this.sqr(res)) + if (w[i] !== 0) + break; + + if (++i < w.length) { + for (var q = this.sqr(res); i < w.length; i++, q = this.sqr(q)) { + if (w[i] === 0) + continue; + res = this.mul(res, q); + } + } + + return res; +}; + +Red.prototype.convertTo = function convertTo(num) { + return num.clone(); +}; + +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).ishln(this.shift); + this.r2 = this.imod(this.r.sqr()); + this.rinv = this.r.invm(this.m); + + // TODO(indutny): simplify it + this.minv = this.rinv.mul(this.r) + .sub(new BN(1)) + .div(this.m) + .neg() + .mod(this.r); +} +inherits(Mont, Red); + +Mont.prototype.convertTo = function convertTo(num) { + return this.imod(num.shln(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.cmpn(0) === 0 || b.cmpn(0) === 0) { + 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).ishrn(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.cmpn(0) === 0 || b.cmpn(0) === 0) + 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).ishrn(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.invm(this.m).mul(this.r2)); + return res._forceRed(this); +}; + +},{}],73:[function(require,module,exports){ +// Base58 encoding/decoding +// Originally written by Mike Hearn for BitcoinJ +// Copyright (c) 2011 Google Inc +// Ported to JavaScript by Stefan Thomas +// Merged Buffer refactorings from base58-native by Stephen Pair +// Copyright (c) 2013 BitPay Inc + +var ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' +var ALPHABET_MAP = {} +for(var i = 0; i < ALPHABET.length; i++) { + ALPHABET_MAP[ALPHABET.charAt(i)] = i +} +var BASE = 58 + +function encode(buffer) { + if (buffer.length === 0) return '' + + var i, j, digits = [0] + for (i = 0; i < buffer.length; i++) { + for (j = 0; j < digits.length; j++) digits[j] <<= 8 + + digits[0] += buffer[i] + + var carry = 0 + for (j = 0; j < digits.length; ++j) { + digits[j] += carry + + carry = (digits[j] / BASE) | 0 + digits[j] %= BASE + } + + while (carry) { + digits.push(carry % BASE) + + carry = (carry / BASE) | 0 + } + } + + // deal with leading zeros + for (i = 0; buffer[i] === 0 && i < buffer.length - 1; i++) digits.push(0) + + return digits.reverse().map(function(digit) { return ALPHABET[digit] }).join('') +} + +function decode(string) { + if (string.length === 0) return [] + + var i, j, bytes = [0] + for (i = 0; i < string.length; i++) { + var c = string[i] + if (!(c in ALPHABET_MAP)) throw new Error('Non-base58 character') + + for (j = 0; j < bytes.length; j++) bytes[j] *= BASE + bytes[0] += ALPHABET_MAP[c] + + var carry = 0 + for (j = 0; j < bytes.length; ++j) { + bytes[j] += carry + + carry = bytes[j] >> 8 + bytes[j] &= 0xff + } + + while (carry) { + bytes.push(carry & 0xff) + + carry >>= 8 + } + } + + // deal with leading zeros + for (i = 0; string[i] === '1' && i < string.length - 1; i++) bytes.push(0) + + return bytes.reverse() +} + +module.exports = { + encode: encode, + decode: decode +} + +},{}],74:[function(require,module,exports){ +var elliptic = exports; + +elliptic.version = require('../package.json').version; +elliptic.utils = require('./elliptic/utils'); +elliptic.rand = require('brorand'); +elliptic.hmacDRBG = require('./elliptic/hmac-drbg'); +elliptic.curve = require('./elliptic/curve'); +elliptic.curves = require('./elliptic/curves'); + +// Protocols +elliptic.ec = require('./elliptic/ec'); + +},{"../package.json":87,"./elliptic/curve":77,"./elliptic/curves":80,"./elliptic/ec":81,"./elliptic/hmac-drbg":84,"./elliptic/utils":85,"brorand":86}],75:[function(require,module,exports){ +var assert = require('assert'); +var bn = require('bn.js'); +var elliptic = require('../../elliptic'); + +var getNAF = elliptic.utils.getNAF; +var getJSF = elliptic.utils.getJSF; + +function BaseCurve(type, conf) { + this.type = type; + this.p = new bn(conf.p, 16); + + // Use Montgomery, when there is no fast reduction for the prime + this.red = conf.prime ? bn.red(conf.prime) : bn.mont(this.p); + + // Useful for many curves + this.zero = new bn(0).toRed(this.red); + this.one = new bn(1).toRed(this.red); + this.two = new bn(2).toRed(this.red); + + // Curve configuration, optional + this.n = conf.n && new bn(conf.n, 16); + this.g = conf.g && this.pointFromJSON(conf.g, conf.gRed); + + // Temporary arrays + this._wnafT1 = new Array(4); + this._wnafT2 = new Array(4); + this._wnafT3 = new Array(4); + this._wnafT4 = new Array(4); +} +module.exports = BaseCurve; + +BaseCurve.prototype.point = function point() { + throw new Error('Not implemented'); +}; + +BaseCurve.prototype.validate = function validate(point) { + throw new Error('Not implemented'); +}; + +BaseCurve.prototype._fixedNafMul = function _fixedNafMul(p, k) { + var doubles = p._getDoubles(); + + var naf = getNAF(k, 1); + var I = (1 << (doubles.step + 1)) - (doubles.step % 2 === 0 ? 2 : 1); + I /= 3; + + // Translate into more windowed form + var repr = []; + for (var j = 0; j < naf.length; j += doubles.step) { + var nafW = 0; + for (var k = j + doubles.step - 1; k >= j; k--) + nafW = (nafW << 1) + naf[k]; + repr.push(nafW); + } + + var a = this.jpoint(null, null, null); + var b = this.jpoint(null, null, null); + for (var i = I; i > 0; i--) { + for (var j = 0; j < repr.length; j++) { + var nafW = repr[j]; + if (nafW === i) + b = b.mixedAdd(doubles.points[j]); + else if (nafW === -i) + b = b.mixedAdd(doubles.points[j].neg()); + } + a = a.add(b); + } + return a.toP(); +}; + +BaseCurve.prototype._wnafMul = function _wnafMul(p, k) { + var w = 4; + + // Precompute window + var nafPoints = p._getNAFPoints(w); + w = nafPoints.wnd; + var wnd = nafPoints.points; + + // Get NAF form + var naf = getNAF(k, w); + + // Add `this`*(N+1) for every w-NAF index + var acc = this.jpoint(null, null, null); + for (var i = naf.length - 1; i >= 0; i--) { + // Count zeroes + for (var k = 0; i >= 0 && naf[i] === 0; i--) + k++; + if (i >= 0) + k++; + acc = acc.dblp(k); + + if (i < 0) + break; + var z = naf[i]; + assert(z !== 0); + if (p.type === 'affine') { + // J +- P + if (z > 0) + acc = acc.mixedAdd(wnd[(z - 1) >> 1]); + else + acc = acc.mixedAdd(wnd[(-z - 1) >> 1].neg()); + } else { + // J +- J + if (z > 0) + acc = acc.add(wnd[(z - 1) >> 1]); + else + acc = acc.add(wnd[(-z - 1) >> 1].neg()); + } + } + return p.type === 'affine' ? acc.toP() : acc; +}; + +BaseCurve.prototype._wnafMulAdd = function _wnafMulAdd(defW, + points, + coeffs, + len) { + var wndWidth = this._wnafT1; + var wnd = this._wnafT2; + var naf = this._wnafT3; + + // Fill all arrays + var max = 0; + for (var i = 0; i < len; i++) { + var p = points[i]; + var nafPoints = p._getNAFPoints(defW); + wndWidth[i] = nafPoints.wnd; + wnd[i] = nafPoints.points; + } + + // Comb small window NAFs + for (var i = len - 1; i >= 1; i -= 2) { + var a = i - 1; + var b = i; + if (wndWidth[a] !== 1 || wndWidth[b] !== 1) { + naf[a] = getNAF(coeffs[a], wndWidth[a]); + naf[b] = getNAF(coeffs[b], wndWidth[b]); + max = Math.max(naf[a].length, max); + max = Math.max(naf[b].length, max); + continue; + } + + var comb = [ + points[a], /* 1 */ + null, /* 3 */ + null, /* 5 */ + points[b] /* 7 */ + ]; + + // Try to avoid Projective points, if possible + if (points[a].y.cmp(points[b].y) === 0) { + comb[1] = points[a].add(points[b]); + comb[2] = points[a].toJ().mixedAdd(points[b].neg()); + } else if (points[a].y.cmp(points[b].y.redNeg()) === 0) { + comb[1] = points[a].toJ().mixedAdd(points[b]); + comb[2] = points[a].add(points[b].neg()); + } else { + comb[1] = points[a].toJ().mixedAdd(points[b]); + comb[2] = points[a].toJ().mixedAdd(points[b].neg()); + } + + var index = [ + -3, /* -1 -1 */ + -1, /* -1 0 */ + -5, /* -1 1 */ + -7, /* 0 -1 */ + 0, /* 0 0 */ + 7, /* 0 1 */ + 5, /* 1 -1 */ + 1, /* 1 0 */ + 3 /* 1 1 */ + ]; + + var jsf = getJSF(coeffs[a], coeffs[b]); + max = Math.max(jsf[0].length, max); + naf[a] = new Array(max); + naf[b] = new Array(max); + for (var j = 0; j < max; j++) { + var ja = jsf[0][j] | 0; + var jb = jsf[1][j] | 0; + + naf[a][j] = index[(ja + 1) * 3 + (jb + 1)]; + naf[b][j] = 0; + wnd[a] = comb; + } + } + + var acc = this.jpoint(null, null, null); + var tmp = this._wnafT4; + for (var i = max; i >= 0; i--) { + var k = 0; + + while (i >= 0) { + var zero = true; + for (var j = 0; j < len; j++) { + tmp[j] = naf[j][i] | 0; + if (tmp[j] !== 0) + zero = false; + } + if (!zero) + break; + k++; + i--; + } + if (i >= 0) + k++; + acc = acc.dblp(k); + if (i < 0) + break; + + for (var j = 0; j < len; j++) { + var z = tmp[j]; + var p; + if (z === 0) + continue; + else if (z > 0) + p = wnd[j][(z - 1) >> 1]; + else if (z < 0) + p = wnd[j][(-z - 1) >> 1].neg(); + + if (p.type === 'affine') + acc = acc.mixedAdd(p); + else + acc = acc.add(p); + } + } + // Zeroify references + for (var i = 0; i < len; i++) + wnd[i] = null; + return acc.toP(); +}; + +BaseCurve.BasePoint = BasePoint; + +function BasePoint(curve, type) { + this.curve = curve; + this.type = type; + this.precomputed = null; +} + +BasePoint.prototype.validate = function validate() { + return this.curve.validate(this); +}; + +BasePoint.prototype.precompute = function precompute(power, _beta) { + if (this.precomputed) + return this; + + var precomputed = { + doubles: null, + naf: null, + beta: null + }; + precomputed.naf = this._getNAFPoints(8); + precomputed.doubles = this._getDoubles(4, power); + precomputed.beta = this._getBeta(); + this.precomputed = precomputed; + + return this; +}; + +BasePoint.prototype._getDoubles = function _getDoubles(step, power) { + if (this.precomputed && this.precomputed.doubles) + return this.precomputed.doubles; + + var doubles = [ this ]; + var acc = this; + for (var i = 0; i < power; i += step) { + for (var j = 0; j < step; j++) + acc = acc.dbl(); + doubles.push(acc); + } + return { + step: step, + points: doubles + }; +}; + +BasePoint.prototype._getNAFPoints = function _getNAFPoints(wnd) { + if (this.precomputed && this.precomputed.naf) + return this.precomputed.naf; + + var res = [ this ]; + var max = (1 << wnd) - 1; + var dbl = max === 1 ? null : this.dbl(); + for (var i = 1; i < max; i++) + res[i] = res[i - 1].add(dbl); + return { + wnd: wnd, + points: res + }; +}; + +BasePoint.prototype._getBeta = function _getBeta() { + return null; +}; + +BasePoint.prototype.dblp = function dblp(k) { + var r = this; + for (var i = 0; i < k; i++) + r = r.dbl(); + return r; +}; + +},{"../../elliptic":74,"assert":194,"bn.js":72}],76:[function(require,module,exports){ +var assert = require('assert'); +var curve = require('../curve'); +var elliptic = require('../../elliptic'); +var bn = require('bn.js'); +var inherits = require('inherits'); +var Base = curve.base; + +var getNAF = elliptic.utils.getNAF; + +function EdwardsCurve(conf) { + // NOTE: Important as we are creating point in Base.call() + this.twisted = conf.a != 1; + this.mOneA = this.twisted && conf.a == -1; + this.extended = this.mOneA; + + Base.call(this, 'mont', conf); + + this.a = new bn(conf.a, 16).mod(this.red.m).toRed(this.red); + this.c = new bn(conf.c, 16).toRed(this.red); + this.c2 = this.c.redSqr(); + this.d = new bn(conf.d, 16).toRed(this.red); + this.dd = this.d.redAdd(this.d); + + assert(!this.twisted || this.c.fromRed().cmpn(1) === 0); + this.oneC = conf.c == 1; +} +inherits(EdwardsCurve, Base); +module.exports = EdwardsCurve; + +EdwardsCurve.prototype._mulA = function _mulA(num) { + if (this.mOneA) + return num.redNeg(); + else + return this.a.redMul(num); +}; + +EdwardsCurve.prototype._mulC = function _mulC(num) { + if (this.oneC) + return num; + else + return this.c.redMul(num); +}; + +EdwardsCurve.prototype.point = function point(x, y, z, t) { + return new Point(this, x, y, z, t); +}; + +// Just for compatibility with Short curve +EdwardsCurve.prototype.jpoint = function jpoint(x, y, z, t) { + return this.point(x, y, z, t); +}; + +EdwardsCurve.prototype.pointFromJSON = function pointFromJSON(obj) { + return Point.fromJSON(this, obj); +}; + +EdwardsCurve.prototype.pointFromX = function pointFromX(odd, x) { + x = new bn(x, 16); + if (!x.red) + x = x.toRed(this.red); + + var x2 = x.redSqr(); + var rhs = this.c2.redSub(this.a.redMul(x2)); + var lhs = this.one.redSub(this.c2.redMul(this.d).redMul(x2)); + + var y = rhs.redMul(lhs.redInvm()).redSqrt(); + var isOdd = y.fromRed().isOdd(); + if (odd && !isOdd || !odd && isOdd) + y = y.redNeg(); + + return this.point(x, y, curve.one); +}; + +EdwardsCurve.prototype.validate = function validate(point) { + if (point.isInfinity()) + return true; + + // Curve: A * X^2 + Y^2 = C^2 * (1 + D * X^2 * Y^2) + point.normalize(); + + var x2 = point.x.redSqr(); + var y2 = point.y.redSqr(); + var lhs = x2.redMul(this.a).redAdd(y2); + var rhs = this.c2.redMul(this.one.redAdd(this.d.redMul(x2).redMul(y2))); + + return lhs.cmp(rhs) === 0; +}; + +function Point(curve, x, y, z, t) { + Base.BasePoint.call(this, curve, 'projective'); + if (x === null && y === null && z === null) { + this.x = this.curve.zero; + this.y = this.curve.one; + this.z = this.curve.one; + this.t = this.curve.zero; + this.zOne = true; + } else { + this.x = new bn(x, 16); + this.y = new bn(y, 16); + this.z = z ? new bn(z, 16) : this.curve.one; + this.t = t && new bn(t, 16); + if (!this.x.red) + this.x = this.x.toRed(this.curve.red); + if (!this.y.red) + this.y = this.y.toRed(this.curve.red); + if (!this.z.red) + this.z = this.z.toRed(this.curve.red); + if (this.t && !this.t.red) + this.t = this.t.toRed(this.curve.red); + this.zOne = this.z === this.curve.one; + + // Use extended coordinates + if (this.curve.extended && !this.t) { + this.t = this.x.redMul(this.y); + if (!this.zOne) + this.t = this.t.redMul(this.z.redInvm()); + } + } +} +inherits(Point, Base.BasePoint); + +Point.fromJSON = function fromJSON(curve, obj) { + return new Point(curve, obj[0], obj[1], obj[2]); +}; + +Point.prototype.inspect = function inspect() { + if (this.isInfinity()) + return ''; + return ''; +}; + +Point.prototype.isInfinity = function isInfinity() { + // XXX This code assumes that zero is always zero in red + return this.x.cmpn(0) === 0 && + this.y.cmp(this.z) === 0; +}; + +Point.prototype._extDbl = function _extDbl() { + // http://hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html#doubling-dbl-2008-hwcd + // 4M + 4S + + // A = X1^2 + var a = this.x.redSqr(); + // B = Y1^2 + var b = this.y.redSqr(); + // C = 2 * Z1^2 + var c = this.z.redSqr(); + c = c.redIAdd(c); + // D = a * A + var d = this.curve._mulA(a); + // E = (X1 + Y1)^2 - A - B + var e = this.x.redAdd(this.y).redSqr().redISub(a).redISub(b); + // G = D + B + var g = d.redAdd(b); + // F = G - C + var f = g.redSub(c); + // H = D - B + var h = d.redSub(b); + // X3 = E * F + var nx = e.redMul(f); + // Y3 = G * H + var ny = g.redMul(h); + // T3 = E * H + var nt = e.redMul(h); + // Z3 = F * G + var nz = f.redMul(g); + return this.curve.point(nx, ny, nz, nt); +}; + +Point.prototype._projDbl = function _projDbl() { + // http://hyperelliptic.org/EFD/g1p/auto-twisted-projective.html#doubling-dbl-2008-bbjlp + // http://hyperelliptic.org/EFD/g1p/auto-edwards-projective.html#doubling-dbl-2007-bl + // and others + // Generally 3M + 4S or 2M + 4S + + // B = (X1 + Y1)^2 + var b = this.x.redAdd(this.y).redSqr(); + // C = X1^2 + var c = this.x.redSqr(); + // D = Y1^2 + var d = this.y.redSqr(); + + if (this.curve.twisted) { + // E = a * C + var e = this.curve._mulA(c); + // F = E + D + var f = e.redAdd(d); + if (this.zOne) { + // X3 = (B - C - D) * (F - 2) + var nx = b.redSub(c).redSub(d).redMul(f.redSub(this.curve.two)); + // Y3 = F * (E - D) + var ny = f.redMul(e.redSub(d)); + // Z3 = F^2 - 2 * F + var nz = f.redSqr().redSub(f).redSub(f); + } else { + // H = Z1^2 + var h = this.z.redSqr(); + // J = F - 2 * H + var j = f.redSub(h).redISub(h); + // X3 = (B-C-D)*J + var nx = b.redSub(c).redISub(d).redMul(j); + // Y3 = F * (E - D) + var ny = f.redMul(e.redSub(d)); + // Z3 = F * J + var nz = f.redMul(j); + } + } else { + // E = C + D + var e = c.redAdd(d); + // H = (c * Z1)^2 + var h = this.curve._mulC(redMul(this.z)).redSqr(); + // J = E - 2 * H + var j = e.redSub(h).redSub(h); + // X3 = c * (B - E) * J + var nx = this.curve._mulC(b.redISub(e)).redMul(j); + // Y3 = c * E * (C - D) + var ny = this.curve._mulC(e).redMul(c.redISub(d)); + // Z3 = E * J + var nz = e.redMul(j); + } + return this.curve.point(nx, ny, nz); +}; + +Point.prototype.dbl = function dbl() { + if (this.isInfinity()) + return this; + + // Double in extended coordinates + if (this.curve.extended) + return this._extDbl(); + else + return this._projDbl(); +}; + +Point.prototype._extAdd = function _extAdd(p) { + // http://hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html#addition-add-2008-hwcd-3 + // 8M + + // A = (Y1 - X1) * (Y2 - X2) + var a = this.y.redSub(this.x).redMul(p.y.redSub(p.x)); + // B = (Y1 + X1) * (Y2 + X2) + var b = this.y.redAdd(this.x).redMul(p.y.redAdd(p.x)); + // C = T1 * k * T2 + var c = this.t.redMul(this.curve.dd).redMul(p.t); + // D = Z1 * 2 * Z2 + var d = this.z.redMul(p.z.redAdd(p.z)); + // E = B - A + var e = b.redSub(a); + // F = D - C + var f = d.redSub(c); + // G = D + C + var g = d.redAdd(c); + // H = B + A + var h = b.redAdd(a); + // X3 = E * F + var nx = e.redMul(f); + // Y3 = G * H + var ny = g.redMul(h); + // T3 = E * H + var nt = e.redMul(h); + // Z3 = F * G + var nz = f.redMul(g); + return this.curve.point(nx, ny, nz, nt); +}; + +Point.prototype._projAdd = function _projAdd(p) { + // http://hyperelliptic.org/EFD/g1p/auto-twisted-projective.html#addition-add-2008-bbjlp + // http://hyperelliptic.org/EFD/g1p/auto-edwards-projective.html#addition-add-2007-bl + // 10M + 1S + + // A = Z1 * Z2 + var a = this.z.redMul(p.z); + // B = A^2 + var b = a.redSqr(); + // C = X1 * X2 + var c = this.x.redMul(p.x); + // D = Y1 * Y2 + var d = this.y.redMul(p.y); + // E = d * C * D + var e = this.curve.d.redMul(c).redMul(d); + // F = B - E + var f = b.redSub(e); + // G = B + E + var g = b.redAdd(e); + // X3 = A * F * ((X1 + Y1) * (X2 + Y2) - C - D) + var tmp = this.x.redAdd(this.y).redMul(p.x.redAdd(p.y)).redISub(c).redISub(d); + var nx = a.redMul(f).redMul(tmp); + if (this.curve.twisted) { + // Y3 = A * G * (D - a * C) + var ny = a.redMul(g).redMul(d.redSub(this.curve._mulA(c))); + // Z3 = F * G + var nz = f.redMul(g); + } else { + // Y3 = A * G * (D - C) + var ny = a.redMul(g).redMul(d.redSub(c)); + // Z3 = c * F * G + var nz = this.curve._mulC(f).redMul(g); + } + return this.curve.point(nx, ny, nz); +}; + +Point.prototype.add = function add(p) { + if (this.isInfinity()) + return p; + if (p.isInfinity()) + return this; + + if (this.curve.extended) + return this._extAdd(p); + else + return this._projAdd(p); +}; + +Point.prototype.mul = function mul(k) { + if (this.precomputed && this.precomputed.doubles) + return this.curve._fixedNafMul(this, k); + else + return this.curve._wnafMul(this, k); +}; + +Point.prototype.mulAdd = function mulAdd(k1, p, k2) { + return this.curve._wnafMulAdd(1, [ this, p ], [ k1, k2 ], 2); +}; + +Point.prototype.normalize = function normalize() { + if (this.zOne) + return this; + + // Normalize coordinates + var zi = this.z.redInvm(); + this.x = this.x.redMul(zi); + this.y = this.y.redMul(zi); + if (this.t) + this.t = this.t.redMul(zi); + this.z = this.curve.one; + this.zOne = true; + return this; +}; + +Point.prototype.neg = function neg() { + return this.curve.point(this.x.redNeg(), + this.y, + this.z, + this.t && this.t.redNeg()); +}; + +Point.prototype.getX = function getX() { + this.normalize(); + return this.x.fromRed(); +}; + +Point.prototype.getY = function getY() { + this.normalize(); + return this.y.fromRed(); +}; + +// Compatibility with BaseCurve +Point.prototype.toP = Point.prototype.normalize; +Point.prototype.mixedAdd = Point.prototype.add; + +},{"../../elliptic":74,"../curve":77,"assert":194,"bn.js":72,"inherits":94}],77:[function(require,module,exports){ +var curve = exports; + +curve.base = require('./base'); +curve.short = require('./short'); +curve.mont = require('./mont'); +curve.edwards = require('./edwards'); + +},{"./base":75,"./edwards":76,"./mont":78,"./short":79}],78:[function(require,module,exports){ +var assert = require('assert'); +var curve = require('../curve'); +var elliptic = require('../../elliptic'); +var bn = require('bn.js'); +var inherits = require('inherits'); +var Base = curve.base; + +var getNAF = elliptic.utils.getNAF; + +function MontCurve(conf) { + Base.call(this, 'mont', conf); + + this.a = new bn(conf.a, 16).toRed(this.red); + this.b = new bn(conf.b, 16).toRed(this.red); + this.i4 = new bn(4).toRed(this.red).redInvm(); + this.two = new bn(2).toRed(this.red); + this.a24 = this.i4.redMul(this.a.redAdd(this.two)); +} +inherits(MontCurve, Base); +module.exports = MontCurve; + +MontCurve.prototype.point = function point(x, z) { + return new Point(this, x, z); +}; + +MontCurve.prototype.pointFromJSON = function pointFromJSON(obj) { + return Point.fromJSON(this, obj); +} + +MontCurve.prototype.validate = function validate(point) { + var x = point.normalize().x; + var x2 = x.redSqr(); + var rhs = x2.redMul(x).redAdd(x2.redMul(this.a)).redAdd(x); + var y = rhs.redSqrt(); + + return y.redSqr().cmp(rhs) === 0; +}; + +function Point(curve, x, z) { + Base.BasePoint.call(this, curve, 'projective'); + if (x === null && z === null) { + this.x = this.curve.one; + this.z = this.curve.zero; + } else { + this.x = new bn(x, 16); + this.z = new bn(z, 16); + if (!this.x.red) + this.x = this.x.toRed(this.curve.red); + if (!this.z.red) + this.z = this.z.toRed(this.curve.red); + } +} +inherits(Point, Base.BasePoint); + +Point.prototype.precompute = function precompute() { + // No-op +}; + +Point.fromJSON = function fromJSON(curve, obj) { + return new Point(curve, obj[0], obj[1] || curve.one); +}; + +Point.prototype.inspect = function inspect() { + if (this.isInfinity()) + return ''; + return ''; +}; + +Point.prototype.isInfinity = function isInfinity() { + // XXX This code assumes that zero is always zero in red + return this.z.cmpn(0) === 0; +}; + +Point.prototype.dbl = function dbl() { + // http://hyperelliptic.org/EFD/g1p/auto-montgom-xz.html#doubling-dbl-1987-m-3 + // 2M + 2S + 4A + + // A = X1 + Z1 + var a = this.x.redAdd(this.z); + // AA = A^2 + var aa = a.redSqr(); + // B = X1 - Z1 + var b = this.x.redSub(this.z); + // BB = B^2 + var bb = b.redSqr(); + // C = AA - BB + var c = aa.redSub(bb); + // X3 = AA * BB + var nx = aa.redMul(bb); + // Z3 = C * (BB + A24 * C) + var nz = c.redMul(bb.redAdd(this.curve.a24.redMul(c))); + return this.curve.point(nx, nz); +}; + +Point.prototype.add = function add(p) { + throw new Error('Not supported on Montgomery curve'); +}; + +Point.prototype.diffAdd = function diffAdd(p, diff) { + // http://hyperelliptic.org/EFD/g1p/auto-montgom-xz.html#diffadd-dadd-1987-m-3 + // 4M + 2S + 6A + + // A = X2 + Z2 + var a = this.x.redAdd(this.z); + // B = X2 - Z2 + var b = this.x.redSub(this.z); + // C = X3 + Z3 + var c = p.x.redAdd(p.z); + // D = X3 - Z3 + var d = p.x.redSub(p.z); + // DA = D * A + var da = d.redMul(a); + // CB = C * B + var cb = c.redMul(b); + // X5 = Z1 * (DA + CB)^2 + var nx = diff.z.redMul(da.redAdd(cb).redSqr()); + // Z5 = X1 * (DA - CB)^2 + var nz = diff.x.redMul(da.redISub(cb).redSqr()); + return this.curve.point(nx, nz); +}; + +Point.prototype.mul = function mul(k) { + var t = k.clone(); + var a = this; // (N / 2) * Q + Q + var b = this.curve.point(null, null); // (N / 2) * Q + var c = this; // Q + + for (var bits = []; t.cmpn(0) !== 0; t.ishrn(1)) + bits.push(t.andln(1)); + + for (var i = bits.length - 1; i >= 0; i--) { + if (bits[i] === 0) { + // N * Q + Q = ((N / 2) * Q + Q)) + (N / 2) * Q + a = a.diffAdd(b, c); + // N * Q = 2 * ((N / 2) * Q + Q)) + b = b.dbl(); + } else { + // N * Q = ((N / 2) * Q + Q) + ((N / 2) * Q) + b = a.diffAdd(b, c); + // N * Q + Q = 2 * ((N / 2) * Q + Q) + a = a.dbl(); + } + } + return b; +}; + +Point.prototype.mulAdd = function mulAdd() { + throw new Error('Not supported on Montgomery curve'); +}; + +Point.prototype.normalize = function normalize() { + this.x = this.x.redMul(this.z.redInvm()); + this.z = this.curve.one; + return this; +}; + +Point.prototype.getX = function getX() { + // Normalize coordinates + this.normalize(); + + return this.x.fromRed(); +}; + +},{"../../elliptic":74,"../curve":77,"assert":194,"bn.js":72,"inherits":94}],79:[function(require,module,exports){ +var assert = require('assert'); +var curve = require('../curve'); +var elliptic = require('../../elliptic'); +var bn = require('bn.js'); +var inherits = require('inherits'); +var Base = curve.base; + +var getNAF = elliptic.utils.getNAF; + +function ShortCurve(conf) { + Base.call(this, 'short', conf); + + this.a = new bn(conf.a, 16).toRed(this.red); + this.b = new bn(conf.b, 16).toRed(this.red); + this.tinv = this.two.redInvm(); + + this.zeroA = this.a.fromRed().cmpn(0) === 0; + this.threeA = this.a.fromRed().sub(this.p).cmpn(-3) === 0; + + // If the curve is endomorphic, precalculate beta and lambda + this.endo = this._getEndomorphism(conf); + this._endoWnafT1 = new Array(4); + this._endoWnafT2 = new Array(4); +} +inherits(ShortCurve, Base); +module.exports = ShortCurve; + +ShortCurve.prototype._getEndomorphism = function _getEndomorphism(conf) { + // No efficient endomorphism + if (!this.zeroA || !this.g || !this.n || this.p.modn(3) !== 1) + return; + + // Compute beta and lambda, that lambda * P = (beta * Px; Py) + var beta; + var lambda; + if (conf.beta) { + beta = new bn(conf.beta, 16).toRed(this.red); + } else { + var betas = this._getEndoRoots(this.p); + // Choose the smallest beta + beta = betas[0].cmp(betas[1]) < 0 ? betas[0] : betas[1]; + beta = beta.toRed(this.red); + } + if (conf.lambda) { + lambda = new bn(conf.lambda, 16); + } else { + // Choose the lambda that is matching selected beta + var lambdas = this._getEndoRoots(this.n); + if (this.g.mul(lambdas[0]).x.cmp(this.g.x.redMul(beta)) === 0) { + lambda = lambdas[0]; + } else { + lambda = lambdas[1]; + assert(this.g.mul(lambda).x.cmp(this.g.x.redMul(beta)) === 0); + } + } + + // Get basis vectors, used for balanced length-two representation + var basis; + if (conf.basis) { + basis = conf.basis.map(function(vec) { + return { + a: new bn(vec.a, 16), + b: new bn(vec.b, 16), + }; + }); + } else { + basis = this._getEndoBasis(lambda); + } + + return { + beta: beta, + lambda: lambda, + basis: basis + }; +}; + +ShortCurve.prototype._getEndoRoots = function _getEndoRoots(num) { + // Find roots of for x^2 + x + 1 in F + // Root = (-1 +- Sqrt(-3)) / 2 + // + var red = num === this.p ? this.red : bn.mont(num); + var tinv = new bn(2).toRed(red).redInvm(); + var ntinv = tinv.redNeg(); + var one = new bn(1).toRed(red); + + var s = new bn(3).toRed(red).redNeg().redSqrt().redMul(tinv); + + var l1 = ntinv.redAdd(s).fromRed(); + var l2 = ntinv.redSub(s).fromRed(); + return [ l1, l2 ]; +}; + +ShortCurve.prototype._getEndoBasis = function _getEndoBasis(lambda) { + // aprxSqrt >= sqrt(this.n) + var aprxSqrt = this.n.shrn(Math.floor(this.n.bitLength() / 2)); + + // 3.74 + // Run EGCD, until r(L + 1) < aprxSqrt + var u = lambda; + var v = this.n.clone(); + var x1 = new bn(1); + var y1 = new bn(0); + var x2 = new bn(0); + var y2 = new bn(1); + + // NOTE: all vectors are roots of: a + b * lambda = 0 (mod n) + var a0; + var b0; + // First vector + var a1; + var b1; + // Second vector + var a2; + var b2; + + var prevR; + var i = 0; + while (u.cmpn(0) !== 0) { + var q = v.div(u); + var r = v.sub(q.mul(u)); + var x = x2.sub(q.mul(x1)); + var y = y2.sub(q.mul(y1)); + + if (!a1 && r.cmp(aprxSqrt) < 0) { + a0 = prevR.neg(); + b0 = x1; + a1 = r.neg(); + b1 = x; + } else if (a1 && ++i === 2) { + break; + } + prevR = r; + + v = u; + u = r; + x2 = x1; + x1 = x; + y2 = y1; + y1 = y; + } + a2 = r.neg(); + b2 = x; + + var len1 = a1.sqr().add(b1.sqr()); + var len2 = a2.sqr().add(b2.sqr()); + if (len2.cmp(len1) >= 0) { + a2 = a0; + b2 = b0; + } + + // Normalize signs + if (a1.sign) { + a1 = a1.neg(); + b1 = b1.neg(); + } + if (a2.sign) { + a2 = a2.neg(); + b2 = b2.neg(); + } + + return [ + { a: a1, b: b1 }, + { a: a2, b: b2 } + ]; +}; + +ShortCurve.prototype._endoSplit = function _endoSplit(k) { + var basis = this.endo.basis; + var v1 = basis[0]; + var v2 = basis[1]; + + var c1 = v2.b.mul(k).divRound(this.n); + var c2 = v1.b.neg().mul(k).divRound(this.n); + + var p1 = c1.mul(v1.a); + var p2 = c2.mul(v2.a); + var q1 = c1.mul(v1.b); + var q2 = c2.mul(v2.b); + + // Calculate answer + var k1 = k.sub(p1).sub(p2); + var k2 = q1.add(q2).neg(); + return { k1: k1, k2: k2 }; +}; + +ShortCurve.prototype.point = function point(x, y, isRed) { + return new Point(this, x, y, isRed); +}; + +ShortCurve.prototype.pointFromX = function pointFromX(odd, x) { + x = new bn(x, 16); + if (!x.red) + x = x.toRed(this.red); + + var y2 = x.redSqr().redMul(x).redIAdd(x.redMul(this.a)).redIAdd(this.b); + var y = y2.redSqrt(); + + // XXX Is there any way to tell if the number is odd without converting it + // to non-red form? + var isOdd = y.fromRed().isOdd(); + if (odd && !isOdd || !odd && isOdd) + y = y.redNeg(); + + return this.point(x, y); +}; + +ShortCurve.prototype.jpoint = function jpoint(x, y, z) { + return new JPoint(this, x, y, z); +}; + +ShortCurve.prototype.pointFromJSON = function pointFromJSON(obj, red) { + return Point.fromJSON(this, obj, red); +}; + +ShortCurve.prototype.validate = function validate(point) { + if (point.inf) + return true; + + var x = point.x; + var y = point.y; + + var ax = this.a.redMul(x); + var rhs = x.redSqr().redMul(x).redIAdd(ax).redIAdd(this.b); + return y.redSqr().redISub(rhs).cmpn(0) === 0; +}; + +ShortCurve.prototype._endoWnafMulAdd = function _endoWnafMulAdd(points, coeffs) { + var npoints = this._endoWnafT1; + var ncoeffs = this._endoWnafT2; + for (var i = 0; i < points.length; i++) { + var split = this._endoSplit(coeffs[i]); + var p = points[i]; + var beta = p._getBeta(); + + if (split.k1.sign) { + split.k1.sign = !split.k1.sign; + p = p.neg(true); + } + if (split.k2.sign) { + split.k2.sign = !split.k2.sign; + beta = beta.neg(true); + } + + npoints[i * 2] = p; + npoints[i * 2 + 1] = beta; + ncoeffs[i * 2] = split.k1; + ncoeffs[i * 2 + 1] = split.k2; + } + var res = this._wnafMulAdd(1, npoints, ncoeffs, i * 2); + + // Clean-up references to points and coefficients + for (var j = 0; j < i * 2; j++) { + npoints[j] = null; + ncoeffs[j] = null; + } + return res; +}; + +function Point(curve, x, y, isRed) { + Base.BasePoint.call(this, curve, 'affine'); + if (x === null && y === null) { + this.x = null; + this.y = null; + this.inf = true; + } else { + this.x = new bn(x, 16); + this.y = new bn(y, 16); + // Force redgomery representation when loading from JSON + if (isRed) { + this.x.forceRed(this.curve.red); + this.y.forceRed(this.curve.red); + } + if (!this.x.red) + this.x = this.x.toRed(this.curve.red); + if (!this.y.red) + this.y = this.y.toRed(this.curve.red); + this.inf = false; + } +} +inherits(Point, Base.BasePoint); + +Point.prototype._getBeta = function _getBeta() { + if (!this.curve.endo) + return; + + var pre = this.precomputed; + if (pre && pre.beta) + return pre.beta; + + var beta = this.curve.point(this.x.redMul(this.curve.endo.beta), this.y); + if (pre) { + var curve = this.curve; + function endoMul(p) { + return curve.point(p.x.redMul(curve.endo.beta), p.y); + } + pre.beta = beta; + beta.precomputed = { + beta: null, + naf: pre.naf && { + wnd: pre.naf.wnd, + points: pre.naf.points.map(endoMul) + }, + doubles: pre.doubles && { + step: pre.doubles.step, + points: pre.doubles.points.map(endoMul) + } + }; + } + return beta; +}; + +Point.prototype.toJSON = function toJSON() { + if (!this.precomputed) + return [ this.x, this.y ]; + + return [ this.x, this.y, this.precomputed && { + doubles: this.precomputed.doubles && { + step: this.precomputed.doubles.step, + points: this.precomputed.doubles.points.slice(1) + }, + naf: this.precomputed.naf && { + wnd: this.precomputed.naf.wnd, + points: this.precomputed.naf.points.slice(1) + } + }]; +}; + +Point.fromJSON = function fromJSON(curve, obj, red) { + if (typeof obj === 'string') + obj = JSON.parse(obj); + var res = curve.point(obj[0], obj[1], red); + if (!obj[2]) + return res; + + function obj2point(obj) { + return curve.point(obj[0], obj[1], red); + } + + var pre = obj[2]; + res.precomputed = { + beta: null, + doubles: pre.doubles && { + step: pre.doubles.step, + points: [ res ].concat(pre.doubles.points.map(obj2point)) + }, + naf: pre.naf && { + wnd: pre.naf.wnd, + points: [ res ].concat(pre.naf.points.map(obj2point)) + } + }; + return res; +}; + +Point.prototype.inspect = function inspect() { + if (this.isInfinity()) + return ''; + return ''; +}; + +Point.prototype.isInfinity = function isInfinity() { + return this.inf; +}; + +Point.prototype.add = function add(p) { + // O + P = P + if (this.inf) + return p; + + // P + O = P + if (p.inf) + return this; + + // P + P = 2P + if (this.eq(p)) + return this.dbl(); + + // P + (-P) = O + if (this.neg().eq(p)) + return this.curve.point(null, null); + + // P + Q = O + if (this.x.cmp(p.x) === 0) + return this.curve.point(null, null); + + var c = this.y.redSub(p.y); + if (c.cmpn(0) !== 0) + c = c.redMul(this.x.redSub(p.x).redInvm()); + var nx = c.redSqr().redISub(this.x).redISub(p.x); + var ny = c.redMul(this.x.redSub(nx)).redISub(this.y); + return this.curve.point(nx, ny); +}; + +Point.prototype.dbl = function dbl() { + if (this.inf) + return this; + + // 2P = O + var ys1 = this.y.redAdd(this.y); + if (ys1.cmpn(0) === 0) + return this.curve.point(null, null); + + var a = this.curve.a; + + var x2 = this.x.redSqr(); + var dyinv = ys1.redInvm(); + var c = x2.redAdd(x2).redIAdd(x2).redIAdd(a).redMul(dyinv); + + var nx = c.redSqr().redISub(this.x.redAdd(this.x)); + var ny = c.redMul(this.x.redSub(nx)).redISub(this.y); + return this.curve.point(nx, ny); +}; + +Point.prototype.getX = function getX() { + return this.x.fromRed(); +}; + +Point.prototype.getY = function getY() { + return this.y.fromRed(); +}; + +Point.prototype.mul = function mul(k) { + k = new bn(k, 16); + + if (this.precomputed && this.precomputed.doubles) + return this.curve._fixedNafMul(this, k); + else if (this.curve.endo) + return this.curve._endoWnafMulAdd([ this ], [ k ]); + else + return this.curve._wnafMul(this, k); +}; + +Point.prototype.mulAdd = function mulAdd(k1, p2, k2) { + var points = [ this, p2 ]; + var coeffs = [ k1, k2 ]; + if (this.curve.endo) + return this.curve._endoWnafMulAdd(points, coeffs); + else + return this.curve._wnafMulAdd(1, points, coeffs, 2); +}; + +Point.prototype.eq = function eq(p) { + return this === p || + this.inf === p.inf && + (this.inf || this.x.cmp(p.x) === 0 && this.y.cmp(p.y) === 0); +}; + +Point.prototype.neg = function neg(_precompute) { + if (this.inf) + return this; + + var res = this.curve.point(this.x, this.y.redNeg()); + if (_precompute && this.precomputed) { + var pre = this.precomputed; + function negate(p) { + return p.neg(); + } + res.precomputed = { + naf: pre.naf && { + wnd: pre.naf.wnd, + points: pre.naf.points.map(negate) + }, + doubles: pre.doubles && { + step: pre.doubles.step, + points: pre.doubles.points.map(negate) + } + }; + } + return res; +}; + +Point.prototype.toJ = function toJ() { + if (this.inf) + return this.curve.jpoint(null, null, null); + + var res = this.curve.jpoint(this.x, this.y, this.curve.one); + return res; +}; + +function JPoint(curve, x, y, z) { + Base.BasePoint.call(this, curve, 'jacobian'); + if (x === null && y === null && z === null) { + this.x = this.curve.one; + this.y = this.curve.one; + this.z = new bn(0); + } else { + this.x = new bn(x, 16); + this.y = new bn(y, 16); + this.z = new bn(z, 16); + } + if (!this.x.red) + this.x = this.x.toRed(this.curve.red); + if (!this.y.red) + this.y = this.y.toRed(this.curve.red); + if (!this.z.red) + this.z = this.z.toRed(this.curve.red); + + this.zOne = this.z === this.curve.one; +} +inherits(JPoint, Base.BasePoint); + +JPoint.prototype.toP = function toP() { + if (this.isInfinity()) + return this.curve.point(null, null); + + var zinv = this.z.redInvm(); + var zinv2 = zinv.redSqr(); + var ax = this.x.redMul(zinv2); + var ay = this.y.redMul(zinv2).redMul(zinv); + + return this.curve.point(ax, ay); +}; + +JPoint.prototype.neg = function neg() { + return this.curve.jpoint(this.x, this.y.redNeg(), this.z); +}; + +JPoint.prototype.add = function add(p) { + // O + P = P + if (this.isInfinity()) + return p; + + // P + O = P + if (p.isInfinity()) + return this; + + // 12M + 4S + 7A + var pz2 = p.z.redSqr(); + var z2 = this.z.redSqr(); + var u1 = this.x.redMul(pz2); + var u2 = p.x.redMul(z2); + var s1 = this.y.redMul(pz2.redMul(p.z)); + var s2 = p.y.redMul(z2.redMul(this.z)); + + var h = u1.redSub(u2); + var r = s1.redSub(s2); + if (h.cmpn(0) === 0) { + if (r.cmpn(0) !== 0) + return this.curve.jpoint(null, null, null); + else + return this.dbl(); + } + + var h2 = h.redSqr(); + var h3 = h2.redMul(h); + var v = u1.redMul(h2); + + var nx = r.redSqr().redIAdd(h3).redISub(v).redISub(v); + var ny = r.redMul(v.redISub(nx)).redISub(s1.redMul(h3)); + var nz = this.z.redMul(p.z).redMul(h); + + return this.curve.jpoint(nx, ny, nz); +}; + +JPoint.prototype.mixedAdd = function mixedAdd(p) { + // O + P = P + if (this.isInfinity()) + return p.toJ(); + + // P + O = P + if (p.isInfinity()) + return this; + + // 8M + 3S + 7A + var z2 = this.z.redSqr(); + var u1 = this.x; + var u2 = p.x.redMul(z2); + var s1 = this.y; + var s2 = p.y.redMul(z2).redMul(this.z); + + var h = u1.redSub(u2); + var r = s1.redSub(s2); + if (h.cmpn(0) === 0) { + if (r.cmpn(0) !== 0) + return this.curve.jpoint(null, null, null); + else + return this.dbl(); + } + + var h2 = h.redSqr(); + var h3 = h2.redMul(h); + var v = u1.redMul(h2); + + var nx = r.redSqr().redIAdd(h3).redISub(v).redISub(v); + var ny = r.redMul(v.redISub(nx)).redISub(s1.redMul(h3)); + var nz = this.z.redMul(h); + + return this.curve.jpoint(nx, ny, nz); +}; + +JPoint.prototype.dblp = function dblp(pow) { + if (pow === 0) + return this; + if (this.isInfinity()) + return this; + if (!pow) + return this.dbl(); + + if (this.curve.zeroA || this.curve.threeA) { + var r = this; + for (var i = 0; i < pow; i++) + r = r.dbl(); + return r; + } + + // 1M + 2S + 1A + N * (4S + 5M + 8A) + // N = 1 => 6M + 6S + 9A + var a = this.curve.a; + var tinv = this.curve.tinv; + + var jx = this.x; + var jy = this.y; + var jz = this.z; + var jz4 = jz.redSqr().redSqr(); + + // Reuse results + var jyd = jy.redAdd(jy); + for (var i = 0; i < pow; i++) { + var jx2 = jx.redSqr(); + var jyd2 = jyd.redSqr(); + var jyd4 = jyd2.redSqr(); + var c = jx2.redAdd(jx2).redIAdd(jx2).redIAdd(a.redMul(jz4)); + + var t1 = jx.redMul(jyd2); + var nx = c.redSqr().redISub(t1.redAdd(t1)); + var t2 = t1.redISub(nx); + var dny = c.redMul(t2); + dny = dny.redIAdd(dny).redISub(jyd4); + var nz = jyd.redMul(jz); + if (i + 1 < pow) + jz4 = jz4.redMul(jyd4); + + jx = nx; + jz = nz; + jyd = dny; + } + + return this.curve.jpoint(jx, jyd.redMul(tinv), jz); +}; + +JPoint.prototype.dbl = function dbl() { + if (this.isInfinity()) + return this; + + if (this.curve.zeroA) + return this._zeroDbl(); + else if (this.curve.threeA) + return this._threeDbl(); + else + return this._dbl(); +}; + +JPoint.prototype._zeroDbl = function _zeroDbl() { + // Z = 1 + if (this.zOne) { + // http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl + // 1M + 5S + 14A + + // XX = X1^2 + var xx = this.x.redSqr(); + // YY = Y1^2 + var yy = this.y.redSqr(); + // YYYY = YY^2 + var yyyy = yy.redSqr(); + // S = 2 * ((X1 + YY)^2 - XX - YYYY) + var s = this.x.redAdd(yy).redSqr().redISub(xx).redISub(yyyy); + s = s.redIAdd(s); + // M = 3 * XX + a; a = 0 + var m = xx.redAdd(xx).redIAdd(xx); + // T = M ^ 2 - 2*S + var t = m.redSqr().redISub(s).redISub(s); + + // 8 * YYYY + var yyyy8 = yyyy.redIAdd(yyyy); + yyyy8 = yyyy8.redIAdd(yyyy8); + yyyy8 = yyyy8.redIAdd(yyyy8); + + // X3 = T + var nx = t; + // Y3 = M * (S - T) - 8 * YYYY + var ny = m.redMul(s.redISub(t)).redISub(yyyy8); + // Z3 = 2*Y1 + var nz = this.y.redAdd(this.y); + } else { + // http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l + // 2M + 5S + 13A + + // A = X1^2 + var a = this.x.redSqr(); + // B = Y1^2 + var b = this.y.redSqr(); + // C = B^2 + var c = b.redSqr(); + // D = 2 * ((X1 + B)^2 - A - C) + var d = this.x.redAdd(b).redSqr().redISub(a).redISub(c); + d = d.redIAdd(d); + // E = 3 * A + var e = a.redAdd(a).redIAdd(a); + // F = E^2 + var f = e.redSqr(); + + // 8 * C + var c8 = c.redIAdd(c); + c8 = c8.redIAdd(c8); + c8 = c8.redIAdd(c8); + + // X3 = F - 2 * D + var nx = f.redISub(d).redISub(d); + // Y3 = E * (D - X3) - 8 * C + var ny = e.redMul(d.redISub(nx)).redISub(c8); + // Z3 = 2 * Y1 * Z1 + var nz = this.y.redMul(this.z); + nz = nz.redIAdd(nz); + } + + return this.curve.jpoint(nx, ny, nz); +}; + +JPoint.prototype._threeDbl = function _threeDbl() { + // Z = 1 + if (this.zOne) { + // http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-mdbl-2007-bl + // 1M + 5S + 15A + + // XX = X1^2 + var xx = this.x.redSqr(); + // YY = Y1^2 + var yy = this.y.redSqr(); + // YYYY = YY^2 + var yyyy = yy.redSqr(); + // S = 2 * ((X1 + YY)^2 - XX - YYYY) + var s = this.x.redAdd(yy).redSqr().redISub(xx).redISub(yyyy); + s = s.redIAdd(s); + // M = 3 * XX + a + var m = xx.redAdd(xx).redIAdd(xx).redIAdd(this.curve.a); + // T = M^2 - 2 * S + var t = m.redSqr().redISub(s).redISub(s); + // X3 = T + var nx = t; + // Y3 = M * (S - T) - 8 * YYYY + var yyyy8 = yyyy.redIAdd(yyyy); + yyyy8 = yyyy8.redIAdd(yyyy8); + yyyy8 = yyyy8.redIAdd(yyyy8); + var ny = m.redMul(s.redISub(t)).redISub(yyyy8); + // Z3 = 2 * Y1 + var nz = this.y.redAdd(this.y); + } else { + // http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b + // 3M + 5S + + // delta = Z1^2 + var delta = this.z.redSqr(); + // gamma = Y1^2 + var gamma = this.y.redSqr(); + // beta = X1 * gamma + var beta = this.x.redMul(gamma); + // alpha = 3 * (X1 - delta) * (X1 + delta) + var alpha = this.x.redSub(delta).redMul(this.x.redAdd(delta)); + alpha = alpha.redAdd(alpha).redIAdd(alpha); + // X3 = alpha^2 - 8 * beta + var beta4 = beta.redIAdd(beta); + beta4 = beta4.redIAdd(beta4); + var beta8 = beta4.redAdd(beta4); + var nx = alpha.redSqr().redISub(beta8); + // Z3 = (Y1 + Z1)^2 - gamma - delta + var nz = this.y.redAdd(this.z).redSqr().redISub(gamma).redISub(delta); + // Y3 = alpha * (4 * beta - X3) - 8 * gamma^2 + var ggamma8 = gamma.redSqr(); + ggamma8 = ggamma8.redIAdd(ggamma8); + ggamma8 = ggamma8.redIAdd(ggamma8); + ggamma8 = ggamma8.redIAdd(ggamma8); + var ny = alpha.redMul(beta4.redISub(nx)).redISub(ggamma8); + } + + return this.curve.jpoint(nx, ny, nz); +}; + +JPoint.prototype._dbl = function _dbl() { + var a = this.curve.a; + var tinv = this.curve.tinv; + + // 4M + 6S + 10A + var jx = this.x; + var jy = this.y; + var jz = this.z; + var jz4 = jz.redSqr().redSqr(); + + var jx2 = jx.redSqr(); + var jy2 = jy.redSqr(); + + var c = jx2.redAdd(jx2).redIAdd(jx2).redIAdd(a.redMul(jz4)); + + var jxd4 = jx.redAdd(jx); + jxd4 = jxd4.redIAdd(jxd4); + var t1 = jxd4.redMul(jy2); + var nx = c.redSqr().redISub(t1.redAdd(t1)); + var t2 = t1.redISub(nx); + + var jyd8 = jy2.redSqr(); + jyd8 = jyd8.redIAdd(jyd8); + jyd8 = jyd8.redIAdd(jyd8); + jyd8 = jyd8.redIAdd(jyd8); + var ny = c.redMul(t2).redISub(jyd8); + var nz = jy.redAdd(jy).redMul(jz); + + return this.curve.jpoint(nx, ny, nz); +}; + +JPoint.prototype.trpl = function trpl() { + if (!this.curve.zeroA) + return this.dbl().add(this); + + // http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#tripling-tpl-2007-bl + // 5M + 10S + ... + + // XX = X1^2 + var xx = this.x.redSqr(); + // YY = Y1^2 + var yy = this.y.redSqr(); + // ZZ = Z1^2 + var zz = this.z.redSqr(); + // YYYY = YY^2 + var yyyy = yy.redSqr(); + // M = 3 * XX + a * ZZ2; a = 0 + var m = xx.redAdd(xx).redIAdd(xx); + // MM = M^2 + var mm = m.redSqr(); + // E = 6 * ((X1 + YY)^2 - XX - YYYY) - MM + var e = this.x.redAdd(yy).redSqr().redISub(xx).redISub(yyyy); + e = e.redIAdd(e); + e = e.redAdd(e).redIAdd(e); + e = e.redISub(mm); + // EE = E^2 + var ee = e.redSqr(); + // T = 16*YYYY + var t = yyyy.redIAdd(yyyy); + t = t.redIAdd(t); + t = t.redIAdd(t); + t = t.redIAdd(t); + // U = (M + E)^2 - MM - EE - T + var u = m.redIAdd(e).redSqr().redISub(mm).redISub(ee).redISub(t); + // X3 = 4 * (X1 * EE - 4 * YY * U) + var yyu4 = yy.redMul(u); + yyu4 = yyu4.redIAdd(yyu4); + yyu4 = yyu4.redIAdd(yyu4); + var nx = this.x.redMul(ee).redISub(yyu4); + nx = nx.redIAdd(nx); + nx = nx.redIAdd(nx); + // Y3 = 8 * Y1 * (U * (T - U) - E * EE) + var ny = this.y.redMul(u.redMul(t.redISub(u)).redISub(e.redMul(ee))); + ny = ny.redIAdd(ny); + ny = ny.redIAdd(ny); + ny = ny.redIAdd(ny); + // Z3 = (Z1 + E)^2 - ZZ - EE + var nz = this.z.redAdd(e).redSqr().redISub(zz).redISub(ee); + + return this.curve.jpoint(nx, ny, nz); +}; + +JPoint.prototype.mul = function mul(k, kbase) { + k = new bn(k, kbase); + + return this.curve._wnafMul(this, k); +}; + +JPoint.prototype.eq = function eq(p) { + if (p.type === 'affine') + return this.eq(p.toJ()); + + if (this === p) + return true; + + // x1 * z2^2 == x2 * z1^2 + var z2 = this.z.redSqr(); + var pz2 = p.z.redSqr(); + if (this.x.redMul(pz2).redISub(p.x.redMul(z2)).cmpn(0) !== 0) + return false; + + // y1 * z2^3 == y2 * z1^3 + var z3 = z2.redMul(this.z); + var pz3 = pz2.redMul(p.z); + return this.y.redMul(pz3).redISub(p.y.redMul(z3)).cmpn(0) === 0; +}; + +JPoint.prototype.inspect = function inspect() { + if (this.isInfinity()) + return ''; + return ''; +}; + +JPoint.prototype.isInfinity = function isInfinity() { + // XXX This code assumes that zero is always zero in red + return this.z.cmpn(0) === 0; +}; + +},{"../../elliptic":74,"../curve":77,"assert":194,"bn.js":72,"inherits":94}],80:[function(require,module,exports){ +var curves = exports; + +var assert = require('assert'); +var hash = require('hash.js'); +var bn = require('bn.js'); +var elliptic = require('../elliptic'); + +function PresetCurve(options) { + if (options.type === 'short') + this.curve = new elliptic.curve.short(options); + else if (options.type === 'edwards') + this.curve = new elliptic.curve.edwards(options); + else + this.curve = new elliptic.curve.mont(options); + this.g = this.curve.g; + this.n = this.curve.n; + this.hash = options.hash; + + assert(this.g.validate(), 'Invalid curve'); + assert(this.g.mul(this.n).isInfinity(), 'Invalid curve, G*N != O'); +} +curves.PresetCurve = PresetCurve; + +function defineCurve(name, options) { + Object.defineProperty(curves, name, { + configurable: true, + enumerable: true, + get: function() { + var curve = new PresetCurve(options); + Object.defineProperty(curves, name, { + configurable: true, + enumerable: true, + value: curve + }); + return curve; + } + }); +} + +defineCurve('p192', { + type: 'short', + prime: 'p192', + p: 'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff', + a: 'ffffffff ffffffff ffffffff fffffffe ffffffff fffffffc', + b: '64210519 e59c80e7 0fa7e9ab 72243049 feb8deec c146b9b1', + n: 'ffffffff ffffffff ffffffff 99def836 146bc9b1 b4d22831', + hash: hash.sha256, + gRed: false, + g: [ + '188da80e b03090f6 7cbf20eb 43a18800 f4ff0afd 82ff1012', + '07192b95 ffc8da78 631011ed 6b24cdd5 73f977a1 1e794811' + ], +}); + +defineCurve('p224', { + type: 'short', + prime: 'p224', + p: 'ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001', + a: 'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff fffffffe', + b: 'b4050a85 0c04b3ab f5413256 5044b0b7 d7bfd8ba 270b3943 2355ffb4', + n: 'ffffffff ffffffff ffffffff ffff16a2 e0b8f03e 13dd2945 5c5c2a3d', + hash: hash.sha256, + gRed: false, + g: [ + 'b70e0cbd 6bb4bf7f 321390b9 4a03c1d3 56c21122 343280d6 115c1d21', + 'bd376388 b5f723fb 4c22dfe6 cd4375a0 5a074764 44d58199 85007e34' + ], +}); + +defineCurve('p256', { + type: 'short', + prime: null, + p: 'ffffffff 00000001 00000000 00000000 00000000 ffffffff ffffffff ffffffff', + a: 'ffffffff 00000001 00000000 00000000 00000000 ffffffff ffffffff fffffffc', + b: '5ac635d8 aa3a93e7 b3ebbd55 769886bc 651d06b0 cc53b0f6 3bce3c3e 27d2604b', + n: 'ffffffff 00000000 ffffffff ffffffff bce6faad a7179e84 f3b9cac2 fc632551', + hash: hash.sha256, + gRed: false, + g: [ + '6b17d1f2 e12c4247 f8bce6e5 63a440f2 77037d81 2deb33a0 f4a13945 d898c296', + '4fe342e2 fe1a7f9b 8ee7eb4a 7c0f9e16 2bce3357 6b315ece cbb64068 37bf51f5' + ], +}); + +defineCurve('curve25519', { + type: 'mont', + prime: 'p25519', + p: '7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed', + a: '76d06', + b: '0', + n: '1000000000000000 0000000000000000 14def9dea2f79cd6 5812631a5cf5d3ed', + hash: hash.sha256, + gRed: false, + g: [ + '9' + ] +}); + +defineCurve('ed25519', { + type: 'edwards', + prime: 'p25519', + p: '7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed', + a: '-1', + c: '1', + // -121665 * (121666^(-1)) (mod P) + d: '52036cee2b6ffe73 8cc740797779e898 00700a4d4141d8ab 75eb4dca135978a3', + n: '1000000000000000 0000000000000000 14def9dea2f79cd6 5812631a5cf5d3ed', + hash: hash.sha256, + gRed: false, + g: [ + '216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51a', + + // 4/5 + '6666666666666666666666666666666666666666666666666666666666666658' + ] +}); + +defineCurve('secp256k1', { + type: 'short', + prime: 'k256', + p: 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f', + a: '0', + b: '7', + n: 'ffffffff ffffffff ffffffff fffffffe baaedce6 af48a03b bfd25e8c d0364141', + h: '1', + hash: hash.sha256, + + // Precomputed endomorphism + beta: '7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee', + lambda: '5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72', + basis: [ + { + a: '3086d221a7d46bcde86c90e49284eb15', + b: '-e4437ed6010e88286f547fa90abfe4c3' + }, + { + a: '114ca50f7a8e2f3f657c1108d9d44cfd8', + b: '3086d221a7d46bcde86c90e49284eb15' + } + ], + + gRed: false, + g: [ + '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798', + '483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8', + { + 'doubles': { + 'step': 4, + 'points': [ + [ + 'e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a', + 'f7e3507399e595929db99f34f57937101296891e44d23f0be1f32cce69616821' + ], + [ + '8282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508', + '11f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf' + ], + [ + '175e159f728b865a72f99cc6c6fc846de0b93833fd2222ed73fce5b551e5b739', + 'd3506e0d9e3c79eba4ef97a51ff71f5eacb5955add24345c6efa6ffee9fed695' + ], + [ + '363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640', + '4e273adfc732221953b445397f3363145b9a89008199ecb62003c7f3bee9de9' + ], + [ + '8b4b5f165df3c2be8c6244b5b745638843e4a781a15bcd1b69f79a55dffdf80c', '4aad0a6f68d308b4b3fbd7813ab0da04f9e336546162ee56b3eff0c65fd4fd36' ], [ @@ -17759,7203 +21665,33364 @@ defineCurve('secp256k1', { ] } } - ] -}); - -},{"../elliptic":58,"assert":89,"bn.js":56,"hash.js":72}],65:[function(require,module,exports){ -var assert = require('assert'); -var bn = require('bn.js'); -var elliptic = require('../../elliptic'); -var utils = elliptic.utils; - -var KeyPair = require('./key'); -var Signature = require('./signature'); + ] +}); + +},{"../elliptic":74,"assert":194,"bn.js":72,"hash.js":88}],81:[function(require,module,exports){ +var assert = require('assert'); +var bn = require('bn.js'); +var elliptic = require('../../elliptic'); +var utils = elliptic.utils; + +var KeyPair = require('./key'); +var Signature = require('./signature'); + +function EC(options) { + if (!(this instanceof EC)) + return new EC(options); + + // Shortcut `elliptic.ec(curve-name)` + if (typeof options === 'string') { + assert(elliptic.curves.hasOwnProperty(options), 'Unknown curve ' + options); + + options = elliptic.curves[options]; + } + + // Shortcut for `elliptic.ec(elliptic.curves.curveName)` + if (options instanceof elliptic.curves.PresetCurve) + options = { curve: options }; + + this.curve = options.curve.curve; + this.n = this.curve.n; + this.nh = this.n.shrn(1); + this.g = this.curve.g; + + // Point on curve + this.g = options.curve.g; + this.g.precompute(options.curve.n.bitLength() + 1); + + // Hash for function for DRBG + this.hash = options.hash || options.curve.hash; +} +module.exports = EC; + +EC.prototype.keyPair = function keyPair(priv, pub) { + return new KeyPair(this, priv, pub); +}; + +EC.prototype.genKeyPair = function genKeyPair(options) { + if (!options) + options = {}; + + // Instantiate Hmac_DRBG + var drbg = new elliptic.hmacDRBG({ + hash: this.hash, + pers: options.pers, + entropy: options.entropy || elliptic.rand(this.hash.hmacStrength), + nonce: this.n.toArray() + }); + + var bytes = this.n.byteLength(); + var ns2 = this.n.sub(new bn(2)); + do { + var priv = new bn(drbg.generate(bytes)); + if (priv.cmp(ns2) > 0) + continue; + + priv.iaddn(1); + return this.keyPair(priv); + } while (true); +}; + +EC.prototype._truncateToN = function truncateToN(msg, truncOnly) { + var delta = msg.byteLength() * 8 - this.n.bitLength(); + if (delta > 0) + msg = msg.shrn(delta); + if (!truncOnly && msg.cmp(this.n) >= 0) + return msg.sub(this.n); + else + return msg; +}; + +EC.prototype.sign = function sign(msg, key, options) { + key = this.keyPair(key, 'hex'); + msg = this._truncateToN(new bn(msg, 16)); + if (!options) + options = {}; + + // Zero-extend key to provide enough entropy + var bytes = this.n.byteLength(); + var bkey = key.getPrivate().toArray(); + for (var i = bkey.length; i < 21; i++) + bkey.unshift(0); + + // Zero-extend nonce to have the same byte size as N + var nonce = msg.toArray(); + for (var i = nonce.length; i < bytes; i++) + nonce.unshift(0); + + // Instantiate Hmac_DRBG + var drbg = new elliptic.hmacDRBG({ + hash: this.hash, + entropy: bkey, + nonce: nonce + }); + + // Number of bytes to generate + var ns1 = this.n.sub(new bn(1)); + do { + var k = new bn(drbg.generate(this.n.byteLength())); + k = this._truncateToN(k, true); + if (k.cmpn(1) <= 0 || k.cmp(ns1) >= 0) + continue; + + var kp = this.g.mul(k); + if (kp.isInfinity()) + continue; + + var r = kp.getX().mod(this.n); + if (r.cmpn(0) === 0) + continue; + + var s = k.invm(this.n).mul(r.mul(key.getPrivate()).iadd(msg)).mod(this.n); + if (s.cmpn(0) === 0) + continue; + + // Use complement of `s`, if it is > `n / 2` + if (options.canonical && s.cmp(this.nh) > 0) + s = this.n.sub(s); + + return new Signature(r, s); + } while (true); +}; + +EC.prototype.verify = function verify(msg, signature, key) { + msg = this._truncateToN(new bn(msg, 16)); + key = this.keyPair(key, 'hex'); + signature = new Signature(signature, 'hex'); + + // Perform primitive values validation + var r = signature.r; + var s = signature.s; + if (r.cmpn(1) < 0 || r.cmp(this.n) >= 0) + return false; + if (s.cmpn(1) < 0 || s.cmp(this.n) >= 0) + return false; + + // Validate signature + var sinv = s.invm(this.n); + var u1 = sinv.mul(msg).mod(this.n); + var u2 = sinv.mul(r).mod(this.n); + + var p = this.g.mulAdd(u1, key.getPublic(), u2); + if (p.isInfinity()) + return false; + + return p.getX().mod(this.n).cmp(r) === 0; +}; + +},{"../../elliptic":74,"./key":82,"./signature":83,"assert":194,"bn.js":72}],82:[function(require,module,exports){ +var assert = require('assert'); +var bn = require('bn.js'); + +var elliptic = require('../../elliptic'); +var utils = elliptic.utils; + +function KeyPair(ec, priv, pub) { + if (priv instanceof KeyPair) + return priv; + if (pub instanceof KeyPair) + return pub; + + if (!priv) { + priv = pub; + pub = null; + } + if (priv !== null && typeof priv === 'object') { + if (priv.x) { + // KeyPair(public) + pub = priv; + priv = null; + } else if (priv.priv || priv.pub) { + // KeyPair({ priv: ..., pub: ... }) + pub = priv.pub; + priv = priv.priv; + } + } + + this.ec = ec; + this.priv = null; + this.pub = null; + + // KeyPair(public, 'hex') + if (this._importPublicHex(priv, pub)) + return; + + if (pub === 'hex') + pub = null; + + // KeyPair(priv, pub) + if (priv) + this._importPrivate(priv); + if (pub) + this._importPublic(pub); +} +module.exports = KeyPair; + +KeyPair.prototype.validate = function validate() { + var pub = this.getPublic(); + + if (pub.isInfinity()) + return { result: false, reason: 'Invalid public key' }; + if (!pub.validate()) + return { result: false, reason: 'Public key is not a point' }; + if (!pub.mul(this.ec.curve.n).isInfinity()) + return { result: false, reason: 'Public key * N != O' }; + + return { result: true, reason: null }; +}; + +KeyPair.prototype.getPublic = function getPublic(compact, enc) { + if (!this.pub) + this.pub = this.ec.g.mul(this.priv); + + // compact is optional argument + if (typeof compact === 'string') { + enc = compact; + compact = null; + } + + if (!enc) + return this.pub; + + var len = this.ec.curve.p.byteLength(); + var x = this.pub.getX().toArray(); + + for (var i = x.length; i < len; i++) + x.unshift(0); + + if (compact) { + var res = [ this.pub.getY().isEven() ? 0x02 : 0x03 ].concat(x); + } else { + var y = this.pub.getY().toArray(); + for (var i = y.length; i < len; i++) + y.unshift(0); + var res = [ 0x04 ].concat(x, y); + } + return utils.encode(res, enc); +}; + +KeyPair.prototype.getPrivate = function getPrivate(enc) { + if (enc === 'hex') + return this.priv.toString(16, 2); + else + return this.priv; +}; + +KeyPair.prototype._importPrivate = function _importPrivate(key) { + this.priv = new bn(key, 16); + + // Ensure that the priv won't be bigger than n, otherwise we may fail + // in fixed multiplication method + this.priv = this.priv.mod(this.ec.curve.n); +}; + +KeyPair.prototype._importPublic = function _importPublic(key) { + this.pub = this.ec.curve.point(key.x, key.y); +}; + +KeyPair.prototype._importPublicHex = function _importPublic(key, enc) { + key = utils.toArray(key, enc); + var len = this.ec.curve.p.byteLength(); + if (key[0] === 0x04 && key.length - 1 === 2 * len) { + this.pub = this.ec.curve.point( + key.slice(1, 1 + len), + key.slice(1 + len, 1 + 2 * len)); + } else if ((key[0] === 0x02 || key[0] === 0x03) && key.length - 1 === len) { + this.pub = this.ec.curve.pointFromX(key[0] === 0x03, + key.slice(1, 1 +len)); + } else { + return false; + } + + return true; +}; + +// ECDH +KeyPair.prototype.derive = function derive(pub) { + return pub.mul(this.priv).getX(); +}; + +// ECDSA +KeyPair.prototype.sign = function sign(msg) { + return this.ec.sign(msg, this); +}; + +KeyPair.prototype.verify = function verify(msg, signature) { + return this.ec.verify(msg, signature, this); +}; + +KeyPair.prototype.inspect = function inspect() { + return ''; +}; + +},{"../../elliptic":74,"assert":194,"bn.js":72}],83:[function(require,module,exports){ +var assert = require('assert'); +var bn = require('bn.js'); + +var elliptic = require('../../elliptic'); +var utils = elliptic.utils; + +function Signature(r, s) { + if (r instanceof Signature) + return r; + + if (this._importDER(r, s)) + return; + + assert(r && s, 'Signature without r or s'); + this.r = new bn(r, 16); + this.s = new bn(s, 16); +} +module.exports = Signature; + +Signature.prototype._importDER = function _importDER(data, enc) { + data = utils.toArray(data, enc); + if (data.length < 6 || data[0] !== 0x30 || data[2] !== 0x02) + return false; + var total = data[1]; + if (1 + total > data.length) + return false; + var rlen = data[3]; + // Short length notation + if (rlen >= 0x80) + return false; + if (4 + rlen + 2 >= data.length) + return false; + if (data[4 + rlen] !== 0x02) + return false; + var slen = data[5 + rlen]; + // Short length notation + if (slen >= 0x80) + return false; + if (4 + rlen + 2 + slen > data.length) + return false; + + this.r = new bn(data.slice(4, 4 + rlen)); + this.s = new bn(data.slice(4 + rlen + 2, 4 + rlen + 2 + slen)); + + return true; +}; + +Signature.prototype.toDER = function toDER(enc) { + var r = this.r.toArray(); + var s = this.s.toArray(); + + // Pad values + if (r[0] & 0x80) + r = [ 0 ].concat(r); + // Pad values + if (s[0] & 0x80) + s = [ 0 ].concat(s); + + var total = r.length + s.length + 4; + var res = [ 0x30, total, 0x02, r.length ]; + res = res.concat(r, [ 0x02, s.length ], s); + return utils.encode(res, enc); +}; + +},{"../../elliptic":74,"assert":194,"bn.js":72}],84:[function(require,module,exports){ +var assert = require('assert'); + +var hash = require('hash.js'); +var elliptic = require('../elliptic'); +var utils = elliptic.utils; + +function HmacDRBG(options) { + if (!(this instanceof HmacDRBG)) + return new HmacDRBG(options); + this.hash = options.hash; + this.predResist = !!options.predResist; + + this.outLen = this.hash.outSize; + this.minEntropy = options.minEntropy || this.hash.hmacStrength; + + this.reseed = null; + this.reseedInterval = null; + this.K = null; + this.V = null; + + var entropy = utils.toArray(options.entropy, options.entropyEnc); + var nonce = utils.toArray(options.nonce, options.nonceEnc); + var pers = utils.toArray(options.pers, options.persEnc); + assert(entropy.length >= (this.minEntropy / 8), + 'Not enough entropy. Minimum is: ' + this.minEntropy + ' bits'); + this._init(entropy, nonce, pers); +} +module.exports = HmacDRBG; + +HmacDRBG.prototype._init = function init(entropy, nonce, pers) { + var seed = entropy.concat(nonce).concat(pers); + + this.K = new Array(this.outLen / 8); + this.V = new Array(this.outLen / 8); + for (var i = 0; i < this.V.length; i++) { + this.K[i] = 0x00; + this.V[i] = 0x01; + } + + this._update(seed); + this.reseed = 1; + this.reseedInterval = 0x1000000000000; // 2^48 +}; + +HmacDRBG.prototype._hmac = function hmac() { + return new hash.hmac(this.hash, this.K); +}; + +HmacDRBG.prototype._update = function update(seed) { + var kmac = this._hmac() + .update(this.V) + .update([ 0x00 ]); + if (seed) + kmac = kmac.update(seed); + this.K = kmac.digest(); + this.V = this._hmac().update(this.V).digest(); + if (!seed) + return; + + this.K = this._hmac() + .update(this.V) + .update([ 0x01 ]) + .update(seed) + .digest(); + this.V = this._hmac().update(this.V).digest(); +}; + +HmacDRBG.prototype.reseed = function reseed(entropy, entropyEnc, add, addEnc) { + // Optional entropy enc + if (typeof entropyEnc !== 'string') { + addEnc = add; + add = entropyEnc; + entropyEnc = null; + } + + entropy = utils.toBuffer(entropy, entropyEnc); + add = utils.toBuffer(add, addEnc); + + assert(entropy.length >= (this.minEntropy / 8), + 'Not enough entropy. Minimum is: ' + this.minEntropy + ' bits'); + + this._update(entropy.concat(add || [])); + this.reseed = 1; +}; + +HmacDRBG.prototype.generate = function generate(len, enc, add, addEnc) { + if (this.reseed > this.reseedInterval) + throw new Error('Reseed is required'); + + // Optional encoding + if (typeof enc !== 'string') { + addEnc = add; + add = enc; + enc = null; + } + + // Optional additional data + if (add) { + add = utils.toArray(add, addEnc); + this._update(add); + } + + var temp = []; + while (temp.length < len) { + this.V = this._hmac().update(this.V).digest(); + temp = temp.concat(this.V); + } + + var res = temp.slice(0, len); + this._update(add); + this.reseed++; + return utils.encode(res, enc); +}; + +},{"../elliptic":74,"assert":194,"hash.js":88}],85:[function(require,module,exports){ +var assert = require('assert'); +var bn = require('bn.js'); + +var utils = exports; + +function toArray(msg, enc) { + if (Array.isArray(msg)) + return msg.slice(); + if (!msg) + return []; + var res = []; + if (typeof msg === 'string') { + if (!enc) { + for (var i = 0; i < msg.length; i++) { + var c = msg.charCodeAt(i); + var hi = c >> 8; + var lo = c & 0xff; + if (hi) + res.push(hi, lo); + else + res.push(lo); + } + } else if (enc === 'hex') { + msg = msg.replace(/[^a-z0-9]+/ig, ''); + if (msg.length % 2 !== 0) + msg = '0' + msg; + for (var i = 0; i < msg.length; i += 2) + res.push(parseInt(msg[i] + msg[i + 1], 16)); + } + } else { + for (var i = 0; i < msg.length; i++) + res[i] = msg[i] | 0; + } + return res; +} +utils.toArray = toArray; + +function toHex(msg) { + var res = ''; + for (var i = 0; i < msg.length; i++) + res += zero2(msg[i].toString(16)); + return res; +} +utils.toHex = toHex; + +utils.encode = function encode(arr, enc) { + if (enc === 'hex') + return toHex(arr); + else + return arr; +}; + +function zero2(word) { + if (word.length === 1) + return '0' + word; + else + return word; +} +utils.zero2 = zero2; + +// Represent num in a w-NAF form +function getNAF(num, w) { + var naf = []; + var ws = 1 << (w + 1); + var k = num.clone(); + while (k.cmpn(1) >= 0) { + var z; + if (k.isOdd()) { + var mod = k.andln(ws - 1); + if (mod > (ws >> 1) - 1) + z = (ws >> 1) - mod; + else + z = mod; + k.isubn(z); + } else { + z = 0; + } + naf.push(z); + + // Optimization, shift by word if possible + var shift = (k.cmpn(0) !== 0 && k.andln(ws - 1) === 0) ? (w + 1) : 1; + for (var i = 1; i < shift; i++) + naf.push(0); + k.ishrn(shift); + } + + return naf; +} +utils.getNAF = getNAF; + +// Represent k1, k2 in a Joint Sparse Form +function getJSF(k1, k2) { + var jsf = [ + [], + [] + ]; + + k1 = k1.clone(); + k2 = k2.clone(); + var d1 = 0; + var d2 = 0; + while (k1.cmpn(-d1) > 0 || k2.cmpn(-d2) > 0) { + + // First phase + var m14 = (k1.andln(3) + d1) & 3; + var m24 = (k2.andln(3) + d2) & 3; + if (m14 === 3) + m14 = -1; + if (m24 === 3) + m24 = -1; + var u1; + if ((m14 & 1) === 0) { + u1 = 0; + } else { + var m8 = (k1.andln(7) + d1) & 7; + if ((m8 === 3 || m8 === 5) && m24 === 2) + u1 = -m14; + else + u1 = m14; + } + jsf[0].push(u1); + + var u2; + if ((m24 & 1) === 0) { + u2 = 0; + } else { + var m8 = (k2.andln(7) + d2) & 7; + if ((m8 === 3 || m8 === 5) && m14 === 2) + u2 = -m24; + else + u2 = m24; + } + jsf[1].push(u2); + + // Second phase + if (2 * d1 === u1 + 1) + d1 = 1 - d1; + if (2 * d2 === u2 + 1) + d2 = 1 - d2; + k1.ishrn(1); + k2.ishrn(1); + } + + return jsf; +} +utils.getJSF = getJSF; + +},{"assert":194,"bn.js":72}],86:[function(require,module,exports){ +var r; + +module.exports = function rand(len) { + if (!r) + r = new Rand(); + + return r.generate(len); +}; + +function Rand() { +} + +Rand.prototype.generate = function generate(len) { + return this._rand(len); +}; + +if (typeof window === 'object') { + if (window.crypto && window.crypto.getRandomValues) { + // Modern browsers + Rand.prototype._rand = function _rand(n) { + var arr = new Uint8Array(n); + window.crypto.getRandomValues(arr); + return arr; + }; + } else if (window.msCrypto && window.msCrypto.getRandomValues) { + // IE + Rand.prototype._rand = function _rand(n) { + var arr = new Uint8Array(n); + window.msCrypto.getRandomValues(arr); + return arr; + }; + } else { + // Old junk + Rand.prototype._rand = function() { + throw new Error('Not implemented yet'); + }; + } +} else { + // Node.js + var crypto; + Rand.prototype._rand = function _rand(n) { + if (!crypto) + crypto = require('cry' + 'pto'); + return crypto.randomBytes(n); + }; +} + +},{}],87:[function(require,module,exports){ +module.exports={ + "name": "elliptic", + "version": "0.16.0", + "description": "EC cryptography", + "main": "lib/elliptic.js", + "scripts": { + "test": "mocha --reporter=spec test/*-test.js" + }, + "repository": { + "type": "git", + "url": "git@github.com:indutny/elliptic" + }, + "keywords": [ + "EC", + "Elliptic", + "curve", + "Cryptography" + ], + "author": { + "name": "Fedor Indutny", + "email": "fedor@indutny.com" + }, + "license": "MIT", + "bugs": { + "url": "https://github.com/indutny/elliptic/issues" + }, + "homepage": "https://github.com/indutny/elliptic", + "devDependencies": { + "browserify": "^3.44.2", + "mocha": "^1.18.2", + "uglify-js": "^2.4.13" + }, + "dependencies": { + "bn.js": "^0.16.0", + "brorand": "^1.0.1", + "hash.js": "^0.3.2", + "inherits": "^2.0.1" + }, + "readme": "# Elliptic [![Build Status](https://secure.travis-ci.org/indutny/elliptic.png)](http://travis-ci.org/indutny/elliptic)\n\nFast elliptic-curve cryptography in a plain javascript implementation.\n\nNOTE: Please take a look at http://safecurves.cr.yp.to/ before choosing a curve\nfor your cryptography operations.\n\n## Incentive\n\nECC is much slower than regular RSA cryptography, the JS implementations are\neven more slower.\n\n## Benchmarks\n\n```bash\n$ node benchmarks/index.js\nBenchmarking: sign\nelliptic#sign x 262 ops/sec ±0.51% (177 runs sampled)\neccjs#sign x 55.91 ops/sec ±0.90% (144 runs sampled)\n------------------------\nFastest is elliptic#sign\n========================\nBenchmarking: verify\nelliptic#verify x 113 ops/sec ±0.50% (166 runs sampled)\neccjs#verify x 48.56 ops/sec ±0.36% (125 runs sampled)\n------------------------\nFastest is elliptic#verify\n========================\nBenchmarking: gen\nelliptic#gen x 294 ops/sec ±0.43% (176 runs sampled)\neccjs#gen x 62.25 ops/sec ±0.63% (129 runs sampled)\n------------------------\nFastest is elliptic#gen\n========================\nBenchmarking: ecdh\nelliptic#ecdh x 136 ops/sec ±0.85% (156 runs sampled)\n------------------------\nFastest is elliptic#ecdh\n========================\n```\n\n## API\n\n### ECDSA\n\n```javascript\nvar EC = require('elliptic').ec;\n\n// Create and initialize EC context\n// (better do it once and reuse it)\nvar ec = new EC('secp256k1');\n\n// Generate keys\nvar key = ec.genKeyPair();\n\n// Sign message (must be an array, or it'll be treated as a hex sequence)\nvar msg = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];\nvar signature = key.sign(msg);\n\n// Export DER encoded signature in Array\nvar derSign = signature.toDER();\n\n// Verify signature\nconsole.log(key.verify(msg, derSign));\n```\n\n### ECDH\n\n```javascript\n// Generate keys\nvar key1 = ec.genKeyPair();\nvar key2 = ec.genKeyPair();\n\nvar shared1 = key1.derive(key2.getPublic());\nvar shared2 = key2.derive(key1.getPublic());\n\nconsole.log('Both shared secrets are BN instances');\nconsole.log(shared1.toString(16));\nconsole.log(shared2.toString(16));\n```\n\nNOTE: `.derive()` returns a [BN][1] instance.\n\n## Supported curves\n\nElliptic.js support following curve types:\n\n* Short Weierstrass\n* Montgomery\n* Edwards\n* Twisted Edwards\n\nFollowing curve 'presets' are embedded into the library:\n\n* `secp256k1`\n* `p192`\n* `p224`\n* `p256`\n* `curve25519`\n* `ed25519`\n\nNOTE: That `curve25519` could not be used for ECDSA, use `ed25519` instead.\n\n### Implementation details\n\nECDSA is using deterministic `k` value generation as per [RFC6979][0]. Most of\nthe curve operations are performed on non-affine coordinates (either projective\nor extended), various windowing techniques are used for different cases.\n\nAll operations are performed in reduction context using [bn.js][1], hashing is\nprovided by [hash.js][2]\n\n#### LICENSE\n\nThis software is licensed under the MIT License.\n\nCopyright Fedor Indutny, 2014.\n\nPermission is hereby granted, free of charge, to any person obtaining a\ncopy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to permit\npersons to whom the Software is furnished to do so, subject to the\nfollowing conditions:\n\nThe above copyright notice and this permission notice shall be included\nin all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\nOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\nNO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\nDAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\nOTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\nUSE OR OTHER DEALINGS IN THE SOFTWARE.\n\n[0]: http://tools.ietf.org/html/rfc6979\n[1]: https://github.com/indutny/bn.js\n[2]: https://github.com/indutny/hash.js\n", + "readmeFilename": "README.md", + "_id": "elliptic@0.16.0", + "_shasum": "9bc84e75ccd97e3e452c97371726c535314d1a57", + "_from": "https://registry.npmjs.org/elliptic/-/elliptic-0.16.0.tgz", + "_resolved": "https://registry.npmjs.org/elliptic/-/elliptic-0.16.0.tgz" +} + +},{}],88:[function(require,module,exports){ +var hash = exports; + +hash.utils = require('./hash/utils'); +hash.common = require('./hash/common'); +hash.sha = require('./hash/sha'); +hash.ripemd = require('./hash/ripemd'); +hash.hmac = require('./hash/hmac'); + +// Proxy hash functions to the main object +hash.sha1 = hash.sha.sha1; +hash.sha256 = hash.sha.sha256; +hash.sha224 = hash.sha.sha224; +hash.ripemd160 = hash.ripemd.ripemd160; + +},{"./hash/common":89,"./hash/hmac":90,"./hash/ripemd":91,"./hash/sha":92,"./hash/utils":93}],89:[function(require,module,exports){ +var hash = require('../hash'); +var utils = hash.utils; +var assert = utils.assert; + +function BlockHash() { + this.pending = null; + this.pendingTotal = 0; + this.blockSize = this.constructor.blockSize; + this.outSize = this.constructor.outSize; + this.hmacStrength = this.constructor.hmacStrength; + this.endian = 'big'; + + this._delta8 = this.blockSize / 8; + this._delta32 = this.blockSize / 32; +} +exports.BlockHash = BlockHash; + +BlockHash.prototype.update = function update(msg, enc) { + // Convert message to array, pad it, and join into 32bit blocks + msg = utils.toArray(msg, enc); + if (!this.pending) + this.pending = msg; + else + this.pending = this.pending.concat(msg); + this.pendingTotal += msg.length; + + // Enough data, try updating + if (this.pending.length >= this._delta8) { + msg = this.pending; + + // Process pending data in blocks + var r = msg.length % this._delta8; + this.pending = msg.slice(msg.length - r, msg.length); + if (this.pending.length === 0) + this.pending = null; + + msg = utils.join32(msg, 0, msg.length - r, this.endian); + for (var i = 0; i < msg.length; i += this._delta32) + this._update(msg, i, i + this._delta32); + } + + return this; +}; + +BlockHash.prototype.digest = function digest(enc) { + this.update(this._pad()); + assert(this.pending === null); + + return this._digest(enc); +}; + +BlockHash.prototype._pad = function pad() { + var len = this.pendingTotal; + var bytes = this._delta8; + var k = bytes - ((len + 8) % bytes); + var res = new Array(k + 8); + res[0] = 0x80; + for (var i = 1; i < k; i++) + res[i] = 0; + + // Append length + len <<= 3; + if (this.endian === 'big') { + res[i++] = 0; + res[i++] = 0; + res[i++] = 0; + res[i++] = 0; + res[i++] = (len >>> 24) & 0xff; + res[i++] = (len >>> 16) & 0xff; + res[i++] = (len >>> 8) & 0xff; + res[i++] = len & 0xff; + } else { + res[i++] = len & 0xff; + res[i++] = (len >>> 8) & 0xff; + res[i++] = (len >>> 16) & 0xff; + res[i++] = (len >>> 24) & 0xff; + res[i++] = 0; + res[i++] = 0; + res[i++] = 0; + res[i++] = 0; + } + + return res; +} + +},{"../hash":88}],90:[function(require,module,exports){ +var hmac = exports; + +var hash = require('../hash'); +var utils = hash.utils; +var assert = utils.assert; + +function Hmac(hash, key, enc) { + if (!(this instanceof Hmac)) + return new Hmac(hash, key, enc); + this.Hash = hash; + this.blockSize = hash.blockSize / 8; + this.outSize = hash.outSize / 8; + this.inner = null; + this.outer = null; + + this._init(utils.toArray(key, enc)); +} +module.exports = Hmac; + +Hmac.prototype._init = function init(key) { + // Shorten key, if needed + if (key.length > this.blockSize) + key = new this.Hash().update(key).digest(); + assert(key.length <= this.blockSize); + + // Add padding to key + for (var i = key.length; i < this.blockSize; i++) + key.push(0); + + for (var i = 0; i < key.length; i++) + key[i] ^= 0x36; + this.inner = new this.Hash().update(key); + + // 0x36 ^ 0x5c = 0x6a + for (var i = 0; i < key.length; i++) + key[i] ^= 0x6a; + this.outer = new this.Hash().update(key); +}; + +Hmac.prototype.update = function update(msg, enc) { + this.inner.update(msg, enc); + return this; +}; + +Hmac.prototype.digest = function digest(enc) { + this.outer.update(this.inner.digest()); + return this.outer.digest(enc); +}; + +},{"../hash":88}],91:[function(require,module,exports){ +var hash = require('../hash'); +var utils = hash.utils; + +var rotl32 = utils.rotl32; +var sum32 = utils.sum32; +var sum32_3 = utils.sum32_3; +var sum32_4 = utils.sum32_4; +var BlockHash = hash.common.BlockHash; + +function RIPEMD160() { + if (!(this instanceof RIPEMD160)) + return new RIPEMD160(); + + BlockHash.call(this); + + this.h = [ 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 ]; + this.endian = 'little'; +} +utils.inherits(RIPEMD160, BlockHash); +exports.ripemd160 = RIPEMD160; + +RIPEMD160.blockSize = 512; +RIPEMD160.outSize = 160; +RIPEMD160.hmacStrength = 192; + +RIPEMD160.prototype._update = function update(msg, start) { + var A = this.h[0]; + var B = this.h[1]; + var C = this.h[2]; + var D = this.h[3]; + var E = this.h[4]; + var Ah = A; + var Bh = B; + var Ch = C; + var Dh = D; + var Eh = E; + for (var j = 0; j < 80; j++) { + var T = sum32( + rotl32( + sum32_4(A, f(j, B, C, D), msg[r[j] + start], K(j)), + s[j]), + E); + A = E; + E = D; + D = rotl32(C, 10); + C = B; + B = T; + T = sum32( + rotl32( + sum32_4(Ah, f(79 - j, Bh, Ch, Dh), msg[rh[j] + start], Kh(j)), + sh[j]), + Eh); + Ah = Eh; + Eh = Dh; + Dh = rotl32(Ch, 10); + Ch = Bh; + Bh = T; + } + T = sum32_3(this.h[1], C, Dh); + this.h[1] = sum32_3(this.h[2], D, Eh); + this.h[2] = sum32_3(this.h[3], E, Ah); + this.h[3] = sum32_3(this.h[4], A, Bh); + this.h[4] = sum32_3(this.h[0], B, Ch); + this.h[0] = T; +}; + +RIPEMD160.prototype._digest = function digest(enc) { + if (enc === 'hex') + return utils.toHex32(this.h, 'little'); + else + return utils.split32(this.h, 'little'); +}; + +function f(j, x, y, z) { + if (j <= 15) + return x ^ y ^ z; + else if (j <= 31) + return (x & y) | ((~x) & z); + else if (j <= 47) + return (x | (~y)) ^ z; + else if (j <= 63) + return (x & z) | (y & (~z)); + else + return x ^ (y | (~z)); +} + +function K(j) { + if (j <= 15) + return 0x00000000; + else if (j <= 31) + return 0x5a827999; + else if (j <= 47) + return 0x6ed9eba1; + else if (j <= 63) + return 0x8f1bbcdc; + else + return 0xa953fd4e; +} + +function Kh(j) { + if (j <= 15) + return 0x50a28be6; + else if (j <= 31) + return 0x5c4dd124; + else if (j <= 47) + return 0x6d703ef3; + else if (j <= 63) + return 0x7a6d76e9; + else + return 0x00000000; +} + +var r = [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8, + 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12, + 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2, + 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13, +]; + +var rh = [ + 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, + 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2, + 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13, + 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14, + 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11 +]; + +var s = [ + 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8, + 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12, + 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5, + 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12, + 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6, +]; + +var sh = [ + 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6, + 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11, + 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5, + 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8, + 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11 +]; + +},{"../hash":88}],92:[function(require,module,exports){ +var hash = require('../hash'); +var utils = hash.utils; +var assert = utils.assert; + +var rotr32 = utils.rotr32; +var rotl32 = utils.rotl32; +var sum32 = utils.sum32; +var sum32_4 = utils.sum32_4; +var sum32_5 = utils.sum32_5; +var BlockHash = hash.common.BlockHash; + +var sha256_K = [ + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +]; + +var sha1_K = [ + 0x5A827999, 0x6ED9EBA1, + 0x8F1BBCDC, 0xCA62C1D6 +]; + +function SHA256() { + if (!(this instanceof SHA256)) + return new SHA256(); + + BlockHash.call(this); + this.h = [ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 ]; + this.k = sha256_K; + this.W = new Array(64); +} +utils.inherits(SHA256, BlockHash); +exports.sha256 = SHA256; + +SHA256.blockSize = 512; +SHA256.outSize = 256; +SHA256.hmacStrength = 192; + +SHA256.prototype._update = function _update(msg, start) { + var W = this.W; + + for (var i = 0; i < 16; i++) + W[i] = msg[start + i]; + for (; i < W.length; i++) + W[i] = sum32_4(g1_256(W[i - 2]), W[i - 7], g0_256(W[i - 15]), W[i - 16]); + + var a = this.h[0]; + var b = this.h[1]; + var c = this.h[2]; + var d = this.h[3]; + var e = this.h[4]; + var f = this.h[5]; + var g = this.h[6]; + var h = this.h[7]; + + assert(this.k.length === W.length); + for (var i = 0; i < W.length; i++) { + var T1 = sum32_5(h, s1_256(e), ch32(e, f, g), this.k[i], W[i]); + var T2 = sum32(s0_256(a), maj32(a, b, c)); + h = g; + g = f; + f = e; + e = sum32(d, T1); + d = c; + c = b; + b = a; + a = sum32(T1, T2); + } + + this.h[0] = sum32(this.h[0], a); + this.h[1] = sum32(this.h[1], b); + this.h[2] = sum32(this.h[2], c); + this.h[3] = sum32(this.h[3], d); + this.h[4] = sum32(this.h[4], e); + this.h[5] = sum32(this.h[5], f); + this.h[6] = sum32(this.h[6], g); + this.h[7] = sum32(this.h[7], h); +}; + +SHA256.prototype._digest = function digest(enc) { + if (enc === 'hex') + return utils.toHex32(this.h, 'big'); + else + return utils.split32(this.h, 'big'); +}; + +function SHA224() { + if (!(this instanceof SHA224)) + return new SHA224(); + + SHA256.call(this); + this.h = [ 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, + 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4 ]; +} +utils.inherits(SHA224, SHA256); +exports.sha224 = SHA224; + +SHA224.blockSize = 512; +SHA224.outSize = 224; +SHA224.hmacStrength = 192; + +SHA224.prototype._digest = function digest(enc) { + // Just truncate output + if (enc === 'hex') + return utils.toHex32(this.h.slice(0, 7), 'big'); + else + return utils.split32(this.h.slice(0, 7), 'big'); +}; + +function SHA1() { + if (!(this instanceof SHA1)) + return new SHA1(); + + BlockHash.call(this); + this.h = [ 0x67452301, 0xefcdab89, 0x98badcfe, + 0x10325476, 0xc3d2e1f0 ]; + this.W = new Array(80); +} + +utils.inherits(SHA1, BlockHash); +exports.sha1 = SHA1; + +SHA1.blockSize = 512; +SHA1.outSize = 160; +SHA1.hmacStrength = 80; + +SHA1.prototype._update = function _update(msg, start) { + var W = this.W; + + for (var i = 0; i < 16; i++) + W[i] = msg[start + i]; + + for(; i < W.length; i++) + W[i] = rotl32(W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16], 1); + + var a = this.h[0]; + var b = this.h[1]; + var c = this.h[2]; + var d = this.h[3]; + var e = this.h[4]; + + for (var i = 0; i < W.length; i++) { + var s = ~~(i / 20); + var t = sum32_5(rotl32(a, 5), ft_1(s, b, c, d), e, W[i], sha1_K[s]); + e = d; + d = c; + c = rotl32(b, 30); + b = a; + a = t; + } + + this.h[0] = sum32(this.h[0], a); + this.h[1] = sum32(this.h[1], b); + this.h[2] = sum32(this.h[2], c); + this.h[3] = sum32(this.h[3], d); + this.h[4] = sum32(this.h[4], e); +}; + +SHA1.prototype._digest = function digest(enc) { + if (enc === 'hex') + return utils.toHex32(this.h, 'big'); + else + return utils.split32(this.h, 'big'); +}; + +function ch32(x, y, z) { + return (x & y) ^ ((~x) & z); +} + +function maj32(x, y, z) { + return (x & y) ^ (x & z) ^ (y & z); +} + +function p32(x, y, z) { + return x ^ y ^ z; +} + +function s0_256(x) { + return rotr32(x, 2) ^ rotr32(x, 13) ^ rotr32(x, 22); +} + +function s1_256(x) { + return rotr32(x, 6) ^ rotr32(x, 11) ^ rotr32(x, 25); +} + +function g0_256(x) { + return rotr32(x, 7) ^ rotr32(x, 18) ^ (x >>> 3); +} + +function g1_256(x) { + return rotr32(x, 17) ^ rotr32(x, 19) ^ (x >>> 10); +} + +function ft_1(s, x, y, z) { + if (s === 0) + return ch32(x, y, z); + if (s === 1 || s === 3) + return p32(x, y, z) + if (s === 2) + return maj32(x, y, z) +} + +},{"../hash":88}],93:[function(require,module,exports){ +var utils = exports; +var inherits = require('inherits'); + +function toArray(msg, enc) { + if (Array.isArray(msg)) + return msg.slice(); + if (!msg) + return []; + var res = []; + if (typeof msg === 'string') { + if (!enc) { + for (var i = 0; i < msg.length; i++) { + var c = msg.charCodeAt(i); + var hi = c >> 8; + var lo = c & 0xff; + if (hi) + res.push(hi, lo); + else + res.push(lo); + } + } else if (enc === 'hex') { + msg = msg.replace(/[^a-z0-9]+/ig, ''); + if (msg.length % 2 != 0) + msg = '0' + msg; + for (var i = 0; i < msg.length; i += 2) + res.push(parseInt(msg[i] + msg[i + 1], 16)); + } + } else { + for (var i = 0; i < msg.length; i++) + res[i] = msg[i] | 0; + } + return res; +} +utils.toArray = toArray; + +function toHex(msg) { + var res = ''; + for (var i = 0; i < msg.length; i++) + res += zero2(msg[i].toString(16)); + return res; +} +utils.toHex = toHex; + +function toHex32(msg, endian) { + var res = ''; + for (var i = 0; i < msg.length; i++) { + var w = msg[i]; + if (endian === 'little') { + w = (w >>> 24) | + ((w >>> 8) & 0xff00) | + ((w << 8) & 0xff0000) | + ((w & 0xff) << 24); + if (w < 0) + w += 0x100000000; + } + res += zero8(w.toString(16)); + } + return res; +} +utils.toHex32 = toHex32; + +function zero2(word) { + if (word.length === 1) + return '0' + word; + else + return word; +} +utils.zero2 = zero2; + +function zero8(word) { + if (word.length === 7) + return '0' + word; + else if (word.length === 6) + return '00' + word; + else if (word.length === 5) + return '000' + word; + else if (word.length === 4) + return '0000' + word; + else if (word.length === 3) + return '00000' + word; + else if (word.length === 2) + return '000000' + word; + else if (word.length === 1) + return '0000000' + word; + else + return word; +} +utils.zero8 = zero8; + +function join32(msg, start, end, endian) { + var len = end - start; + assert(len % 4 === 0); + var res = new Array(len / 4); + for (var i = 0, k = start; i < res.length; i++, k += 4) { + var w; + if (endian === 'big') + w = (msg[k] << 24) | (msg[k + 1] << 16) | (msg[k + 2] << 8) | msg[k + 3]; + else + w = (msg[k + 3] << 24) | (msg[k + 2] << 16) | (msg[k + 1] << 8) | msg[k]; + if (w < 0) + w += 0x100000000; + res[i] = w; + } + return res; +} +utils.join32 = join32; + +function split32(msg, endian) { + var res = new Array(msg.length * 4); + for (var i = 0, k = 0; i < msg.length; i++, k += 4) { + var m = msg[i]; + if (endian === 'big') { + res[k] = m >>> 24; + res[k + 1] = (m >>> 16) & 0xff; + res[k + 2] = (m >>> 8) & 0xff; + res[k + 3] = m & 0xff; + } else { + res[k + 3] = m >>> 24; + res[k + 2] = (m >>> 16) & 0xff; + res[k + 1] = (m >>> 8) & 0xff; + res[k] = m & 0xff; + } + } + return res; +} +utils.split32 = split32; + +function rotr32(w, b) { + return (w >>> b) | (w << (32 - b)); +} +utils.rotr32 = rotr32; + +function rotl32(w, b) { + return (w << b) | (w >>> (32 - b)); +} +utils.rotl32 = rotl32; + +function sum32(a, b) { + var r = (a + b) & 0xffffffff; + if (r < 0) + r += 0x100000000; + return r; +} +utils.sum32 = sum32; + +function sum32_3(a, b, c) { + var r = (a + b + c) & 0xffffffff; + if (r < 0) + r += 0x100000000; + return r; +} +utils.sum32_3 = sum32_3; + +function sum32_4(a, b, c, d) { + var r = (a + b + c + d) & 0xffffffff; + if (r < 0) + r += 0x100000000; + return r; +} +utils.sum32_4 = sum32_4; + +function sum32_5(a, b, c, d, e) { + var r = (a + b + c + d + e) & 0xffffffff; + if (r < 0) + r += 0x100000000; + return r; +} +utils.sum32_5 = sum32_5; + +function assert(cond, msg) { + if (!cond) + throw new Error(msg || 'Assertion failed'); +} +utils.assert = assert; + +utils.inherits = inherits; + +},{"inherits":94}],94:[function(require,module,exports){ +if (typeof Object.create === 'function') { + // implementation from standard node.js 'util' module + module.exports = function inherits(ctor, superCtor) { + ctor.super_ = superCtor + ctor.prototype = Object.create(superCtor.prototype, { + constructor: { + value: ctor, + enumerable: false, + writable: true, + configurable: true + } + }); + }; +} else { + // old school shim for old browsers + module.exports = function inherits(ctor, superCtor) { + ctor.super_ = superCtor + var TempCtor = function () {} + TempCtor.prototype = superCtor.prototype + ctor.prototype = new TempCtor() + ctor.prototype.constructor = ctor + } +} + +},{}],95:[function(require,module,exports){ +(function (global){ +/** + * @license + * Lo-Dash 2.4.1 (Custom Build) + * Build: `lodash modern -o ./dist/lodash.js` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +;(function() { + + /** Used as a safe reference for `undefined` in pre ES5 environments */ + var undefined; + + /** Used to pool arrays and objects used internally */ + var arrayPool = [], + objectPool = []; + + /** Used to generate unique IDs */ + var idCounter = 0; + + /** Used to prefix keys to avoid issues with `__proto__` and properties on `Object.prototype` */ + var keyPrefix = +new Date + ''; + + /** Used as the size when optimizations are enabled for large arrays */ + var largeArraySize = 75; + + /** Used as the max size of the `arrayPool` and `objectPool` */ + var maxPoolSize = 40; + + /** Used to detect and test whitespace */ + var whitespace = ( + // whitespace + ' \t\x0B\f\xA0\ufeff' + + + // line terminators + '\n\r\u2028\u2029' + + + // unicode category "Zs" space separators + '\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000' + ); + + /** Used to match empty string literals in compiled template source */ + var reEmptyStringLeading = /\b__p \+= '';/g, + reEmptyStringMiddle = /\b(__p \+=) '' \+/g, + reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g; + + /** + * Used to match ES6 template delimiters + * http://people.mozilla.org/~jorendorff/es6-draft.html#sec-literals-string-literals + */ + var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g; + + /** Used to match regexp flags from their coerced string values */ + var reFlags = /\w*$/; + + /** Used to detected named functions */ + var reFuncName = /^\s*function[ \n\r\t]+\w/; + + /** Used to match "interpolate" template delimiters */ + var reInterpolate = /<%=([\s\S]+?)%>/g; + + /** Used to match leading whitespace and zeros to be removed */ + var reLeadingSpacesAndZeros = RegExp('^[' + whitespace + ']*0+(?=.$)'); + + /** Used to ensure capturing order of template delimiters */ + var reNoMatch = /($^)/; + + /** Used to detect functions containing a `this` reference */ + var reThis = /\bthis\b/; + + /** Used to match unescaped characters in compiled string literals */ + var reUnescapedString = /['\n\r\t\u2028\u2029\\]/g; + + /** Used to assign default `context` object properties */ + var contextProps = [ + 'Array', 'Boolean', 'Date', 'Function', 'Math', 'Number', 'Object', + 'RegExp', 'String', '_', 'attachEvent', 'clearTimeout', 'isFinite', 'isNaN', + 'parseInt', 'setTimeout' + ]; + + /** Used to make template sourceURLs easier to identify */ + var templateCounter = 0; + + /** `Object#toString` result shortcuts */ + var argsClass = '[object Arguments]', + arrayClass = '[object Array]', + boolClass = '[object Boolean]', + dateClass = '[object Date]', + funcClass = '[object Function]', + numberClass = '[object Number]', + objectClass = '[object Object]', + regexpClass = '[object RegExp]', + stringClass = '[object String]'; + + /** Used to identify object classifications that `_.clone` supports */ + var cloneableClasses = {}; + cloneableClasses[funcClass] = false; + cloneableClasses[argsClass] = cloneableClasses[arrayClass] = + cloneableClasses[boolClass] = cloneableClasses[dateClass] = + cloneableClasses[numberClass] = cloneableClasses[objectClass] = + cloneableClasses[regexpClass] = cloneableClasses[stringClass] = true; + + /** Used as an internal `_.debounce` options object */ + var debounceOptions = { + 'leading': false, + 'maxWait': 0, + 'trailing': false + }; + + /** Used as the property descriptor for `__bindData__` */ + var descriptor = { + 'configurable': false, + 'enumerable': false, + 'value': null, + 'writable': false + }; + + /** Used to determine if values are of the language type Object */ + var objectTypes = { + 'boolean': false, + 'function': true, + 'object': true, + 'number': false, + 'string': false, + 'undefined': false + }; + + /** Used to escape characters for inclusion in compiled string literals */ + var stringEscapes = { + '\\': '\\', + "'": "'", + '\n': 'n', + '\r': 'r', + '\t': 't', + '\u2028': 'u2028', + '\u2029': 'u2029' + }; + + /** Used as a reference to the global object */ + var root = (objectTypes[typeof window] && window) || this; + + /** Detect free variable `exports` */ + var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports; + + /** Detect free variable `module` */ + var freeModule = objectTypes[typeof module] && module && !module.nodeType && module; + + /** Detect the popular CommonJS extension `module.exports` */ + var moduleExports = freeModule && freeModule.exports === freeExports && freeExports; + + /** Detect free variable `global` from Node.js or Browserified code and use it as `root` */ + var freeGlobal = objectTypes[typeof global] && global; + if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal)) { + root = freeGlobal; + } + + /*--------------------------------------------------------------------------*/ + + /** + * The base implementation of `_.indexOf` without support for binary searches + * or `fromIndex` constraints. + * + * @private + * @param {Array} array The array to search. + * @param {*} value The value to search for. + * @param {number} [fromIndex=0] The index to search from. + * @returns {number} Returns the index of the matched value or `-1`. + */ + function baseIndexOf(array, value, fromIndex) { + var index = (fromIndex || 0) - 1, + length = array ? array.length : 0; + + while (++index < length) { + if (array[index] === value) { + return index; + } + } + return -1; + } + + /** + * An implementation of `_.contains` for cache objects that mimics the return + * signature of `_.indexOf` by returning `0` if the value is found, else `-1`. + * + * @private + * @param {Object} cache The cache object to inspect. + * @param {*} value The value to search for. + * @returns {number} Returns `0` if `value` is found, else `-1`. + */ + function cacheIndexOf(cache, value) { + var type = typeof value; + cache = cache.cache; + + if (type == 'boolean' || value == null) { + return cache[value] ? 0 : -1; + } + if (type != 'number' && type != 'string') { + type = 'object'; + } + var key = type == 'number' ? value : keyPrefix + value; + cache = (cache = cache[type]) && cache[key]; + + return type == 'object' + ? (cache && baseIndexOf(cache, value) > -1 ? 0 : -1) + : (cache ? 0 : -1); + } + + /** + * Adds a given value to the corresponding cache object. + * + * @private + * @param {*} value The value to add to the cache. + */ + function cachePush(value) { + var cache = this.cache, + type = typeof value; + + if (type == 'boolean' || value == null) { + cache[value] = true; + } else { + if (type != 'number' && type != 'string') { + type = 'object'; + } + var key = type == 'number' ? value : keyPrefix + value, + typeCache = cache[type] || (cache[type] = {}); + + if (type == 'object') { + (typeCache[key] || (typeCache[key] = [])).push(value); + } else { + typeCache[key] = true; + } + } + } + + /** + * Used by `_.max` and `_.min` as the default callback when a given + * collection is a string value. + * + * @private + * @param {string} value The character to inspect. + * @returns {number} Returns the code unit of given character. + */ + function charAtCallback(value) { + return value.charCodeAt(0); + } + + /** + * Used by `sortBy` to compare transformed `collection` elements, stable sorting + * them in ascending order. + * + * @private + * @param {Object} a The object to compare to `b`. + * @param {Object} b The object to compare to `a`. + * @returns {number} Returns the sort order indicator of `1` or `-1`. + */ + function compareAscending(a, b) { + var ac = a.criteria, + bc = b.criteria, + index = -1, + length = ac.length; + + while (++index < length) { + var value = ac[index], + other = bc[index]; + + if (value !== other) { + if (value > other || typeof value == 'undefined') { + return 1; + } + if (value < other || typeof other == 'undefined') { + return -1; + } + } + } + // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications + // that causes it, under certain circumstances, to return the same value for + // `a` and `b`. See https://github.com/jashkenas/underscore/pull/1247 + // + // This also ensures a stable sort in V8 and other engines. + // See http://code.google.com/p/v8/issues/detail?id=90 + return a.index - b.index; + } + + /** + * Creates a cache object to optimize linear searches of large arrays. + * + * @private + * @param {Array} [array=[]] The array to search. + * @returns {null|Object} Returns the cache object or `null` if caching should not be used. + */ + function createCache(array) { + var index = -1, + length = array.length, + first = array[0], + mid = array[(length / 2) | 0], + last = array[length - 1]; + + if (first && typeof first == 'object' && + mid && typeof mid == 'object' && last && typeof last == 'object') { + return false; + } + var cache = getObject(); + cache['false'] = cache['null'] = cache['true'] = cache['undefined'] = false; + + var result = getObject(); + result.array = array; + result.cache = cache; + result.push = cachePush; + + while (++index < length) { + result.push(array[index]); + } + return result; + } + + /** + * Used by `template` to escape characters for inclusion in compiled + * string literals. + * + * @private + * @param {string} match The matched character to escape. + * @returns {string} Returns the escaped character. + */ + function escapeStringChar(match) { + return '\\' + stringEscapes[match]; + } + + /** + * Gets an array from the array pool or creates a new one if the pool is empty. + * + * @private + * @returns {Array} The array from the pool. + */ + function getArray() { + return arrayPool.pop() || []; + } + + /** + * Gets an object from the object pool or creates a new one if the pool is empty. + * + * @private + * @returns {Object} The object from the pool. + */ + function getObject() { + return objectPool.pop() || { + 'array': null, + 'cache': null, + 'criteria': null, + 'false': false, + 'index': 0, + 'null': false, + 'number': null, + 'object': null, + 'push': null, + 'string': null, + 'true': false, + 'undefined': false, + 'value': null + }; + } + + /** + * Releases the given array back to the array pool. + * + * @private + * @param {Array} [array] The array to release. + */ + function releaseArray(array) { + array.length = 0; + if (arrayPool.length < maxPoolSize) { + arrayPool.push(array); + } + } + + /** + * Releases the given object back to the object pool. + * + * @private + * @param {Object} [object] The object to release. + */ + function releaseObject(object) { + var cache = object.cache; + if (cache) { + releaseObject(cache); + } + object.array = object.cache = object.criteria = object.object = object.number = object.string = object.value = null; + if (objectPool.length < maxPoolSize) { + objectPool.push(object); + } + } + + /** + * Slices the `collection` from the `start` index up to, but not including, + * the `end` index. + * + * Note: This function is used instead of `Array#slice` to support node lists + * in IE < 9 and to ensure dense arrays are returned. + * + * @private + * @param {Array|Object|string} collection The collection to slice. + * @param {number} start The start index. + * @param {number} end The end index. + * @returns {Array} Returns the new array. + */ + function slice(array, start, end) { + start || (start = 0); + if (typeof end == 'undefined') { + end = array ? array.length : 0; + } + var index = -1, + length = end - start || 0, + result = Array(length < 0 ? 0 : length); + + while (++index < length) { + result[index] = array[start + index]; + } + return result; + } + + /*--------------------------------------------------------------------------*/ + + /** + * Create a new `lodash` function using the given context object. + * + * @static + * @memberOf _ + * @category Utilities + * @param {Object} [context=root] The context object. + * @returns {Function} Returns the `lodash` function. + */ + function runInContext(context) { + // Avoid issues with some ES3 environments that attempt to use values, named + // after built-in constructors like `Object`, for the creation of literals. + // ES5 clears this up by stating that literals must use built-in constructors. + // See http://es5.github.io/#x11.1.5. + context = context ? _.defaults(root.Object(), context, _.pick(root, contextProps)) : root; + + /** Native constructor references */ + var Array = context.Array, + Boolean = context.Boolean, + Date = context.Date, + Function = context.Function, + Math = context.Math, + Number = context.Number, + Object = context.Object, + RegExp = context.RegExp, + String = context.String, + TypeError = context.TypeError; + + /** + * Used for `Array` method references. + * + * Normally `Array.prototype` would suffice, however, using an array literal + * avoids issues in Narwhal. + */ + var arrayRef = []; + + /** Used for native method references */ + var objectProto = Object.prototype; + + /** Used to restore the original `_` reference in `noConflict` */ + var oldDash = context._; + + /** Used to resolve the internal [[Class]] of values */ + var toString = objectProto.toString; + + /** Used to detect if a method is native */ + var reNative = RegExp('^' + + String(toString) + .replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + .replace(/toString| for [^\]]+/g, '.*?') + '$' + ); + + /** Native method shortcuts */ + var ceil = Math.ceil, + clearTimeout = context.clearTimeout, + floor = Math.floor, + fnToString = Function.prototype.toString, + getPrototypeOf = isNative(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf, + hasOwnProperty = objectProto.hasOwnProperty, + push = arrayRef.push, + setTimeout = context.setTimeout, + splice = arrayRef.splice, + unshift = arrayRef.unshift; + + /** Used to set meta data on functions */ + var defineProperty = (function() { + // IE 8 only accepts DOM elements + try { + var o = {}, + func = isNative(func = Object.defineProperty) && func, + result = func(o, o, o) && func; + } catch(e) { } + return result; + }()); + + /* Native method shortcuts for methods with the same name as other `lodash` methods */ + var nativeCreate = isNative(nativeCreate = Object.create) && nativeCreate, + nativeIsArray = isNative(nativeIsArray = Array.isArray) && nativeIsArray, + nativeIsFinite = context.isFinite, + nativeIsNaN = context.isNaN, + nativeKeys = isNative(nativeKeys = Object.keys) && nativeKeys, + nativeMax = Math.max, + nativeMin = Math.min, + nativeParseInt = context.parseInt, + nativeRandom = Math.random; + + /** Used to lookup a built-in constructor by [[Class]] */ + var ctorByClass = {}; + ctorByClass[arrayClass] = Array; + ctorByClass[boolClass] = Boolean; + ctorByClass[dateClass] = Date; + ctorByClass[funcClass] = Function; + ctorByClass[objectClass] = Object; + ctorByClass[numberClass] = Number; + ctorByClass[regexpClass] = RegExp; + ctorByClass[stringClass] = String; + + /*--------------------------------------------------------------------------*/ + + /** + * Creates a `lodash` object which wraps the given value to enable intuitive + * method chaining. + * + * In addition to Lo-Dash methods, wrappers also have the following `Array` methods: + * `concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`, `splice`, + * and `unshift` + * + * Chaining is supported in custom builds as long as the `value` method is + * implicitly or explicitly included in the build. + * + * The chainable wrapper functions are: + * `after`, `assign`, `bind`, `bindAll`, `bindKey`, `chain`, `compact`, + * `compose`, `concat`, `countBy`, `create`, `createCallback`, `curry`, + * `debounce`, `defaults`, `defer`, `delay`, `difference`, `filter`, `flatten`, + * `forEach`, `forEachRight`, `forIn`, `forInRight`, `forOwn`, `forOwnRight`, + * `functions`, `groupBy`, `indexBy`, `initial`, `intersection`, `invert`, + * `invoke`, `keys`, `map`, `max`, `memoize`, `merge`, `min`, `object`, `omit`, + * `once`, `pairs`, `partial`, `partialRight`, `pick`, `pluck`, `pull`, `push`, + * `range`, `reject`, `remove`, `rest`, `reverse`, `shuffle`, `slice`, `sort`, + * `sortBy`, `splice`, `tap`, `throttle`, `times`, `toArray`, `transform`, + * `union`, `uniq`, `unshift`, `unzip`, `values`, `where`, `without`, `wrap`, + * and `zip` + * + * The non-chainable wrapper functions are: + * `clone`, `cloneDeep`, `contains`, `escape`, `every`, `find`, `findIndex`, + * `findKey`, `findLast`, `findLastIndex`, `findLastKey`, `has`, `identity`, + * `indexOf`, `isArguments`, `isArray`, `isBoolean`, `isDate`, `isElement`, + * `isEmpty`, `isEqual`, `isFinite`, `isFunction`, `isNaN`, `isNull`, `isNumber`, + * `isObject`, `isPlainObject`, `isRegExp`, `isString`, `isUndefined`, `join`, + * `lastIndexOf`, `mixin`, `noConflict`, `parseInt`, `pop`, `random`, `reduce`, + * `reduceRight`, `result`, `shift`, `size`, `some`, `sortedIndex`, `runInContext`, + * `template`, `unescape`, `uniqueId`, and `value` + * + * The wrapper functions `first` and `last` return wrapped values when `n` is + * provided, otherwise they return unwrapped values. + * + * Explicit chaining can be enabled by using the `_.chain` method. + * + * @name _ + * @constructor + * @category Chaining + * @param {*} value The value to wrap in a `lodash` instance. + * @returns {Object} Returns a `lodash` instance. + * @example + * + * var wrapped = _([1, 2, 3]); + * + * // returns an unwrapped value + * wrapped.reduce(function(sum, num) { + * return sum + num; + * }); + * // => 6 + * + * // returns a wrapped value + * var squares = wrapped.map(function(num) { + * return num * num; + * }); + * + * _.isArray(squares); + * // => false + * + * _.isArray(squares.value()); + * // => true + */ + function lodash(value) { + // don't wrap if already wrapped, even if wrapped by a different `lodash` constructor + return (value && typeof value == 'object' && !isArray(value) && hasOwnProperty.call(value, '__wrapped__')) + ? value + : new lodashWrapper(value); + } + + /** + * A fast path for creating `lodash` wrapper objects. + * + * @private + * @param {*} value The value to wrap in a `lodash` instance. + * @param {boolean} chainAll A flag to enable chaining for all methods + * @returns {Object} Returns a `lodash` instance. + */ + function lodashWrapper(value, chainAll) { + this.__chain__ = !!chainAll; + this.__wrapped__ = value; + } + // ensure `new lodashWrapper` is an instance of `lodash` + lodashWrapper.prototype = lodash.prototype; + + /** + * An object used to flag environments features. + * + * @static + * @memberOf _ + * @type Object + */ + var support = lodash.support = {}; + + /** + * Detect if functions can be decompiled by `Function#toString` + * (all but PS3 and older Opera mobile browsers & avoided in Windows 8 apps). + * + * @memberOf _.support + * @type boolean + */ + support.funcDecomp = !isNative(context.WinRTError) && reThis.test(runInContext); + + /** + * Detect if `Function#name` is supported (all but IE). + * + * @memberOf _.support + * @type boolean + */ + support.funcNames = typeof Function.name == 'string'; + + /** + * By default, the template delimiters used by Lo-Dash are similar to those in + * embedded Ruby (ERB). Change the following template settings to use alternative + * delimiters. + * + * @static + * @memberOf _ + * @type Object + */ + lodash.templateSettings = { + + /** + * Used to detect `data` property values to be HTML-escaped. + * + * @memberOf _.templateSettings + * @type RegExp + */ + 'escape': /<%-([\s\S]+?)%>/g, + + /** + * Used to detect code to be evaluated. + * + * @memberOf _.templateSettings + * @type RegExp + */ + 'evaluate': /<%([\s\S]+?)%>/g, + + /** + * Used to detect `data` property values to inject. + * + * @memberOf _.templateSettings + * @type RegExp + */ + 'interpolate': reInterpolate, + + /** + * Used to reference the data object in the template text. + * + * @memberOf _.templateSettings + * @type string + */ + 'variable': '', + + /** + * Used to import variables into the compiled template. + * + * @memberOf _.templateSettings + * @type Object + */ + 'imports': { + + /** + * A reference to the `lodash` function. + * + * @memberOf _.templateSettings.imports + * @type Function + */ + '_': lodash + } + }; + + /*--------------------------------------------------------------------------*/ + + /** + * The base implementation of `_.bind` that creates the bound function and + * sets its meta data. + * + * @private + * @param {Array} bindData The bind data array. + * @returns {Function} Returns the new bound function. + */ + function baseBind(bindData) { + var func = bindData[0], + partialArgs = bindData[2], + thisArg = bindData[4]; + + function bound() { + // `Function#bind` spec + // http://es5.github.io/#x15.3.4.5 + if (partialArgs) { + // avoid `arguments` object deoptimizations by using `slice` instead + // of `Array.prototype.slice.call` and not assigning `arguments` to a + // variable as a ternary expression + var args = slice(partialArgs); + push.apply(args, arguments); + } + // mimic the constructor's `return` behavior + // http://es5.github.io/#x13.2.2 + if (this instanceof bound) { + // ensure `new bound` is an instance of `func` + var thisBinding = baseCreate(func.prototype), + result = func.apply(thisBinding, args || arguments); + return isObject(result) ? result : thisBinding; + } + return func.apply(thisArg, args || arguments); + } + setBindData(bound, bindData); + return bound; + } + + /** + * The base implementation of `_.clone` without argument juggling or support + * for `thisArg` binding. + * + * @private + * @param {*} value The value to clone. + * @param {boolean} [isDeep=false] Specify a deep clone. + * @param {Function} [callback] The function to customize cloning values. + * @param {Array} [stackA=[]] Tracks traversed source objects. + * @param {Array} [stackB=[]] Associates clones with source counterparts. + * @returns {*} Returns the cloned value. + */ + function baseClone(value, isDeep, callback, stackA, stackB) { + if (callback) { + var result = callback(value); + if (typeof result != 'undefined') { + return result; + } + } + // inspect [[Class]] + var isObj = isObject(value); + if (isObj) { + var className = toString.call(value); + if (!cloneableClasses[className]) { + return value; + } + var ctor = ctorByClass[className]; + switch (className) { + case boolClass: + case dateClass: + return new ctor(+value); + + case numberClass: + case stringClass: + return new ctor(value); + + case regexpClass: + result = ctor(value.source, reFlags.exec(value)); + result.lastIndex = value.lastIndex; + return result; + } + } else { + return value; + } + var isArr = isArray(value); + if (isDeep) { + // check for circular references and return corresponding clone + var initedStack = !stackA; + stackA || (stackA = getArray()); + stackB || (stackB = getArray()); + + var length = stackA.length; + while (length--) { + if (stackA[length] == value) { + return stackB[length]; + } + } + result = isArr ? ctor(value.length) : {}; + } + else { + result = isArr ? slice(value) : assign({}, value); + } + // add array properties assigned by `RegExp#exec` + if (isArr) { + if (hasOwnProperty.call(value, 'index')) { + result.index = value.index; + } + if (hasOwnProperty.call(value, 'input')) { + result.input = value.input; + } + } + // exit for shallow clone + if (!isDeep) { + return result; + } + // add the source value to the stack of traversed objects + // and associate it with its clone + stackA.push(value); + stackB.push(result); + + // recursively populate clone (susceptible to call stack limits) + (isArr ? forEach : forOwn)(value, function(objValue, key) { + result[key] = baseClone(objValue, isDeep, callback, stackA, stackB); + }); + + if (initedStack) { + releaseArray(stackA); + releaseArray(stackB); + } + return result; + } + + /** + * The base implementation of `_.create` without support for assigning + * properties to the created object. + * + * @private + * @param {Object} prototype The object to inherit from. + * @returns {Object} Returns the new object. + */ + function baseCreate(prototype, properties) { + return isObject(prototype) ? nativeCreate(prototype) : {}; + } + // fallback for browsers without `Object.create` + if (!nativeCreate) { + baseCreate = (function() { + function Object() {} + return function(prototype) { + if (isObject(prototype)) { + Object.prototype = prototype; + var result = new Object; + Object.prototype = null; + } + return result || context.Object(); + }; + }()); + } + + /** + * The base implementation of `_.createCallback` without support for creating + * "_.pluck" or "_.where" style callbacks. + * + * @private + * @param {*} [func=identity] The value to convert to a callback. + * @param {*} [thisArg] The `this` binding of the created callback. + * @param {number} [argCount] The number of arguments the callback accepts. + * @returns {Function} Returns a callback function. + */ + function baseCreateCallback(func, thisArg, argCount) { + if (typeof func != 'function') { + return identity; + } + // exit early for no `thisArg` or already bound by `Function#bind` + if (typeof thisArg == 'undefined' || !('prototype' in func)) { + return func; + } + var bindData = func.__bindData__; + if (typeof bindData == 'undefined') { + if (support.funcNames) { + bindData = !func.name; + } + bindData = bindData || !support.funcDecomp; + if (!bindData) { + var source = fnToString.call(func); + if (!support.funcNames) { + bindData = !reFuncName.test(source); + } + if (!bindData) { + // checks if `func` references the `this` keyword and stores the result + bindData = reThis.test(source); + setBindData(func, bindData); + } + } + } + // exit early if there are no `this` references or `func` is bound + if (bindData === false || (bindData !== true && bindData[1] & 1)) { + return func; + } + switch (argCount) { + case 1: return function(value) { + return func.call(thisArg, value); + }; + case 2: return function(a, b) { + return func.call(thisArg, a, b); + }; + case 3: return function(value, index, collection) { + return func.call(thisArg, value, index, collection); + }; + case 4: return function(accumulator, value, index, collection) { + return func.call(thisArg, accumulator, value, index, collection); + }; + } + return bind(func, thisArg); + } + + /** + * The base implementation of `createWrapper` that creates the wrapper and + * sets its meta data. + * + * @private + * @param {Array} bindData The bind data array. + * @returns {Function} Returns the new function. + */ + function baseCreateWrapper(bindData) { + var func = bindData[0], + bitmask = bindData[1], + partialArgs = bindData[2], + partialRightArgs = bindData[3], + thisArg = bindData[4], + arity = bindData[5]; + + var isBind = bitmask & 1, + isBindKey = bitmask & 2, + isCurry = bitmask & 4, + isCurryBound = bitmask & 8, + key = func; + + function bound() { + var thisBinding = isBind ? thisArg : this; + if (partialArgs) { + var args = slice(partialArgs); + push.apply(args, arguments); + } + if (partialRightArgs || isCurry) { + args || (args = slice(arguments)); + if (partialRightArgs) { + push.apply(args, partialRightArgs); + } + if (isCurry && args.length < arity) { + bitmask |= 16 & ~32; + return baseCreateWrapper([func, (isCurryBound ? bitmask : bitmask & ~3), args, null, thisArg, arity]); + } + } + args || (args = arguments); + if (isBindKey) { + func = thisBinding[key]; + } + if (this instanceof bound) { + thisBinding = baseCreate(func.prototype); + var result = func.apply(thisBinding, args); + return isObject(result) ? result : thisBinding; + } + return func.apply(thisBinding, args); + } + setBindData(bound, bindData); + return bound; + } + + /** + * The base implementation of `_.difference` that accepts a single array + * of values to exclude. + * + * @private + * @param {Array} array The array to process. + * @param {Array} [values] The array of values to exclude. + * @returns {Array} Returns a new array of filtered values. + */ + function baseDifference(array, values) { + var index = -1, + indexOf = getIndexOf(), + length = array ? array.length : 0, + isLarge = length >= largeArraySize && indexOf === baseIndexOf, + result = []; + + if (isLarge) { + var cache = createCache(values); + if (cache) { + indexOf = cacheIndexOf; + values = cache; + } else { + isLarge = false; + } + } + while (++index < length) { + var value = array[index]; + if (indexOf(values, value) < 0) { + result.push(value); + } + } + if (isLarge) { + releaseObject(values); + } + return result; + } + + /** + * The base implementation of `_.flatten` without support for callback + * shorthands or `thisArg` binding. + * + * @private + * @param {Array} array The array to flatten. + * @param {boolean} [isShallow=false] A flag to restrict flattening to a single level. + * @param {boolean} [isStrict=false] A flag to restrict flattening to arrays and `arguments` objects. + * @param {number} [fromIndex=0] The index to start from. + * @returns {Array} Returns a new flattened array. + */ + function baseFlatten(array, isShallow, isStrict, fromIndex) { + var index = (fromIndex || 0) - 1, + length = array ? array.length : 0, + result = []; + + while (++index < length) { + var value = array[index]; + + if (value && typeof value == 'object' && typeof value.length == 'number' + && (isArray(value) || isArguments(value))) { + // recursively flatten arrays (susceptible to call stack limits) + if (!isShallow) { + value = baseFlatten(value, isShallow, isStrict); + } + var valIndex = -1, + valLength = value.length, + resIndex = result.length; + + result.length += valLength; + while (++valIndex < valLength) { + result[resIndex++] = value[valIndex]; + } + } else if (!isStrict) { + result.push(value); + } + } + return result; + } + + /** + * The base implementation of `_.isEqual`, without support for `thisArg` binding, + * that allows partial "_.where" style comparisons. + * + * @private + * @param {*} a The value to compare. + * @param {*} b The other value to compare. + * @param {Function} [callback] The function to customize comparing values. + * @param {Function} [isWhere=false] A flag to indicate performing partial comparisons. + * @param {Array} [stackA=[]] Tracks traversed `a` objects. + * @param {Array} [stackB=[]] Tracks traversed `b` objects. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + */ + function baseIsEqual(a, b, callback, isWhere, stackA, stackB) { + // used to indicate that when comparing objects, `a` has at least the properties of `b` + if (callback) { + var result = callback(a, b); + if (typeof result != 'undefined') { + return !!result; + } + } + // exit early for identical values + if (a === b) { + // treat `+0` vs. `-0` as not equal + return a !== 0 || (1 / a == 1 / b); + } + var type = typeof a, + otherType = typeof b; + + // exit early for unlike primitive values + if (a === a && + !(a && objectTypes[type]) && + !(b && objectTypes[otherType])) { + return false; + } + // exit early for `null` and `undefined` avoiding ES3's Function#call behavior + // http://es5.github.io/#x15.3.4.4 + if (a == null || b == null) { + return a === b; + } + // compare [[Class]] names + var className = toString.call(a), + otherClass = toString.call(b); + + if (className == argsClass) { + className = objectClass; + } + if (otherClass == argsClass) { + otherClass = objectClass; + } + if (className != otherClass) { + return false; + } + switch (className) { + case boolClass: + case dateClass: + // coerce dates and booleans to numbers, dates to milliseconds and booleans + // to `1` or `0` treating invalid dates coerced to `NaN` as not equal + return +a == +b; + + case numberClass: + // treat `NaN` vs. `NaN` as equal + return (a != +a) + ? b != +b + // but treat `+0` vs. `-0` as not equal + : (a == 0 ? (1 / a == 1 / b) : a == +b); + + case regexpClass: + case stringClass: + // coerce regexes to strings (http://es5.github.io/#x15.10.6.4) + // treat string primitives and their corresponding object instances as equal + return a == String(b); + } + var isArr = className == arrayClass; + if (!isArr) { + // unwrap any `lodash` wrapped values + var aWrapped = hasOwnProperty.call(a, '__wrapped__'), + bWrapped = hasOwnProperty.call(b, '__wrapped__'); + + if (aWrapped || bWrapped) { + return baseIsEqual(aWrapped ? a.__wrapped__ : a, bWrapped ? b.__wrapped__ : b, callback, isWhere, stackA, stackB); + } + // exit for functions and DOM nodes + if (className != objectClass) { + return false; + } + // in older versions of Opera, `arguments` objects have `Array` constructors + var ctorA = a.constructor, + ctorB = b.constructor; + + // non `Object` object instances with different constructors are not equal + if (ctorA != ctorB && + !(isFunction(ctorA) && ctorA instanceof ctorA && isFunction(ctorB) && ctorB instanceof ctorB) && + ('constructor' in a && 'constructor' in b) + ) { + return false; + } + } + // assume cyclic structures are equal + // the algorithm for detecting cyclic structures is adapted from ES 5.1 + // section 15.12.3, abstract operation `JO` (http://es5.github.io/#x15.12.3) + var initedStack = !stackA; + stackA || (stackA = getArray()); + stackB || (stackB = getArray()); + + var length = stackA.length; + while (length--) { + if (stackA[length] == a) { + return stackB[length] == b; + } + } + var size = 0; + result = true; + + // add `a` and `b` to the stack of traversed objects + stackA.push(a); + stackB.push(b); + + // recursively compare objects and arrays (susceptible to call stack limits) + if (isArr) { + // compare lengths to determine if a deep comparison is necessary + length = a.length; + size = b.length; + result = size == length; + + if (result || isWhere) { + // deep compare the contents, ignoring non-numeric properties + while (size--) { + var index = length, + value = b[size]; + + if (isWhere) { + while (index--) { + if ((result = baseIsEqual(a[index], value, callback, isWhere, stackA, stackB))) { + break; + } + } + } else if (!(result = baseIsEqual(a[size], value, callback, isWhere, stackA, stackB))) { + break; + } + } + } + } + else { + // deep compare objects using `forIn`, instead of `forOwn`, to avoid `Object.keys` + // which, in this case, is more costly + forIn(b, function(value, key, b) { + if (hasOwnProperty.call(b, key)) { + // count the number of properties. + size++; + // deep compare each property value. + return (result = hasOwnProperty.call(a, key) && baseIsEqual(a[key], value, callback, isWhere, stackA, stackB)); + } + }); + + if (result && !isWhere) { + // ensure both objects have the same number of properties + forIn(a, function(value, key, a) { + if (hasOwnProperty.call(a, key)) { + // `size` will be `-1` if `a` has more properties than `b` + return (result = --size > -1); + } + }); + } + } + stackA.pop(); + stackB.pop(); + + if (initedStack) { + releaseArray(stackA); + releaseArray(stackB); + } + return result; + } + + /** + * The base implementation of `_.merge` without argument juggling or support + * for `thisArg` binding. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @param {Function} [callback] The function to customize merging properties. + * @param {Array} [stackA=[]] Tracks traversed source objects. + * @param {Array} [stackB=[]] Associates values with source counterparts. + */ + function baseMerge(object, source, callback, stackA, stackB) { + (isArray(source) ? forEach : forOwn)(source, function(source, key) { + var found, + isArr, + result = source, + value = object[key]; + + if (source && ((isArr = isArray(source)) || isPlainObject(source))) { + // avoid merging previously merged cyclic sources + var stackLength = stackA.length; + while (stackLength--) { + if ((found = stackA[stackLength] == source)) { + value = stackB[stackLength]; + break; + } + } + if (!found) { + var isShallow; + if (callback) { + result = callback(value, source); + if ((isShallow = typeof result != 'undefined')) { + value = result; + } + } + if (!isShallow) { + value = isArr + ? (isArray(value) ? value : []) + : (isPlainObject(value) ? value : {}); + } + // add `source` and associated `value` to the stack of traversed objects + stackA.push(source); + stackB.push(value); + + // recursively merge objects and arrays (susceptible to call stack limits) + if (!isShallow) { + baseMerge(value, source, callback, stackA, stackB); + } + } + } + else { + if (callback) { + result = callback(value, source); + if (typeof result == 'undefined') { + result = source; + } + } + if (typeof result != 'undefined') { + value = result; + } + } + object[key] = value; + }); + } + + /** + * The base implementation of `_.random` without argument juggling or support + * for returning floating-point numbers. + * + * @private + * @param {number} min The minimum possible value. + * @param {number} max The maximum possible value. + * @returns {number} Returns a random number. + */ + function baseRandom(min, max) { + return min + floor(nativeRandom() * (max - min + 1)); + } + + /** + * The base implementation of `_.uniq` without support for callback shorthands + * or `thisArg` binding. + * + * @private + * @param {Array} array The array to process. + * @param {boolean} [isSorted=false] A flag to indicate that `array` is sorted. + * @param {Function} [callback] The function called per iteration. + * @returns {Array} Returns a duplicate-value-free array. + */ + function baseUniq(array, isSorted, callback) { + var index = -1, + indexOf = getIndexOf(), + length = array ? array.length : 0, + result = []; + + var isLarge = !isSorted && length >= largeArraySize && indexOf === baseIndexOf, + seen = (callback || isLarge) ? getArray() : result; + + if (isLarge) { + var cache = createCache(seen); + indexOf = cacheIndexOf; + seen = cache; + } + while (++index < length) { + var value = array[index], + computed = callback ? callback(value, index, array) : value; + + if (isSorted + ? !index || seen[seen.length - 1] !== computed + : indexOf(seen, computed) < 0 + ) { + if (callback || isLarge) { + seen.push(computed); + } + result.push(value); + } + } + if (isLarge) { + releaseArray(seen.array); + releaseObject(seen); + } else if (callback) { + releaseArray(seen); + } + return result; + } + + /** + * Creates a function that aggregates a collection, creating an object composed + * of keys generated from the results of running each element of the collection + * through a callback. The given `setter` function sets the keys and values + * of the composed object. + * + * @private + * @param {Function} setter The setter function. + * @returns {Function} Returns the new aggregator function. + */ + function createAggregator(setter) { + return function(collection, callback, thisArg) { + var result = {}; + callback = lodash.createCallback(callback, thisArg, 3); + + var index = -1, + length = collection ? collection.length : 0; + + if (typeof length == 'number') { + while (++index < length) { + var value = collection[index]; + setter(result, value, callback(value, index, collection), collection); + } + } else { + forOwn(collection, function(value, key, collection) { + setter(result, value, callback(value, key, collection), collection); + }); + } + return result; + }; + } + + /** + * Creates a function that, when called, either curries or invokes `func` + * with an optional `this` binding and partially applied arguments. + * + * @private + * @param {Function|string} func The function or method name to reference. + * @param {number} bitmask The bitmask of method flags to compose. + * The bitmask may be composed of the following flags: + * 1 - `_.bind` + * 2 - `_.bindKey` + * 4 - `_.curry` + * 8 - `_.curry` (bound) + * 16 - `_.partial` + * 32 - `_.partialRight` + * @param {Array} [partialArgs] An array of arguments to prepend to those + * provided to the new function. + * @param {Array} [partialRightArgs] An array of arguments to append to those + * provided to the new function. + * @param {*} [thisArg] The `this` binding of `func`. + * @param {number} [arity] The arity of `func`. + * @returns {Function} Returns the new function. + */ + function createWrapper(func, bitmask, partialArgs, partialRightArgs, thisArg, arity) { + var isBind = bitmask & 1, + isBindKey = bitmask & 2, + isCurry = bitmask & 4, + isCurryBound = bitmask & 8, + isPartial = bitmask & 16, + isPartialRight = bitmask & 32; + + if (!isBindKey && !isFunction(func)) { + throw new TypeError; + } + if (isPartial && !partialArgs.length) { + bitmask &= ~16; + isPartial = partialArgs = false; + } + if (isPartialRight && !partialRightArgs.length) { + bitmask &= ~32; + isPartialRight = partialRightArgs = false; + } + var bindData = func && func.__bindData__; + if (bindData && bindData !== true) { + // clone `bindData` + bindData = slice(bindData); + if (bindData[2]) { + bindData[2] = slice(bindData[2]); + } + if (bindData[3]) { + bindData[3] = slice(bindData[3]); + } + // set `thisBinding` is not previously bound + if (isBind && !(bindData[1] & 1)) { + bindData[4] = thisArg; + } + // set if previously bound but not currently (subsequent curried functions) + if (!isBind && bindData[1] & 1) { + bitmask |= 8; + } + // set curried arity if not yet set + if (isCurry && !(bindData[1] & 4)) { + bindData[5] = arity; + } + // append partial left arguments + if (isPartial) { + push.apply(bindData[2] || (bindData[2] = []), partialArgs); + } + // append partial right arguments + if (isPartialRight) { + unshift.apply(bindData[3] || (bindData[3] = []), partialRightArgs); + } + // merge flags + bindData[1] |= bitmask; + return createWrapper.apply(null, bindData); + } + // fast path for `_.bind` + var creater = (bitmask == 1 || bitmask === 17) ? baseBind : baseCreateWrapper; + return creater([func, bitmask, partialArgs, partialRightArgs, thisArg, arity]); + } + + /** + * Used by `escape` to convert characters to HTML entities. + * + * @private + * @param {string} match The matched character to escape. + * @returns {string} Returns the escaped character. + */ + function escapeHtmlChar(match) { + return htmlEscapes[match]; + } + + /** + * Gets the appropriate "indexOf" function. If the `_.indexOf` method is + * customized, this method returns the custom method, otherwise it returns + * the `baseIndexOf` function. + * + * @private + * @returns {Function} Returns the "indexOf" function. + */ + function getIndexOf() { + var result = (result = lodash.indexOf) === indexOf ? baseIndexOf : result; + return result; + } + + /** + * Checks if `value` is a native function. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if the `value` is a native function, else `false`. + */ + function isNative(value) { + return typeof value == 'function' && reNative.test(value); + } + + /** + * Sets `this` binding data on a given function. + * + * @private + * @param {Function} func The function to set data on. + * @param {Array} value The data array to set. + */ + var setBindData = !defineProperty ? noop : function(func, value) { + descriptor.value = value; + defineProperty(func, '__bindData__', descriptor); + }; + + /** + * A fallback implementation of `isPlainObject` which checks if a given value + * is an object created by the `Object` constructor, assuming objects created + * by the `Object` constructor have no inherited enumerable properties and that + * there are no `Object.prototype` extensions. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. + */ + function shimIsPlainObject(value) { + var ctor, + result; + + // avoid non Object objects, `arguments` objects, and DOM elements + if (!(value && toString.call(value) == objectClass) || + (ctor = value.constructor, isFunction(ctor) && !(ctor instanceof ctor))) { + return false; + } + // In most environments an object's own properties are iterated before + // its inherited properties. If the last iterated property is an object's + // own property then there are no inherited enumerable properties. + forIn(value, function(value, key) { + result = key; + }); + return typeof result == 'undefined' || hasOwnProperty.call(value, result); + } + + /** + * Used by `unescape` to convert HTML entities to characters. + * + * @private + * @param {string} match The matched character to unescape. + * @returns {string} Returns the unescaped character. + */ + function unescapeHtmlChar(match) { + return htmlUnescapes[match]; + } + + /*--------------------------------------------------------------------------*/ + + /** + * Checks if `value` is an `arguments` object. + * + * @static + * @memberOf _ + * @category Objects + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if the `value` is an `arguments` object, else `false`. + * @example + * + * (function() { return _.isArguments(arguments); })(1, 2, 3); + * // => true + * + * _.isArguments([1, 2, 3]); + * // => false + */ + function isArguments(value) { + return value && typeof value == 'object' && typeof value.length == 'number' && + toString.call(value) == argsClass || false; + } + + /** + * Checks if `value` is an array. + * + * @static + * @memberOf _ + * @type Function + * @category Objects + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if the `value` is an array, else `false`. + * @example + * + * (function() { return _.isArray(arguments); })(); + * // => false + * + * _.isArray([1, 2, 3]); + * // => true + */ + var isArray = nativeIsArray || function(value) { + return value && typeof value == 'object' && typeof value.length == 'number' && + toString.call(value) == arrayClass || false; + }; + + /** + * A fallback implementation of `Object.keys` which produces an array of the + * given object's own enumerable property names. + * + * @private + * @type Function + * @param {Object} object The object to inspect. + * @returns {Array} Returns an array of property names. + */ + var shimKeys = function(object) { + var index, iterable = object, result = []; + if (!iterable) return result; + if (!(objectTypes[typeof object])) return result; + for (index in iterable) { + if (hasOwnProperty.call(iterable, index)) { + result.push(index); + } + } + return result + }; + + /** + * Creates an array composed of the own enumerable property names of an object. + * + * @static + * @memberOf _ + * @category Objects + * @param {Object} object The object to inspect. + * @returns {Array} Returns an array of property names. + * @example + * + * _.keys({ 'one': 1, 'two': 2, 'three': 3 }); + * // => ['one', 'two', 'three'] (property order is not guaranteed across environments) + */ + var keys = !nativeKeys ? shimKeys : function(object) { + if (!isObject(object)) { + return []; + } + return nativeKeys(object); + }; + + /** + * Used to convert characters to HTML entities: + * + * Though the `>` character is escaped for symmetry, characters like `>` and `/` + * don't require escaping in HTML and have no special meaning unless they're part + * of a tag or an unquoted attribute value. + * http://mathiasbynens.be/notes/ambiguous-ampersands (under "semi-related fun fact") + */ + var htmlEscapes = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''' + }; + + /** Used to convert HTML entities to characters */ + var htmlUnescapes = invert(htmlEscapes); + + /** Used to match HTML entities and HTML characters */ + var reEscapedHtml = RegExp('(' + keys(htmlUnescapes).join('|') + ')', 'g'), + reUnescapedHtml = RegExp('[' + keys(htmlEscapes).join('') + ']', 'g'); + + /*--------------------------------------------------------------------------*/ + + /** + * Assigns own enumerable properties of source object(s) to the destination + * object. Subsequent sources will overwrite property assignments of previous + * sources. If a callback is provided it will be executed to produce the + * assigned values. The callback is bound to `thisArg` and invoked with two + * arguments; (objectValue, sourceValue). + * + * @static + * @memberOf _ + * @type Function + * @alias extend + * @category Objects + * @param {Object} object The destination object. + * @param {...Object} [source] The source objects. + * @param {Function} [callback] The function to customize assigning values. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {Object} Returns the destination object. + * @example + * + * _.assign({ 'name': 'fred' }, { 'employer': 'slate' }); + * // => { 'name': 'fred', 'employer': 'slate' } + * + * var defaults = _.partialRight(_.assign, function(a, b) { + * return typeof a == 'undefined' ? b : a; + * }); + * + * var object = { 'name': 'barney' }; + * defaults(object, { 'name': 'fred', 'employer': 'slate' }); + * // => { 'name': 'barney', 'employer': 'slate' } + */ + var assign = function(object, source, guard) { + var index, iterable = object, result = iterable; + if (!iterable) return result; + var args = arguments, + argsIndex = 0, + argsLength = typeof guard == 'number' ? 2 : args.length; + if (argsLength > 3 && typeof args[argsLength - 2] == 'function') { + var callback = baseCreateCallback(args[--argsLength - 1], args[argsLength--], 2); + } else if (argsLength > 2 && typeof args[argsLength - 1] == 'function') { + callback = args[--argsLength]; + } + while (++argsIndex < argsLength) { + iterable = args[argsIndex]; + if (iterable && objectTypes[typeof iterable]) { + var ownIndex = -1, + ownProps = objectTypes[typeof iterable] && keys(iterable), + length = ownProps ? ownProps.length : 0; + + while (++ownIndex < length) { + index = ownProps[ownIndex]; + result[index] = callback ? callback(result[index], iterable[index]) : iterable[index]; + } + } + } + return result + }; + + /** + * Creates a clone of `value`. If `isDeep` is `true` nested objects will also + * be cloned, otherwise they will be assigned by reference. If a callback + * is provided it will be executed to produce the cloned values. If the + * callback returns `undefined` cloning will be handled by the method instead. + * The callback is bound to `thisArg` and invoked with one argument; (value). + * + * @static + * @memberOf _ + * @category Objects + * @param {*} value The value to clone. + * @param {boolean} [isDeep=false] Specify a deep clone. + * @param {Function} [callback] The function to customize cloning values. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {*} Returns the cloned value. + * @example + * + * var characters = [ + * { 'name': 'barney', 'age': 36 }, + * { 'name': 'fred', 'age': 40 } + * ]; + * + * var shallow = _.clone(characters); + * shallow[0] === characters[0]; + * // => true + * + * var deep = _.clone(characters, true); + * deep[0] === characters[0]; + * // => false + * + * _.mixin({ + * 'clone': _.partialRight(_.clone, function(value) { + * return _.isElement(value) ? value.cloneNode(false) : undefined; + * }) + * }); + * + * var clone = _.clone(document.body); + * clone.childNodes.length; + * // => 0 + */ + function clone(value, isDeep, callback, thisArg) { + // allows working with "Collections" methods without using their `index` + // and `collection` arguments for `isDeep` and `callback` + if (typeof isDeep != 'boolean' && isDeep != null) { + thisArg = callback; + callback = isDeep; + isDeep = false; + } + return baseClone(value, isDeep, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 1)); + } + + /** + * Creates a deep clone of `value`. If a callback is provided it will be + * executed to produce the cloned values. If the callback returns `undefined` + * cloning will be handled by the method instead. The callback is bound to + * `thisArg` and invoked with one argument; (value). + * + * Note: This method is loosely based on the structured clone algorithm. Functions + * and DOM nodes are **not** cloned. The enumerable properties of `arguments` objects and + * objects created by constructors other than `Object` are cloned to plain `Object` objects. + * See http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm. + * + * @static + * @memberOf _ + * @category Objects + * @param {*} value The value to deep clone. + * @param {Function} [callback] The function to customize cloning values. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {*} Returns the deep cloned value. + * @example + * + * var characters = [ + * { 'name': 'barney', 'age': 36 }, + * { 'name': 'fred', 'age': 40 } + * ]; + * + * var deep = _.cloneDeep(characters); + * deep[0] === characters[0]; + * // => false + * + * var view = { + * 'label': 'docs', + * 'node': element + * }; + * + * var clone = _.cloneDeep(view, function(value) { + * return _.isElement(value) ? value.cloneNode(true) : undefined; + * }); + * + * clone.node == view.node; + * // => false + */ + function cloneDeep(value, callback, thisArg) { + return baseClone(value, true, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 1)); + } + + /** + * Creates an object that inherits from the given `prototype` object. If a + * `properties` object is provided its own enumerable properties are assigned + * to the created object. + * + * @static + * @memberOf _ + * @category Objects + * @param {Object} prototype The object to inherit from. + * @param {Object} [properties] The properties to assign to the object. + * @returns {Object} Returns the new object. + * @example + * + * function Shape() { + * this.x = 0; + * this.y = 0; + * } + * + * function Circle() { + * Shape.call(this); + * } + * + * Circle.prototype = _.create(Shape.prototype, { 'constructor': Circle }); + * + * var circle = new Circle; + * circle instanceof Circle; + * // => true + * + * circle instanceof Shape; + * // => true + */ + function create(prototype, properties) { + var result = baseCreate(prototype); + return properties ? assign(result, properties) : result; + } + + /** + * Assigns own enumerable properties of source object(s) to the destination + * object for all destination properties that resolve to `undefined`. Once a + * property is set, additional defaults of the same property will be ignored. + * + * @static + * @memberOf _ + * @type Function + * @category Objects + * @param {Object} object The destination object. + * @param {...Object} [source] The source objects. + * @param- {Object} [guard] Allows working with `_.reduce` without using its + * `key` and `object` arguments as sources. + * @returns {Object} Returns the destination object. + * @example + * + * var object = { 'name': 'barney' }; + * _.defaults(object, { 'name': 'fred', 'employer': 'slate' }); + * // => { 'name': 'barney', 'employer': 'slate' } + */ + var defaults = function(object, source, guard) { + var index, iterable = object, result = iterable; + if (!iterable) return result; + var args = arguments, + argsIndex = 0, + argsLength = typeof guard == 'number' ? 2 : args.length; + while (++argsIndex < argsLength) { + iterable = args[argsIndex]; + if (iterable && objectTypes[typeof iterable]) { + var ownIndex = -1, + ownProps = objectTypes[typeof iterable] && keys(iterable), + length = ownProps ? ownProps.length : 0; + + while (++ownIndex < length) { + index = ownProps[ownIndex]; + if (typeof result[index] == 'undefined') result[index] = iterable[index]; + } + } + } + return result + }; + + /** + * This method is like `_.findIndex` except that it returns the key of the + * first element that passes the callback check, instead of the element itself. + * + * If a property name is provided for `callback` the created "_.pluck" style + * callback will return the property value of the given element. + * + * If an object is provided for `callback` the created "_.where" style callback + * will return `true` for elements that have the properties of the given object, + * else `false`. + * + * @static + * @memberOf _ + * @category Objects + * @param {Object} object The object to search. + * @param {Function|Object|string} [callback=identity] The function called per + * iteration. If a property name or object is provided it will be used to + * create a "_.pluck" or "_.where" style callback, respectively. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {string|undefined} Returns the key of the found element, else `undefined`. + * @example + * + * var characters = { + * 'barney': { 'age': 36, 'blocked': false }, + * 'fred': { 'age': 40, 'blocked': true }, + * 'pebbles': { 'age': 1, 'blocked': false } + * }; + * + * _.findKey(characters, function(chr) { + * return chr.age < 40; + * }); + * // => 'barney' (property order is not guaranteed across environments) + * + * // using "_.where" callback shorthand + * _.findKey(characters, { 'age': 1 }); + * // => 'pebbles' + * + * // using "_.pluck" callback shorthand + * _.findKey(characters, 'blocked'); + * // => 'fred' + */ + function findKey(object, callback, thisArg) { + var result; + callback = lodash.createCallback(callback, thisArg, 3); + forOwn(object, function(value, key, object) { + if (callback(value, key, object)) { + result = key; + return false; + } + }); + return result; + } + + /** + * This method is like `_.findKey` except that it iterates over elements + * of a `collection` in the opposite order. + * + * If a property name is provided for `callback` the created "_.pluck" style + * callback will return the property value of the given element. + * + * If an object is provided for `callback` the created "_.where" style callback + * will return `true` for elements that have the properties of the given object, + * else `false`. + * + * @static + * @memberOf _ + * @category Objects + * @param {Object} object The object to search. + * @param {Function|Object|string} [callback=identity] The function called per + * iteration. If a property name or object is provided it will be used to + * create a "_.pluck" or "_.where" style callback, respectively. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {string|undefined} Returns the key of the found element, else `undefined`. + * @example + * + * var characters = { + * 'barney': { 'age': 36, 'blocked': true }, + * 'fred': { 'age': 40, 'blocked': false }, + * 'pebbles': { 'age': 1, 'blocked': true } + * }; + * + * _.findLastKey(characters, function(chr) { + * return chr.age < 40; + * }); + * // => returns `pebbles`, assuming `_.findKey` returns `barney` + * + * // using "_.where" callback shorthand + * _.findLastKey(characters, { 'age': 40 }); + * // => 'fred' + * + * // using "_.pluck" callback shorthand + * _.findLastKey(characters, 'blocked'); + * // => 'pebbles' + */ + function findLastKey(object, callback, thisArg) { + var result; + callback = lodash.createCallback(callback, thisArg, 3); + forOwnRight(object, function(value, key, object) { + if (callback(value, key, object)) { + result = key; + return false; + } + }); + return result; + } + + /** + * Iterates over own and inherited enumerable properties of an object, + * executing the callback for each property. The callback is bound to `thisArg` + * and invoked with three arguments; (value, key, object). Callbacks may exit + * iteration early by explicitly returning `false`. + * + * @static + * @memberOf _ + * @type Function + * @category Objects + * @param {Object} object The object to iterate over. + * @param {Function} [callback=identity] The function called per iteration. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {Object} Returns `object`. + * @example + * + * function Shape() { + * this.x = 0; + * this.y = 0; + * } + * + * Shape.prototype.move = function(x, y) { + * this.x += x; + * this.y += y; + * }; + * + * _.forIn(new Shape, function(value, key) { + * console.log(key); + * }); + * // => logs 'x', 'y', and 'move' (property order is not guaranteed across environments) + */ + var forIn = function(collection, callback, thisArg) { + var index, iterable = collection, result = iterable; + if (!iterable) return result; + if (!objectTypes[typeof iterable]) return result; + callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3); + for (index in iterable) { + if (callback(iterable[index], index, collection) === false) return result; + } + return result + }; + + /** + * This method is like `_.forIn` except that it iterates over elements + * of a `collection` in the opposite order. + * + * @static + * @memberOf _ + * @category Objects + * @param {Object} object The object to iterate over. + * @param {Function} [callback=identity] The function called per iteration. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {Object} Returns `object`. + * @example + * + * function Shape() { + * this.x = 0; + * this.y = 0; + * } + * + * Shape.prototype.move = function(x, y) { + * this.x += x; + * this.y += y; + * }; + * + * _.forInRight(new Shape, function(value, key) { + * console.log(key); + * }); + * // => logs 'move', 'y', and 'x' assuming `_.forIn ` logs 'x', 'y', and 'move' + */ + function forInRight(object, callback, thisArg) { + var pairs = []; + + forIn(object, function(value, key) { + pairs.push(key, value); + }); + + var length = pairs.length; + callback = baseCreateCallback(callback, thisArg, 3); + while (length--) { + if (callback(pairs[length--], pairs[length], object) === false) { + break; + } + } + return object; + } + + /** + * Iterates over own enumerable properties of an object, executing the callback + * for each property. The callback is bound to `thisArg` and invoked with three + * arguments; (value, key, object). Callbacks may exit iteration early by + * explicitly returning `false`. + * + * @static + * @memberOf _ + * @type Function + * @category Objects + * @param {Object} object The object to iterate over. + * @param {Function} [callback=identity] The function called per iteration. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {Object} Returns `object`. + * @example + * + * _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) { + * console.log(key); + * }); + * // => logs '0', '1', and 'length' (property order is not guaranteed across environments) + */ + var forOwn = function(collection, callback, thisArg) { + var index, iterable = collection, result = iterable; + if (!iterable) return result; + if (!objectTypes[typeof iterable]) return result; + callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3); + var ownIndex = -1, + ownProps = objectTypes[typeof iterable] && keys(iterable), + length = ownProps ? ownProps.length : 0; + + while (++ownIndex < length) { + index = ownProps[ownIndex]; + if (callback(iterable[index], index, collection) === false) return result; + } + return result + }; + + /** + * This method is like `_.forOwn` except that it iterates over elements + * of a `collection` in the opposite order. + * + * @static + * @memberOf _ + * @category Objects + * @param {Object} object The object to iterate over. + * @param {Function} [callback=identity] The function called per iteration. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {Object} Returns `object`. + * @example + * + * _.forOwnRight({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) { + * console.log(key); + * }); + * // => logs 'length', '1', and '0' assuming `_.forOwn` logs '0', '1', and 'length' + */ + function forOwnRight(object, callback, thisArg) { + var props = keys(object), + length = props.length; + + callback = baseCreateCallback(callback, thisArg, 3); + while (length--) { + var key = props[length]; + if (callback(object[key], key, object) === false) { + break; + } + } + return object; + } + + /** + * Creates a sorted array of property names of all enumerable properties, + * own and inherited, of `object` that have function values. + * + * @static + * @memberOf _ + * @alias methods + * @category Objects + * @param {Object} object The object to inspect. + * @returns {Array} Returns an array of property names that have function values. + * @example + * + * _.functions(_); + * // => ['all', 'any', 'bind', 'bindAll', 'clone', 'compact', 'compose', ...] + */ + function functions(object) { + var result = []; + forIn(object, function(value, key) { + if (isFunction(value)) { + result.push(key); + } + }); + return result.sort(); + } + + /** + * Checks if the specified property name exists as a direct property of `object`, + * instead of an inherited property. + * + * @static + * @memberOf _ + * @category Objects + * @param {Object} object The object to inspect. + * @param {string} key The name of the property to check. + * @returns {boolean} Returns `true` if key is a direct property, else `false`. + * @example + * + * _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b'); + * // => true + */ + function has(object, key) { + return object ? hasOwnProperty.call(object, key) : false; + } + + /** + * Creates an object composed of the inverted keys and values of the given object. + * + * @static + * @memberOf _ + * @category Objects + * @param {Object} object The object to invert. + * @returns {Object} Returns the created inverted object. + * @example + * + * _.invert({ 'first': 'fred', 'second': 'barney' }); + * // => { 'fred': 'first', 'barney': 'second' } + */ + function invert(object) { + var index = -1, + props = keys(object), + length = props.length, + result = {}; + + while (++index < length) { + var key = props[index]; + result[object[key]] = key; + } + return result; + } + + /** + * Checks if `value` is a boolean value. + * + * @static + * @memberOf _ + * @category Objects + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if the `value` is a boolean value, else `false`. + * @example + * + * _.isBoolean(null); + * // => false + */ + function isBoolean(value) { + return value === true || value === false || + value && typeof value == 'object' && toString.call(value) == boolClass || false; + } + + /** + * Checks if `value` is a date. + * + * @static + * @memberOf _ + * @category Objects + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if the `value` is a date, else `false`. + * @example + * + * _.isDate(new Date); + * // => true + */ + function isDate(value) { + return value && typeof value == 'object' && toString.call(value) == dateClass || false; + } + + /** + * Checks if `value` is a DOM element. + * + * @static + * @memberOf _ + * @category Objects + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if the `value` is a DOM element, else `false`. + * @example + * + * _.isElement(document.body); + * // => true + */ + function isElement(value) { + return value && value.nodeType === 1 || false; + } + + /** + * Checks if `value` is empty. Arrays, strings, or `arguments` objects with a + * length of `0` and objects with no own enumerable properties are considered + * "empty". + * + * @static + * @memberOf _ + * @category Objects + * @param {Array|Object|string} value The value to inspect. + * @returns {boolean} Returns `true` if the `value` is empty, else `false`. + * @example + * + * _.isEmpty([1, 2, 3]); + * // => false + * + * _.isEmpty({}); + * // => true + * + * _.isEmpty(''); + * // => true + */ + function isEmpty(value) { + var result = true; + if (!value) { + return result; + } + var className = toString.call(value), + length = value.length; + + if ((className == arrayClass || className == stringClass || className == argsClass ) || + (className == objectClass && typeof length == 'number' && isFunction(value.splice))) { + return !length; + } + forOwn(value, function() { + return (result = false); + }); + return result; + } + + /** + * Performs a deep comparison between two values to determine if they are + * equivalent to each other. If a callback is provided it will be executed + * to compare values. If the callback returns `undefined` comparisons will + * be handled by the method instead. The callback is bound to `thisArg` and + * invoked with two arguments; (a, b). + * + * @static + * @memberOf _ + * @category Objects + * @param {*} a The value to compare. + * @param {*} b The other value to compare. + * @param {Function} [callback] The function to customize comparing values. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + * @example + * + * var object = { 'name': 'fred' }; + * var copy = { 'name': 'fred' }; + * + * object == copy; + * // => false + * + * _.isEqual(object, copy); + * // => true + * + * var words = ['hello', 'goodbye']; + * var otherWords = ['hi', 'goodbye']; + * + * _.isEqual(words, otherWords, function(a, b) { + * var reGreet = /^(?:hello|hi)$/i, + * aGreet = _.isString(a) && reGreet.test(a), + * bGreet = _.isString(b) && reGreet.test(b); + * + * return (aGreet || bGreet) ? (aGreet == bGreet) : undefined; + * }); + * // => true + */ + function isEqual(a, b, callback, thisArg) { + return baseIsEqual(a, b, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 2)); + } + + /** + * Checks if `value` is, or can be coerced to, a finite number. + * + * Note: This is not the same as native `isFinite` which will return true for + * booleans and empty strings. See http://es5.github.io/#x15.1.2.5. + * + * @static + * @memberOf _ + * @category Objects + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if the `value` is finite, else `false`. + * @example + * + * _.isFinite(-101); + * // => true + * + * _.isFinite('10'); + * // => true + * + * _.isFinite(true); + * // => false + * + * _.isFinite(''); + * // => false + * + * _.isFinite(Infinity); + * // => false + */ + function isFinite(value) { + return nativeIsFinite(value) && !nativeIsNaN(parseFloat(value)); + } + + /** + * Checks if `value` is a function. + * + * @static + * @memberOf _ + * @category Objects + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if the `value` is a function, else `false`. + * @example + * + * _.isFunction(_); + * // => true + */ + function isFunction(value) { + return typeof value == 'function'; + } + + /** + * Checks if `value` is the language type of Object. + * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @category Objects + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if the `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(1); + * // => false + */ + function isObject(value) { + // check if the value is the ECMAScript language type of Object + // http://es5.github.io/#x8 + // and avoid a V8 bug + // http://code.google.com/p/v8/issues/detail?id=2291 + return !!(value && objectTypes[typeof value]); + } + + /** + * Checks if `value` is `NaN`. + * + * Note: This is not the same as native `isNaN` which will return `true` for + * `undefined` and other non-numeric values. See http://es5.github.io/#x15.1.2.4. + * + * @static + * @memberOf _ + * @category Objects + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if the `value` is `NaN`, else `false`. + * @example + * + * _.isNaN(NaN); + * // => true + * + * _.isNaN(new Number(NaN)); + * // => true + * + * isNaN(undefined); + * // => true + * + * _.isNaN(undefined); + * // => false + */ + function isNaN(value) { + // `NaN` as a primitive is the only value that is not equal to itself + // (perform the [[Class]] check first to avoid errors with some host objects in IE) + return isNumber(value) && value != +value; + } + + /** + * Checks if `value` is `null`. + * + * @static + * @memberOf _ + * @category Objects + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if the `value` is `null`, else `false`. + * @example + * + * _.isNull(null); + * // => true + * + * _.isNull(undefined); + * // => false + */ + function isNull(value) { + return value === null; + } + + /** + * Checks if `value` is a number. + * + * Note: `NaN` is considered a number. See http://es5.github.io/#x8.5. + * + * @static + * @memberOf _ + * @category Objects + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if the `value` is a number, else `false`. + * @example + * + * _.isNumber(8.4 * 5); + * // => true + */ + function isNumber(value) { + return typeof value == 'number' || + value && typeof value == 'object' && toString.call(value) == numberClass || false; + } + + /** + * Checks if `value` is an object created by the `Object` constructor. + * + * @static + * @memberOf _ + * @category Objects + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. + * @example + * + * function Shape() { + * this.x = 0; + * this.y = 0; + * } + * + * _.isPlainObject(new Shape); + * // => false + * + * _.isPlainObject([1, 2, 3]); + * // => false + * + * _.isPlainObject({ 'x': 0, 'y': 0 }); + * // => true + */ + var isPlainObject = !getPrototypeOf ? shimIsPlainObject : function(value) { + if (!(value && toString.call(value) == objectClass)) { + return false; + } + var valueOf = value.valueOf, + objProto = isNative(valueOf) && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto); + + return objProto + ? (value == objProto || getPrototypeOf(value) == objProto) + : shimIsPlainObject(value); + }; + + /** + * Checks if `value` is a regular expression. + * + * @static + * @memberOf _ + * @category Objects + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if the `value` is a regular expression, else `false`. + * @example + * + * _.isRegExp(/fred/); + * // => true + */ + function isRegExp(value) { + return value && typeof value == 'object' && toString.call(value) == regexpClass || false; + } + + /** + * Checks if `value` is a string. + * + * @static + * @memberOf _ + * @category Objects + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if the `value` is a string, else `false`. + * @example + * + * _.isString('fred'); + * // => true + */ + function isString(value) { + return typeof value == 'string' || + value && typeof value == 'object' && toString.call(value) == stringClass || false; + } + + /** + * Checks if `value` is `undefined`. + * + * @static + * @memberOf _ + * @category Objects + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if the `value` is `undefined`, else `false`. + * @example + * + * _.isUndefined(void 0); + * // => true + */ + function isUndefined(value) { + return typeof value == 'undefined'; + } + + /** + * Creates an object with the same keys as `object` and values generated by + * running each own enumerable property of `object` through the callback. + * The callback is bound to `thisArg` and invoked with three arguments; + * (value, key, object). + * + * If a property name is provided for `callback` the created "_.pluck" style + * callback will return the property value of the given element. + * + * If an object is provided for `callback` the created "_.where" style callback + * will return `true` for elements that have the properties of the given object, + * else `false`. + * + * @static + * @memberOf _ + * @category Objects + * @param {Object} object The object to iterate over. + * @param {Function|Object|string} [callback=identity] The function called + * per iteration. If a property name or object is provided it will be used + * to create a "_.pluck" or "_.where" style callback, respectively. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {Array} Returns a new object with values of the results of each `callback` execution. + * @example + * + * _.mapValues({ 'a': 1, 'b': 2, 'c': 3} , function(num) { return num * 3; }); + * // => { 'a': 3, 'b': 6, 'c': 9 } + * + * var characters = { + * 'fred': { 'name': 'fred', 'age': 40 }, + * 'pebbles': { 'name': 'pebbles', 'age': 1 } + * }; + * + * // using "_.pluck" callback shorthand + * _.mapValues(characters, 'age'); + * // => { 'fred': 40, 'pebbles': 1 } + */ + function mapValues(object, callback, thisArg) { + var result = {}; + callback = lodash.createCallback(callback, thisArg, 3); + + forOwn(object, function(value, key, object) { + result[key] = callback(value, key, object); + }); + return result; + } + + /** + * Recursively merges own enumerable properties of the source object(s), that + * don't resolve to `undefined` into the destination object. Subsequent sources + * will overwrite property assignments of previous sources. If a callback is + * provided it will be executed to produce the merged values of the destination + * and source properties. If the callback returns `undefined` merging will + * be handled by the method instead. The callback is bound to `thisArg` and + * invoked with two arguments; (objectValue, sourceValue). + * + * @static + * @memberOf _ + * @category Objects + * @param {Object} object The destination object. + * @param {...Object} [source] The source objects. + * @param {Function} [callback] The function to customize merging properties. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {Object} Returns the destination object. + * @example + * + * var names = { + * 'characters': [ + * { 'name': 'barney' }, + * { 'name': 'fred' } + * ] + * }; + * + * var ages = { + * 'characters': [ + * { 'age': 36 }, + * { 'age': 40 } + * ] + * }; + * + * _.merge(names, ages); + * // => { 'characters': [{ 'name': 'barney', 'age': 36 }, { 'name': 'fred', 'age': 40 }] } + * + * var food = { + * 'fruits': ['apple'], + * 'vegetables': ['beet'] + * }; + * + * var otherFood = { + * 'fruits': ['banana'], + * 'vegetables': ['carrot'] + * }; + * + * _.merge(food, otherFood, function(a, b) { + * return _.isArray(a) ? a.concat(b) : undefined; + * }); + * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot] } + */ + function merge(object) { + var args = arguments, + length = 2; + + if (!isObject(object)) { + return object; + } + // allows working with `_.reduce` and `_.reduceRight` without using + // their `index` and `collection` arguments + if (typeof args[2] != 'number') { + length = args.length; + } + if (length > 3 && typeof args[length - 2] == 'function') { + var callback = baseCreateCallback(args[--length - 1], args[length--], 2); + } else if (length > 2 && typeof args[length - 1] == 'function') { + callback = args[--length]; + } + var sources = slice(arguments, 1, length), + index = -1, + stackA = getArray(), + stackB = getArray(); + + while (++index < length) { + baseMerge(object, sources[index], callback, stackA, stackB); + } + releaseArray(stackA); + releaseArray(stackB); + return object; + } + + /** + * Creates a shallow clone of `object` excluding the specified properties. + * Property names may be specified as individual arguments or as arrays of + * property names. If a callback is provided it will be executed for each + * property of `object` omitting the properties the callback returns truey + * for. The callback is bound to `thisArg` and invoked with three arguments; + * (value, key, object). + * + * @static + * @memberOf _ + * @category Objects + * @param {Object} object The source object. + * @param {Function|...string|string[]} [callback] The properties to omit or the + * function called per iteration. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {Object} Returns an object without the omitted properties. + * @example + * + * _.omit({ 'name': 'fred', 'age': 40 }, 'age'); + * // => { 'name': 'fred' } + * + * _.omit({ 'name': 'fred', 'age': 40 }, function(value) { + * return typeof value == 'number'; + * }); + * // => { 'name': 'fred' } + */ + function omit(object, callback, thisArg) { + var result = {}; + if (typeof callback != 'function') { + var props = []; + forIn(object, function(value, key) { + props.push(key); + }); + props = baseDifference(props, baseFlatten(arguments, true, false, 1)); + + var index = -1, + length = props.length; + + while (++index < length) { + var key = props[index]; + result[key] = object[key]; + } + } else { + callback = lodash.createCallback(callback, thisArg, 3); + forIn(object, function(value, key, object) { + if (!callback(value, key, object)) { + result[key] = value; + } + }); + } + return result; + } + + /** + * Creates a two dimensional array of an object's key-value pairs, + * i.e. `[[key1, value1], [key2, value2]]`. + * + * @static + * @memberOf _ + * @category Objects + * @param {Object} object The object to inspect. + * @returns {Array} Returns new array of key-value pairs. + * @example + * + * _.pairs({ 'barney': 36, 'fred': 40 }); + * // => [['barney', 36], ['fred', 40]] (property order is not guaranteed across environments) + */ + function pairs(object) { + var index = -1, + props = keys(object), + length = props.length, + result = Array(length); + + while (++index < length) { + var key = props[index]; + result[index] = [key, object[key]]; + } + return result; + } + + /** + * Creates a shallow clone of `object` composed of the specified properties. + * Property names may be specified as individual arguments or as arrays of + * property names. If a callback is provided it will be executed for each + * property of `object` picking the properties the callback returns truey + * for. The callback is bound to `thisArg` and invoked with three arguments; + * (value, key, object). + * + * @static + * @memberOf _ + * @category Objects + * @param {Object} object The source object. + * @param {Function|...string|string[]} [callback] The function called per + * iteration or property names to pick, specified as individual property + * names or arrays of property names. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {Object} Returns an object composed of the picked properties. + * @example + * + * _.pick({ 'name': 'fred', '_userid': 'fred1' }, 'name'); + * // => { 'name': 'fred' } + * + * _.pick({ 'name': 'fred', '_userid': 'fred1' }, function(value, key) { + * return key.charAt(0) != '_'; + * }); + * // => { 'name': 'fred' } + */ + function pick(object, callback, thisArg) { + var result = {}; + if (typeof callback != 'function') { + var index = -1, + props = baseFlatten(arguments, true, false, 1), + length = isObject(object) ? props.length : 0; + + while (++index < length) { + var key = props[index]; + if (key in object) { + result[key] = object[key]; + } + } + } else { + callback = lodash.createCallback(callback, thisArg, 3); + forIn(object, function(value, key, object) { + if (callback(value, key, object)) { + result[key] = value; + } + }); + } + return result; + } + + /** + * An alternative to `_.reduce` this method transforms `object` to a new + * `accumulator` object which is the result of running each of its own + * enumerable properties through a callback, with each callback execution + * potentially mutating the `accumulator` object. The callback is bound to + * `thisArg` and invoked with four arguments; (accumulator, value, key, object). + * Callbacks may exit iteration early by explicitly returning `false`. + * + * @static + * @memberOf _ + * @category Objects + * @param {Array|Object} object The object to iterate over. + * @param {Function} [callback=identity] The function called per iteration. + * @param {*} [accumulator] The custom accumulator value. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {*} Returns the accumulated value. + * @example + * + * var squares = _.transform([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], function(result, num) { + * num *= num; + * if (num % 2) { + * return result.push(num) < 3; + * } + * }); + * // => [1, 9, 25] + * + * var mapped = _.transform({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) { + * result[key] = num * 3; + * }); + * // => { 'a': 3, 'b': 6, 'c': 9 } + */ + function transform(object, callback, accumulator, thisArg) { + var isArr = isArray(object); + if (accumulator == null) { + if (isArr) { + accumulator = []; + } else { + var ctor = object && object.constructor, + proto = ctor && ctor.prototype; + + accumulator = baseCreate(proto); + } + } + if (callback) { + callback = lodash.createCallback(callback, thisArg, 4); + (isArr ? forEach : forOwn)(object, function(value, index, object) { + return callback(accumulator, value, index, object); + }); + } + return accumulator; + } + + /** + * Creates an array composed of the own enumerable property values of `object`. + * + * @static + * @memberOf _ + * @category Objects + * @param {Object} object The object to inspect. + * @returns {Array} Returns an array of property values. + * @example + * + * _.values({ 'one': 1, 'two': 2, 'three': 3 }); + * // => [1, 2, 3] (property order is not guaranteed across environments) + */ + function values(object) { + var index = -1, + props = keys(object), + length = props.length, + result = Array(length); + + while (++index < length) { + result[index] = object[props[index]]; + } + return result; + } + + /*--------------------------------------------------------------------------*/ + + /** + * Creates an array of elements from the specified indexes, or keys, of the + * `collection`. Indexes may be specified as individual arguments or as arrays + * of indexes. + * + * @static + * @memberOf _ + * @category Collections + * @param {Array|Object|string} collection The collection to iterate over. + * @param {...(number|number[]|string|string[])} [index] The indexes of `collection` + * to retrieve, specified as individual indexes or arrays of indexes. + * @returns {Array} Returns a new array of elements corresponding to the + * provided indexes. + * @example + * + * _.at(['a', 'b', 'c', 'd', 'e'], [0, 2, 4]); + * // => ['a', 'c', 'e'] + * + * _.at(['fred', 'barney', 'pebbles'], 0, 2); + * // => ['fred', 'pebbles'] + */ + function at(collection) { + var args = arguments, + index = -1, + props = baseFlatten(args, true, false, 1), + length = (args[2] && args[2][args[1]] === collection) ? 1 : props.length, + result = Array(length); + + while(++index < length) { + result[index] = collection[props[index]]; + } + return result; + } + + /** + * Checks if a given value is present in a collection using strict equality + * for comparisons, i.e. `===`. If `fromIndex` is negative, it is used as the + * offset from the end of the collection. + * + * @static + * @memberOf _ + * @alias include + * @category Collections + * @param {Array|Object|string} collection The collection to iterate over. + * @param {*} target The value to check for. + * @param {number} [fromIndex=0] The index to search from. + * @returns {boolean} Returns `true` if the `target` element is found, else `false`. + * @example + * + * _.contains([1, 2, 3], 1); + * // => true + * + * _.contains([1, 2, 3], 1, 2); + * // => false + * + * _.contains({ 'name': 'fred', 'age': 40 }, 'fred'); + * // => true + * + * _.contains('pebbles', 'eb'); + * // => true + */ + function contains(collection, target, fromIndex) { + var index = -1, + indexOf = getIndexOf(), + length = collection ? collection.length : 0, + result = false; + + fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex) || 0; + if (isArray(collection)) { + result = indexOf(collection, target, fromIndex) > -1; + } else if (typeof length == 'number') { + result = (isString(collection) ? collection.indexOf(target, fromIndex) : indexOf(collection, target, fromIndex)) > -1; + } else { + forOwn(collection, function(value) { + if (++index >= fromIndex) { + return !(result = value === target); + } + }); + } + return result; + } + + /** + * Creates an object composed of keys generated from the results of running + * each element of `collection` through the callback. The corresponding value + * of each key is the number of times the key was returned by the callback. + * The callback is bound to `thisArg` and invoked with three arguments; + * (value, index|key, collection). + * + * If a property name is provided for `callback` the created "_.pluck" style + * callback will return the property value of the given element. + * + * If an object is provided for `callback` the created "_.where" style callback + * will return `true` for elements that have the properties of the given object, + * else `false`. + * + * @static + * @memberOf _ + * @category Collections + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [callback=identity] The function called + * per iteration. If a property name or object is provided it will be used + * to create a "_.pluck" or "_.where" style callback, respectively. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {Object} Returns the composed aggregate object. + * @example + * + * _.countBy([4.3, 6.1, 6.4], function(num) { return Math.floor(num); }); + * // => { '4': 1, '6': 2 } + * + * _.countBy([4.3, 6.1, 6.4], function(num) { return this.floor(num); }, Math); + * // => { '4': 1, '6': 2 } + * + * _.countBy(['one', 'two', 'three'], 'length'); + * // => { '3': 2, '5': 1 } + */ + var countBy = createAggregator(function(result, value, key) { + (hasOwnProperty.call(result, key) ? result[key]++ : result[key] = 1); + }); + + /** + * Checks if the given callback returns truey value for **all** elements of + * a collection. The callback is bound to `thisArg` and invoked with three + * arguments; (value, index|key, collection). + * + * If a property name is provided for `callback` the created "_.pluck" style + * callback will return the property value of the given element. + * + * If an object is provided for `callback` the created "_.where" style callback + * will return `true` for elements that have the properties of the given object, + * else `false`. + * + * @static + * @memberOf _ + * @alias all + * @category Collections + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [callback=identity] The function called + * per iteration. If a property name or object is provided it will be used + * to create a "_.pluck" or "_.where" style callback, respectively. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {boolean} Returns `true` if all elements passed the callback check, + * else `false`. + * @example + * + * _.every([true, 1, null, 'yes']); + * // => false + * + * var characters = [ + * { 'name': 'barney', 'age': 36 }, + * { 'name': 'fred', 'age': 40 } + * ]; + * + * // using "_.pluck" callback shorthand + * _.every(characters, 'age'); + * // => true + * + * // using "_.where" callback shorthand + * _.every(characters, { 'age': 36 }); + * // => false + */ + function every(collection, callback, thisArg) { + var result = true; + callback = lodash.createCallback(callback, thisArg, 3); + + var index = -1, + length = collection ? collection.length : 0; + + if (typeof length == 'number') { + while (++index < length) { + if (!(result = !!callback(collection[index], index, collection))) { + break; + } + } + } else { + forOwn(collection, function(value, index, collection) { + return (result = !!callback(value, index, collection)); + }); + } + return result; + } + + /** + * Iterates over elements of a collection, returning an array of all elements + * the callback returns truey for. The callback is bound to `thisArg` and + * invoked with three arguments; (value, index|key, collection). + * + * If a property name is provided for `callback` the created "_.pluck" style + * callback will return the property value of the given element. + * + * If an object is provided for `callback` the created "_.where" style callback + * will return `true` for elements that have the properties of the given object, + * else `false`. + * + * @static + * @memberOf _ + * @alias select + * @category Collections + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [callback=identity] The function called + * per iteration. If a property name or object is provided it will be used + * to create a "_.pluck" or "_.where" style callback, respectively. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {Array} Returns a new array of elements that passed the callback check. + * @example + * + * var evens = _.filter([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; }); + * // => [2, 4, 6] + * + * var characters = [ + * { 'name': 'barney', 'age': 36, 'blocked': false }, + * { 'name': 'fred', 'age': 40, 'blocked': true } + * ]; + * + * // using "_.pluck" callback shorthand + * _.filter(characters, 'blocked'); + * // => [{ 'name': 'fred', 'age': 40, 'blocked': true }] + * + * // using "_.where" callback shorthand + * _.filter(characters, { 'age': 36 }); + * // => [{ 'name': 'barney', 'age': 36, 'blocked': false }] + */ + function filter(collection, callback, thisArg) { + var result = []; + callback = lodash.createCallback(callback, thisArg, 3); + + var index = -1, + length = collection ? collection.length : 0; + + if (typeof length == 'number') { + while (++index < length) { + var value = collection[index]; + if (callback(value, index, collection)) { + result.push(value); + } + } + } else { + forOwn(collection, function(value, index, collection) { + if (callback(value, index, collection)) { + result.push(value); + } + }); + } + return result; + } + + /** + * Iterates over elements of a collection, returning the first element that + * the callback returns truey for. The callback is bound to `thisArg` and + * invoked with three arguments; (value, index|key, collection). + * + * If a property name is provided for `callback` the created "_.pluck" style + * callback will return the property value of the given element. + * + * If an object is provided for `callback` the created "_.where" style callback + * will return `true` for elements that have the properties of the given object, + * else `false`. + * + * @static + * @memberOf _ + * @alias detect, findWhere + * @category Collections + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [callback=identity] The function called + * per iteration. If a property name or object is provided it will be used + * to create a "_.pluck" or "_.where" style callback, respectively. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {*} Returns the found element, else `undefined`. + * @example + * + * var characters = [ + * { 'name': 'barney', 'age': 36, 'blocked': false }, + * { 'name': 'fred', 'age': 40, 'blocked': true }, + * { 'name': 'pebbles', 'age': 1, 'blocked': false } + * ]; + * + * _.find(characters, function(chr) { + * return chr.age < 40; + * }); + * // => { 'name': 'barney', 'age': 36, 'blocked': false } + * + * // using "_.where" callback shorthand + * _.find(characters, { 'age': 1 }); + * // => { 'name': 'pebbles', 'age': 1, 'blocked': false } + * + * // using "_.pluck" callback shorthand + * _.find(characters, 'blocked'); + * // => { 'name': 'fred', 'age': 40, 'blocked': true } + */ + function find(collection, callback, thisArg) { + callback = lodash.createCallback(callback, thisArg, 3); + + var index = -1, + length = collection ? collection.length : 0; + + if (typeof length == 'number') { + while (++index < length) { + var value = collection[index]; + if (callback(value, index, collection)) { + return value; + } + } + } else { + var result; + forOwn(collection, function(value, index, collection) { + if (callback(value, index, collection)) { + result = value; + return false; + } + }); + return result; + } + } + + /** + * This method is like `_.find` except that it iterates over elements + * of a `collection` from right to left. + * + * @static + * @memberOf _ + * @category Collections + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [callback=identity] The function called + * per iteration. If a property name or object is provided it will be used + * to create a "_.pluck" or "_.where" style callback, respectively. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {*} Returns the found element, else `undefined`. + * @example + * + * _.findLast([1, 2, 3, 4], function(num) { + * return num % 2 == 1; + * }); + * // => 3 + */ + function findLast(collection, callback, thisArg) { + var result; + callback = lodash.createCallback(callback, thisArg, 3); + forEachRight(collection, function(value, index, collection) { + if (callback(value, index, collection)) { + result = value; + return false; + } + }); + return result; + } + + /** + * Iterates over elements of a collection, executing the callback for each + * element. The callback is bound to `thisArg` and invoked with three arguments; + * (value, index|key, collection). Callbacks may exit iteration early by + * explicitly returning `false`. + * + * Note: As with other "Collections" methods, objects with a `length` property + * are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn` + * may be used for object iteration. + * + * @static + * @memberOf _ + * @alias each + * @category Collections + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} [callback=identity] The function called per iteration. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {Array|Object|string} Returns `collection`. + * @example + * + * _([1, 2, 3]).forEach(function(num) { console.log(num); }).join(','); + * // => logs each number and returns '1,2,3' + * + * _.forEach({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { console.log(num); }); + * // => logs each number and returns the object (property order is not guaranteed across environments) + */ + function forEach(collection, callback, thisArg) { + var index = -1, + length = collection ? collection.length : 0; + + callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3); + if (typeof length == 'number') { + while (++index < length) { + if (callback(collection[index], index, collection) === false) { + break; + } + } + } else { + forOwn(collection, callback); + } + return collection; + } + + /** + * This method is like `_.forEach` except that it iterates over elements + * of a `collection` from right to left. + * + * @static + * @memberOf _ + * @alias eachRight + * @category Collections + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} [callback=identity] The function called per iteration. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {Array|Object|string} Returns `collection`. + * @example + * + * _([1, 2, 3]).forEachRight(function(num) { console.log(num); }).join(','); + * // => logs each number from right to left and returns '3,2,1' + */ + function forEachRight(collection, callback, thisArg) { + var length = collection ? collection.length : 0; + callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3); + if (typeof length == 'number') { + while (length--) { + if (callback(collection[length], length, collection) === false) { + break; + } + } + } else { + var props = keys(collection); + length = props.length; + forOwn(collection, function(value, key, collection) { + key = props ? props[--length] : --length; + return callback(collection[key], key, collection); + }); + } + return collection; + } + + /** + * Creates an object composed of keys generated from the results of running + * each element of a collection through the callback. The corresponding value + * of each key is an array of the elements responsible for generating the key. + * The callback is bound to `thisArg` and invoked with three arguments; + * (value, index|key, collection). + * + * If a property name is provided for `callback` the created "_.pluck" style + * callback will return the property value of the given element. + * + * If an object is provided for `callback` the created "_.where" style callback + * will return `true` for elements that have the properties of the given object, + * else `false` + * + * @static + * @memberOf _ + * @category Collections + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [callback=identity] The function called + * per iteration. If a property name or object is provided it will be used + * to create a "_.pluck" or "_.where" style callback, respectively. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {Object} Returns the composed aggregate object. + * @example + * + * _.groupBy([4.2, 6.1, 6.4], function(num) { return Math.floor(num); }); + * // => { '4': [4.2], '6': [6.1, 6.4] } + * + * _.groupBy([4.2, 6.1, 6.4], function(num) { return this.floor(num); }, Math); + * // => { '4': [4.2], '6': [6.1, 6.4] } + * + * // using "_.pluck" callback shorthand + * _.groupBy(['one', 'two', 'three'], 'length'); + * // => { '3': ['one', 'two'], '5': ['three'] } + */ + var groupBy = createAggregator(function(result, value, key) { + (hasOwnProperty.call(result, key) ? result[key] : result[key] = []).push(value); + }); + + /** + * Creates an object composed of keys generated from the results of running + * each element of the collection through the given callback. The corresponding + * value of each key is the last element responsible for generating the key. + * The callback is bound to `thisArg` and invoked with three arguments; + * (value, index|key, collection). + * + * If a property name is provided for `callback` the created "_.pluck" style + * callback will return the property value of the given element. + * + * If an object is provided for `callback` the created "_.where" style callback + * will return `true` for elements that have the properties of the given object, + * else `false`. + * + * @static + * @memberOf _ + * @category Collections + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [callback=identity] The function called + * per iteration. If a property name or object is provided it will be used + * to create a "_.pluck" or "_.where" style callback, respectively. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {Object} Returns the composed aggregate object. + * @example + * + * var keys = [ + * { 'dir': 'left', 'code': 97 }, + * { 'dir': 'right', 'code': 100 } + * ]; + * + * _.indexBy(keys, 'dir'); + * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } } + * + * _.indexBy(keys, function(key) { return String.fromCharCode(key.code); }); + * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } } + * + * _.indexBy(characters, function(key) { this.fromCharCode(key.code); }, String); + * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } } + */ + var indexBy = createAggregator(function(result, value, key) { + result[key] = value; + }); + + /** + * Invokes the method named by `methodName` on each element in the `collection` + * returning an array of the results of each invoked method. Additional arguments + * will be provided to each invoked method. If `methodName` is a function it + * will be invoked for, and `this` bound to, each element in the `collection`. + * + * @static + * @memberOf _ + * @category Collections + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|string} methodName The name of the method to invoke or + * the function invoked per iteration. + * @param {...*} [arg] Arguments to invoke the method with. + * @returns {Array} Returns a new array of the results of each invoked method. + * @example + * + * _.invoke([[5, 1, 7], [3, 2, 1]], 'sort'); + * // => [[1, 5, 7], [1, 2, 3]] + * + * _.invoke([123, 456], String.prototype.split, ''); + * // => [['1', '2', '3'], ['4', '5', '6']] + */ + function invoke(collection, methodName) { + var args = slice(arguments, 2), + index = -1, + isFunc = typeof methodName == 'function', + length = collection ? collection.length : 0, + result = Array(typeof length == 'number' ? length : 0); + + forEach(collection, function(value) { + result[++index] = (isFunc ? methodName : value[methodName]).apply(value, args); + }); + return result; + } + + /** + * Creates an array of values by running each element in the collection + * through the callback. The callback is bound to `thisArg` and invoked with + * three arguments; (value, index|key, collection). + * + * If a property name is provided for `callback` the created "_.pluck" style + * callback will return the property value of the given element. + * + * If an object is provided for `callback` the created "_.where" style callback + * will return `true` for elements that have the properties of the given object, + * else `false`. + * + * @static + * @memberOf _ + * @alias collect + * @category Collections + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [callback=identity] The function called + * per iteration. If a property name or object is provided it will be used + * to create a "_.pluck" or "_.where" style callback, respectively. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {Array} Returns a new array of the results of each `callback` execution. + * @example + * + * _.map([1, 2, 3], function(num) { return num * 3; }); + * // => [3, 6, 9] + * + * _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { return num * 3; }); + * // => [3, 6, 9] (property order is not guaranteed across environments) + * + * var characters = [ + * { 'name': 'barney', 'age': 36 }, + * { 'name': 'fred', 'age': 40 } + * ]; + * + * // using "_.pluck" callback shorthand + * _.map(characters, 'name'); + * // => ['barney', 'fred'] + */ + function map(collection, callback, thisArg) { + var index = -1, + length = collection ? collection.length : 0; + + callback = lodash.createCallback(callback, thisArg, 3); + if (typeof length == 'number') { + var result = Array(length); + while (++index < length) { + result[index] = callback(collection[index], index, collection); + } + } else { + result = []; + forOwn(collection, function(value, key, collection) { + result[++index] = callback(value, key, collection); + }); + } + return result; + } + + /** + * Retrieves the maximum value of a collection. If the collection is empty or + * falsey `-Infinity` is returned. If a callback is provided it will be executed + * for each value in the collection to generate the criterion by which the value + * is ranked. The callback is bound to `thisArg` and invoked with three + * arguments; (value, index, collection). + * + * If a property name is provided for `callback` the created "_.pluck" style + * callback will return the property value of the given element. + * + * If an object is provided for `callback` the created "_.where" style callback + * will return `true` for elements that have the properties of the given object, + * else `false`. + * + * @static + * @memberOf _ + * @category Collections + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [callback=identity] The function called + * per iteration. If a property name or object is provided it will be used + * to create a "_.pluck" or "_.where" style callback, respectively. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {*} Returns the maximum value. + * @example + * + * _.max([4, 2, 8, 6]); + * // => 8 + * + * var characters = [ + * { 'name': 'barney', 'age': 36 }, + * { 'name': 'fred', 'age': 40 } + * ]; + * + * _.max(characters, function(chr) { return chr.age; }); + * // => { 'name': 'fred', 'age': 40 }; + * + * // using "_.pluck" callback shorthand + * _.max(characters, 'age'); + * // => { 'name': 'fred', 'age': 40 }; + */ + function max(collection, callback, thisArg) { + var computed = -Infinity, + result = computed; + + // allows working with functions like `_.map` without using + // their `index` argument as a callback + if (typeof callback != 'function' && thisArg && thisArg[callback] === collection) { + callback = null; + } + if (callback == null && isArray(collection)) { + var index = -1, + length = collection.length; + + while (++index < length) { + var value = collection[index]; + if (value > result) { + result = value; + } + } + } else { + callback = (callback == null && isString(collection)) + ? charAtCallback + : lodash.createCallback(callback, thisArg, 3); + + forEach(collection, function(value, index, collection) { + var current = callback(value, index, collection); + if (current > computed) { + computed = current; + result = value; + } + }); + } + return result; + } + + /** + * Retrieves the minimum value of a collection. If the collection is empty or + * falsey `Infinity` is returned. If a callback is provided it will be executed + * for each value in the collection to generate the criterion by which the value + * is ranked. The callback is bound to `thisArg` and invoked with three + * arguments; (value, index, collection). + * + * If a property name is provided for `callback` the created "_.pluck" style + * callback will return the property value of the given element. + * + * If an object is provided for `callback` the created "_.where" style callback + * will return `true` for elements that have the properties of the given object, + * else `false`. + * + * @static + * @memberOf _ + * @category Collections + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [callback=identity] The function called + * per iteration. If a property name or object is provided it will be used + * to create a "_.pluck" or "_.where" style callback, respectively. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {*} Returns the minimum value. + * @example + * + * _.min([4, 2, 8, 6]); + * // => 2 + * + * var characters = [ + * { 'name': 'barney', 'age': 36 }, + * { 'name': 'fred', 'age': 40 } + * ]; + * + * _.min(characters, function(chr) { return chr.age; }); + * // => { 'name': 'barney', 'age': 36 }; + * + * // using "_.pluck" callback shorthand + * _.min(characters, 'age'); + * // => { 'name': 'barney', 'age': 36 }; + */ + function min(collection, callback, thisArg) { + var computed = Infinity, + result = computed; + + // allows working with functions like `_.map` without using + // their `index` argument as a callback + if (typeof callback != 'function' && thisArg && thisArg[callback] === collection) { + callback = null; + } + if (callback == null && isArray(collection)) { + var index = -1, + length = collection.length; + + while (++index < length) { + var value = collection[index]; + if (value < result) { + result = value; + } + } + } else { + callback = (callback == null && isString(collection)) + ? charAtCallback + : lodash.createCallback(callback, thisArg, 3); + + forEach(collection, function(value, index, collection) { + var current = callback(value, index, collection); + if (current < computed) { + computed = current; + result = value; + } + }); + } + return result; + } + + /** + * Retrieves the value of a specified property from all elements in the collection. + * + * @static + * @memberOf _ + * @type Function + * @category Collections + * @param {Array|Object|string} collection The collection to iterate over. + * @param {string} property The name of the property to pluck. + * @returns {Array} Returns a new array of property values. + * @example + * + * var characters = [ + * { 'name': 'barney', 'age': 36 }, + * { 'name': 'fred', 'age': 40 } + * ]; + * + * _.pluck(characters, 'name'); + * // => ['barney', 'fred'] + */ + var pluck = map; + + /** + * Reduces a collection to a value which is the accumulated result of running + * each element in the collection through the callback, where each successive + * callback execution consumes the return value of the previous execution. If + * `accumulator` is not provided the first element of the collection will be + * used as the initial `accumulator` value. The callback is bound to `thisArg` + * and invoked with four arguments; (accumulator, value, index|key, collection). + * + * @static + * @memberOf _ + * @alias foldl, inject + * @category Collections + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} [callback=identity] The function called per iteration. + * @param {*} [accumulator] Initial value of the accumulator. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {*} Returns the accumulated value. + * @example + * + * var sum = _.reduce([1, 2, 3], function(sum, num) { + * return sum + num; + * }); + * // => 6 + * + * var mapped = _.reduce({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) { + * result[key] = num * 3; + * return result; + * }, {}); + * // => { 'a': 3, 'b': 6, 'c': 9 } + */ + function reduce(collection, callback, accumulator, thisArg) { + if (!collection) return accumulator; + var noaccum = arguments.length < 3; + callback = lodash.createCallback(callback, thisArg, 4); + + var index = -1, + length = collection.length; + + if (typeof length == 'number') { + if (noaccum) { + accumulator = collection[++index]; + } + while (++index < length) { + accumulator = callback(accumulator, collection[index], index, collection); + } + } else { + forOwn(collection, function(value, index, collection) { + accumulator = noaccum + ? (noaccum = false, value) + : callback(accumulator, value, index, collection) + }); + } + return accumulator; + } + + /** + * This method is like `_.reduce` except that it iterates over elements + * of a `collection` from right to left. + * + * @static + * @memberOf _ + * @alias foldr + * @category Collections + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} [callback=identity] The function called per iteration. + * @param {*} [accumulator] Initial value of the accumulator. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {*} Returns the accumulated value. + * @example + * + * var list = [[0, 1], [2, 3], [4, 5]]; + * var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []); + * // => [4, 5, 2, 3, 0, 1] + */ + function reduceRight(collection, callback, accumulator, thisArg) { + var noaccum = arguments.length < 3; + callback = lodash.createCallback(callback, thisArg, 4); + forEachRight(collection, function(value, index, collection) { + accumulator = noaccum + ? (noaccum = false, value) + : callback(accumulator, value, index, collection); + }); + return accumulator; + } + + /** + * The opposite of `_.filter` this method returns the elements of a + * collection that the callback does **not** return truey for. + * + * If a property name is provided for `callback` the created "_.pluck" style + * callback will return the property value of the given element. + * + * If an object is provided for `callback` the created "_.where" style callback + * will return `true` for elements that have the properties of the given object, + * else `false`. + * + * @static + * @memberOf _ + * @category Collections + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [callback=identity] The function called + * per iteration. If a property name or object is provided it will be used + * to create a "_.pluck" or "_.where" style callback, respectively. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {Array} Returns a new array of elements that failed the callback check. + * @example + * + * var odds = _.reject([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; }); + * // => [1, 3, 5] + * + * var characters = [ + * { 'name': 'barney', 'age': 36, 'blocked': false }, + * { 'name': 'fred', 'age': 40, 'blocked': true } + * ]; + * + * // using "_.pluck" callback shorthand + * _.reject(characters, 'blocked'); + * // => [{ 'name': 'barney', 'age': 36, 'blocked': false }] + * + * // using "_.where" callback shorthand + * _.reject(characters, { 'age': 36 }); + * // => [{ 'name': 'fred', 'age': 40, 'blocked': true }] + */ + function reject(collection, callback, thisArg) { + callback = lodash.createCallback(callback, thisArg, 3); + return filter(collection, function(value, index, collection) { + return !callback(value, index, collection); + }); + } + + /** + * Retrieves a random element or `n` random elements from a collection. + * + * @static + * @memberOf _ + * @category Collections + * @param {Array|Object|string} collection The collection to sample. + * @param {number} [n] The number of elements to sample. + * @param- {Object} [guard] Allows working with functions like `_.map` + * without using their `index` arguments as `n`. + * @returns {Array} Returns the random sample(s) of `collection`. + * @example + * + * _.sample([1, 2, 3, 4]); + * // => 2 + * + * _.sample([1, 2, 3, 4], 2); + * // => [3, 1] + */ + function sample(collection, n, guard) { + if (collection && typeof collection.length != 'number') { + collection = values(collection); + } + if (n == null || guard) { + return collection ? collection[baseRandom(0, collection.length - 1)] : undefined; + } + var result = shuffle(collection); + result.length = nativeMin(nativeMax(0, n), result.length); + return result; + } + + /** + * Creates an array of shuffled values, using a version of the Fisher-Yates + * shuffle. See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle. + * + * @static + * @memberOf _ + * @category Collections + * @param {Array|Object|string} collection The collection to shuffle. + * @returns {Array} Returns a new shuffled collection. + * @example + * + * _.shuffle([1, 2, 3, 4, 5, 6]); + * // => [4, 1, 6, 3, 5, 2] + */ + function shuffle(collection) { + var index = -1, + length = collection ? collection.length : 0, + result = Array(typeof length == 'number' ? length : 0); + + forEach(collection, function(value) { + var rand = baseRandom(0, ++index); + result[index] = result[rand]; + result[rand] = value; + }); + return result; + } + + /** + * Gets the size of the `collection` by returning `collection.length` for arrays + * and array-like objects or the number of own enumerable properties for objects. + * + * @static + * @memberOf _ + * @category Collections + * @param {Array|Object|string} collection The collection to inspect. + * @returns {number} Returns `collection.length` or number of own enumerable properties. + * @example + * + * _.size([1, 2]); + * // => 2 + * + * _.size({ 'one': 1, 'two': 2, 'three': 3 }); + * // => 3 + * + * _.size('pebbles'); + * // => 7 + */ + function size(collection) { + var length = collection ? collection.length : 0; + return typeof length == 'number' ? length : keys(collection).length; + } + + /** + * Checks if the callback returns a truey value for **any** element of a + * collection. The function returns as soon as it finds a passing value and + * does not iterate over the entire collection. The callback is bound to + * `thisArg` and invoked with three arguments; (value, index|key, collection). + * + * If a property name is provided for `callback` the created "_.pluck" style + * callback will return the property value of the given element. + * + * If an object is provided for `callback` the created "_.where" style callback + * will return `true` for elements that have the properties of the given object, + * else `false`. + * + * @static + * @memberOf _ + * @alias any + * @category Collections + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [callback=identity] The function called + * per iteration. If a property name or object is provided it will be used + * to create a "_.pluck" or "_.where" style callback, respectively. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {boolean} Returns `true` if any element passed the callback check, + * else `false`. + * @example + * + * _.some([null, 0, 'yes', false], Boolean); + * // => true + * + * var characters = [ + * { 'name': 'barney', 'age': 36, 'blocked': false }, + * { 'name': 'fred', 'age': 40, 'blocked': true } + * ]; + * + * // using "_.pluck" callback shorthand + * _.some(characters, 'blocked'); + * // => true + * + * // using "_.where" callback shorthand + * _.some(characters, { 'age': 1 }); + * // => false + */ + function some(collection, callback, thisArg) { + var result; + callback = lodash.createCallback(callback, thisArg, 3); + + var index = -1, + length = collection ? collection.length : 0; + + if (typeof length == 'number') { + while (++index < length) { + if ((result = callback(collection[index], index, collection))) { + break; + } + } + } else { + forOwn(collection, function(value, index, collection) { + return !(result = callback(value, index, collection)); + }); + } + return !!result; + } + + /** + * Creates an array of elements, sorted in ascending order by the results of + * running each element in a collection through the callback. This method + * performs a stable sort, that is, it will preserve the original sort order + * of equal elements. The callback is bound to `thisArg` and invoked with + * three arguments; (value, index|key, collection). + * + * If a property name is provided for `callback` the created "_.pluck" style + * callback will return the property value of the given element. + * + * If an array of property names is provided for `callback` the collection + * will be sorted by each property value. + * + * If an object is provided for `callback` the created "_.where" style callback + * will return `true` for elements that have the properties of the given object, + * else `false`. + * + * @static + * @memberOf _ + * @category Collections + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Array|Function|Object|string} [callback=identity] The function called + * per iteration. If a property name or object is provided it will be used + * to create a "_.pluck" or "_.where" style callback, respectively. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {Array} Returns a new array of sorted elements. + * @example + * + * _.sortBy([1, 2, 3], function(num) { return Math.sin(num); }); + * // => [3, 1, 2] + * + * _.sortBy([1, 2, 3], function(num) { return this.sin(num); }, Math); + * // => [3, 1, 2] + * + * var characters = [ + * { 'name': 'barney', 'age': 36 }, + * { 'name': 'fred', 'age': 40 }, + * { 'name': 'barney', 'age': 26 }, + * { 'name': 'fred', 'age': 30 } + * ]; + * + * // using "_.pluck" callback shorthand + * _.map(_.sortBy(characters, 'age'), _.values); + * // => [['barney', 26], ['fred', 30], ['barney', 36], ['fred', 40]] + * + * // sorting by multiple properties + * _.map(_.sortBy(characters, ['name', 'age']), _.values); + * // = > [['barney', 26], ['barney', 36], ['fred', 30], ['fred', 40]] + */ + function sortBy(collection, callback, thisArg) { + var index = -1, + isArr = isArray(callback), + length = collection ? collection.length : 0, + result = Array(typeof length == 'number' ? length : 0); + + if (!isArr) { + callback = lodash.createCallback(callback, thisArg, 3); + } + forEach(collection, function(value, key, collection) { + var object = result[++index] = getObject(); + if (isArr) { + object.criteria = map(callback, function(key) { return value[key]; }); + } else { + (object.criteria = getArray())[0] = callback(value, key, collection); + } + object.index = index; + object.value = value; + }); + + length = result.length; + result.sort(compareAscending); + while (length--) { + var object = result[length]; + result[length] = object.value; + if (!isArr) { + releaseArray(object.criteria); + } + releaseObject(object); + } + return result; + } + + /** + * Converts the `collection` to an array. + * + * @static + * @memberOf _ + * @category Collections + * @param {Array|Object|string} collection The collection to convert. + * @returns {Array} Returns the new converted array. + * @example + * + * (function() { return _.toArray(arguments).slice(1); })(1, 2, 3, 4); + * // => [2, 3, 4] + */ + function toArray(collection) { + if (collection && typeof collection.length == 'number') { + return slice(collection); + } + return values(collection); + } + + /** + * Performs a deep comparison of each element in a `collection` to the given + * `properties` object, returning an array of all elements that have equivalent + * property values. + * + * @static + * @memberOf _ + * @type Function + * @category Collections + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Object} props The object of property values to filter by. + * @returns {Array} Returns a new array of elements that have the given properties. + * @example + * + * var characters = [ + * { 'name': 'barney', 'age': 36, 'pets': ['hoppy'] }, + * { 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] } + * ]; + * + * _.where(characters, { 'age': 36 }); + * // => [{ 'name': 'barney', 'age': 36, 'pets': ['hoppy'] }] + * + * _.where(characters, { 'pets': ['dino'] }); + * // => [{ 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] }] + */ + var where = filter; + + /*--------------------------------------------------------------------------*/ + + /** + * Creates an array with all falsey values removed. The values `false`, `null`, + * `0`, `""`, `undefined`, and `NaN` are all falsey. + * + * @static + * @memberOf _ + * @category Arrays + * @param {Array} array The array to compact. + * @returns {Array} Returns a new array of filtered values. + * @example + * + * _.compact([0, 1, false, 2, '', 3]); + * // => [1, 2, 3] + */ + function compact(array) { + var index = -1, + length = array ? array.length : 0, + result = []; + + while (++index < length) { + var value = array[index]; + if (value) { + result.push(value); + } + } + return result; + } + + /** + * Creates an array excluding all values of the provided arrays using strict + * equality for comparisons, i.e. `===`. + * + * @static + * @memberOf _ + * @category Arrays + * @param {Array} array The array to process. + * @param {...Array} [values] The arrays of values to exclude. + * @returns {Array} Returns a new array of filtered values. + * @example + * + * _.difference([1, 2, 3, 4, 5], [5, 2, 10]); + * // => [1, 3, 4] + */ + function difference(array) { + return baseDifference(array, baseFlatten(arguments, true, true, 1)); + } + + /** + * This method is like `_.find` except that it returns the index of the first + * element that passes the callback check, instead of the element itself. + * + * If a property name is provided for `callback` the created "_.pluck" style + * callback will return the property value of the given element. + * + * If an object is provided for `callback` the created "_.where" style callback + * will return `true` for elements that have the properties of the given object, + * else `false`. + * + * @static + * @memberOf _ + * @category Arrays + * @param {Array} array The array to search. + * @param {Function|Object|string} [callback=identity] The function called + * per iteration. If a property name or object is provided it will be used + * to create a "_.pluck" or "_.where" style callback, respectively. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {number} Returns the index of the found element, else `-1`. + * @example + * + * var characters = [ + * { 'name': 'barney', 'age': 36, 'blocked': false }, + * { 'name': 'fred', 'age': 40, 'blocked': true }, + * { 'name': 'pebbles', 'age': 1, 'blocked': false } + * ]; + * + * _.findIndex(characters, function(chr) { + * return chr.age < 20; + * }); + * // => 2 + * + * // using "_.where" callback shorthand + * _.findIndex(characters, { 'age': 36 }); + * // => 0 + * + * // using "_.pluck" callback shorthand + * _.findIndex(characters, 'blocked'); + * // => 1 + */ + function findIndex(array, callback, thisArg) { + var index = -1, + length = array ? array.length : 0; + + callback = lodash.createCallback(callback, thisArg, 3); + while (++index < length) { + if (callback(array[index], index, array)) { + return index; + } + } + return -1; + } + + /** + * This method is like `_.findIndex` except that it iterates over elements + * of a `collection` from right to left. + * + * If a property name is provided for `callback` the created "_.pluck" style + * callback will return the property value of the given element. + * + * If an object is provided for `callback` the created "_.where" style callback + * will return `true` for elements that have the properties of the given object, + * else `false`. + * + * @static + * @memberOf _ + * @category Arrays + * @param {Array} array The array to search. + * @param {Function|Object|string} [callback=identity] The function called + * per iteration. If a property name or object is provided it will be used + * to create a "_.pluck" or "_.where" style callback, respectively. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {number} Returns the index of the found element, else `-1`. + * @example + * + * var characters = [ + * { 'name': 'barney', 'age': 36, 'blocked': true }, + * { 'name': 'fred', 'age': 40, 'blocked': false }, + * { 'name': 'pebbles', 'age': 1, 'blocked': true } + * ]; + * + * _.findLastIndex(characters, function(chr) { + * return chr.age > 30; + * }); + * // => 1 + * + * // using "_.where" callback shorthand + * _.findLastIndex(characters, { 'age': 36 }); + * // => 0 + * + * // using "_.pluck" callback shorthand + * _.findLastIndex(characters, 'blocked'); + * // => 2 + */ + function findLastIndex(array, callback, thisArg) { + var length = array ? array.length : 0; + callback = lodash.createCallback(callback, thisArg, 3); + while (length--) { + if (callback(array[length], length, array)) { + return length; + } + } + return -1; + } + + /** + * Gets the first element or first `n` elements of an array. If a callback + * is provided elements at the beginning of the array are returned as long + * as the callback returns truey. The callback is bound to `thisArg` and + * invoked with three arguments; (value, index, array). + * + * If a property name is provided for `callback` the created "_.pluck" style + * callback will return the property value of the given element. + * + * If an object is provided for `callback` the created "_.where" style callback + * will return `true` for elements that have the properties of the given object, + * else `false`. + * + * @static + * @memberOf _ + * @alias head, take + * @category Arrays + * @param {Array} array The array to query. + * @param {Function|Object|number|string} [callback] The function called + * per element or the number of elements to return. If a property name or + * object is provided it will be used to create a "_.pluck" or "_.where" + * style callback, respectively. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {*} Returns the first element(s) of `array`. + * @example + * + * _.first([1, 2, 3]); + * // => 1 + * + * _.first([1, 2, 3], 2); + * // => [1, 2] + * + * _.first([1, 2, 3], function(num) { + * return num < 3; + * }); + * // => [1, 2] + * + * var characters = [ + * { 'name': 'barney', 'blocked': true, 'employer': 'slate' }, + * { 'name': 'fred', 'blocked': false, 'employer': 'slate' }, + * { 'name': 'pebbles', 'blocked': true, 'employer': 'na' } + * ]; + * + * // using "_.pluck" callback shorthand + * _.first(characters, 'blocked'); + * // => [{ 'name': 'barney', 'blocked': true, 'employer': 'slate' }] + * + * // using "_.where" callback shorthand + * _.pluck(_.first(characters, { 'employer': 'slate' }), 'name'); + * // => ['barney', 'fred'] + */ + function first(array, callback, thisArg) { + var n = 0, + length = array ? array.length : 0; + + if (typeof callback != 'number' && callback != null) { + var index = -1; + callback = lodash.createCallback(callback, thisArg, 3); + while (++index < length && callback(array[index], index, array)) { + n++; + } + } else { + n = callback; + if (n == null || thisArg) { + return array ? array[0] : undefined; + } + } + return slice(array, 0, nativeMin(nativeMax(0, n), length)); + } + + /** + * Flattens a nested array (the nesting can be to any depth). If `isShallow` + * is truey, the array will only be flattened a single level. If a callback + * is provided each element of the array is passed through the callback before + * flattening. The callback is bound to `thisArg` and invoked with three + * arguments; (value, index, array). + * + * If a property name is provided for `callback` the created "_.pluck" style + * callback will return the property value of the given element. + * + * If an object is provided for `callback` the created "_.where" style callback + * will return `true` for elements that have the properties of the given object, + * else `false`. + * + * @static + * @memberOf _ + * @category Arrays + * @param {Array} array The array to flatten. + * @param {boolean} [isShallow=false] A flag to restrict flattening to a single level. + * @param {Function|Object|string} [callback=identity] The function called + * per iteration. If a property name or object is provided it will be used + * to create a "_.pluck" or "_.where" style callback, respectively. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {Array} Returns a new flattened array. + * @example + * + * _.flatten([1, [2], [3, [[4]]]]); + * // => [1, 2, 3, 4]; + * + * _.flatten([1, [2], [3, [[4]]]], true); + * // => [1, 2, 3, [[4]]]; + * + * var characters = [ + * { 'name': 'barney', 'age': 30, 'pets': ['hoppy'] }, + * { 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] } + * ]; + * + * // using "_.pluck" callback shorthand + * _.flatten(characters, 'pets'); + * // => ['hoppy', 'baby puss', 'dino'] + */ + function flatten(array, isShallow, callback, thisArg) { + // juggle arguments + if (typeof isShallow != 'boolean' && isShallow != null) { + thisArg = callback; + callback = (typeof isShallow != 'function' && thisArg && thisArg[isShallow] === array) ? null : isShallow; + isShallow = false; + } + if (callback != null) { + array = map(array, callback, thisArg); + } + return baseFlatten(array, isShallow); + } + + /** + * Gets the index at which the first occurrence of `value` is found using + * strict equality for comparisons, i.e. `===`. If the array is already sorted + * providing `true` for `fromIndex` will run a faster binary search. + * + * @static + * @memberOf _ + * @category Arrays + * @param {Array} array The array to search. + * @param {*} value The value to search for. + * @param {boolean|number} [fromIndex=0] The index to search from or `true` + * to perform a binary search on a sorted array. + * @returns {number} Returns the index of the matched value or `-1`. + * @example + * + * _.indexOf([1, 2, 3, 1, 2, 3], 2); + * // => 1 + * + * _.indexOf([1, 2, 3, 1, 2, 3], 2, 3); + * // => 4 + * + * _.indexOf([1, 1, 2, 2, 3, 3], 2, true); + * // => 2 + */ + function indexOf(array, value, fromIndex) { + if (typeof fromIndex == 'number') { + var length = array ? array.length : 0; + fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex || 0); + } else if (fromIndex) { + var index = sortedIndex(array, value); + return array[index] === value ? index : -1; + } + return baseIndexOf(array, value, fromIndex); + } + + /** + * Gets all but the last element or last `n` elements of an array. If a + * callback is provided elements at the end of the array are excluded from + * the result as long as the callback returns truey. The callback is bound + * to `thisArg` and invoked with three arguments; (value, index, array). + * + * If a property name is provided for `callback` the created "_.pluck" style + * callback will return the property value of the given element. + * + * If an object is provided for `callback` the created "_.where" style callback + * will return `true` for elements that have the properties of the given object, + * else `false`. + * + * @static + * @memberOf _ + * @category Arrays + * @param {Array} array The array to query. + * @param {Function|Object|number|string} [callback=1] The function called + * per element or the number of elements to exclude. If a property name or + * object is provided it will be used to create a "_.pluck" or "_.where" + * style callback, respectively. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {Array} Returns a slice of `array`. + * @example + * + * _.initial([1, 2, 3]); + * // => [1, 2] + * + * _.initial([1, 2, 3], 2); + * // => [1] + * + * _.initial([1, 2, 3], function(num) { + * return num > 1; + * }); + * // => [1] + * + * var characters = [ + * { 'name': 'barney', 'blocked': false, 'employer': 'slate' }, + * { 'name': 'fred', 'blocked': true, 'employer': 'slate' }, + * { 'name': 'pebbles', 'blocked': true, 'employer': 'na' } + * ]; + * + * // using "_.pluck" callback shorthand + * _.initial(characters, 'blocked'); + * // => [{ 'name': 'barney', 'blocked': false, 'employer': 'slate' }] + * + * // using "_.where" callback shorthand + * _.pluck(_.initial(characters, { 'employer': 'na' }), 'name'); + * // => ['barney', 'fred'] + */ + function initial(array, callback, thisArg) { + var n = 0, + length = array ? array.length : 0; + + if (typeof callback != 'number' && callback != null) { + var index = length; + callback = lodash.createCallback(callback, thisArg, 3); + while (index-- && callback(array[index], index, array)) { + n++; + } + } else { + n = (callback == null || thisArg) ? 1 : callback || n; + } + return slice(array, 0, nativeMin(nativeMax(0, length - n), length)); + } + + /** + * Creates an array of unique values present in all provided arrays using + * strict equality for comparisons, i.e. `===`. + * + * @static + * @memberOf _ + * @category Arrays + * @param {...Array} [array] The arrays to inspect. + * @returns {Array} Returns an array of shared values. + * @example + * + * _.intersection([1, 2, 3], [5, 2, 1, 4], [2, 1]); + * // => [1, 2] + */ + function intersection() { + var args = [], + argsIndex = -1, + argsLength = arguments.length, + caches = getArray(), + indexOf = getIndexOf(), + trustIndexOf = indexOf === baseIndexOf, + seen = getArray(); + + while (++argsIndex < argsLength) { + var value = arguments[argsIndex]; + if (isArray(value) || isArguments(value)) { + args.push(value); + caches.push(trustIndexOf && value.length >= largeArraySize && + createCache(argsIndex ? args[argsIndex] : seen)); + } + } + var array = args[0], + index = -1, + length = array ? array.length : 0, + result = []; + + outer: + while (++index < length) { + var cache = caches[0]; + value = array[index]; + + if ((cache ? cacheIndexOf(cache, value) : indexOf(seen, value)) < 0) { + argsIndex = argsLength; + (cache || seen).push(value); + while (--argsIndex) { + cache = caches[argsIndex]; + if ((cache ? cacheIndexOf(cache, value) : indexOf(args[argsIndex], value)) < 0) { + continue outer; + } + } + result.push(value); + } + } + while (argsLength--) { + cache = caches[argsLength]; + if (cache) { + releaseObject(cache); + } + } + releaseArray(caches); + releaseArray(seen); + return result; + } + + /** + * Gets the last element or last `n` elements of an array. If a callback is + * provided elements at the end of the array are returned as long as the + * callback returns truey. The callback is bound to `thisArg` and invoked + * with three arguments; (value, index, array). + * + * If a property name is provided for `callback` the created "_.pluck" style + * callback will return the property value of the given element. + * + * If an object is provided for `callback` the created "_.where" style callback + * will return `true` for elements that have the properties of the given object, + * else `false`. + * + * @static + * @memberOf _ + * @category Arrays + * @param {Array} array The array to query. + * @param {Function|Object|number|string} [callback] The function called + * per element or the number of elements to return. If a property name or + * object is provided it will be used to create a "_.pluck" or "_.where" + * style callback, respectively. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {*} Returns the last element(s) of `array`. + * @example + * + * _.last([1, 2, 3]); + * // => 3 + * + * _.last([1, 2, 3], 2); + * // => [2, 3] + * + * _.last([1, 2, 3], function(num) { + * return num > 1; + * }); + * // => [2, 3] + * + * var characters = [ + * { 'name': 'barney', 'blocked': false, 'employer': 'slate' }, + * { 'name': 'fred', 'blocked': true, 'employer': 'slate' }, + * { 'name': 'pebbles', 'blocked': true, 'employer': 'na' } + * ]; + * + * // using "_.pluck" callback shorthand + * _.pluck(_.last(characters, 'blocked'), 'name'); + * // => ['fred', 'pebbles'] + * + * // using "_.where" callback shorthand + * _.last(characters, { 'employer': 'na' }); + * // => [{ 'name': 'pebbles', 'blocked': true, 'employer': 'na' }] + */ + function last(array, callback, thisArg) { + var n = 0, + length = array ? array.length : 0; + + if (typeof callback != 'number' && callback != null) { + var index = length; + callback = lodash.createCallback(callback, thisArg, 3); + while (index-- && callback(array[index], index, array)) { + n++; + } + } else { + n = callback; + if (n == null || thisArg) { + return array ? array[length - 1] : undefined; + } + } + return slice(array, nativeMax(0, length - n)); + } + + /** + * Gets the index at which the last occurrence of `value` is found using strict + * equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used + * as the offset from the end of the collection. + * + * If a property name is provided for `callback` the created "_.pluck" style + * callback will return the property value of the given element. + * + * If an object is provided for `callback` the created "_.where" style callback + * will return `true` for elements that have the properties of the given object, + * else `false`. + * + * @static + * @memberOf _ + * @category Arrays + * @param {Array} array The array to search. + * @param {*} value The value to search for. + * @param {number} [fromIndex=array.length-1] The index to search from. + * @returns {number} Returns the index of the matched value or `-1`. + * @example + * + * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2); + * // => 4 + * + * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2, 3); + * // => 1 + */ + function lastIndexOf(array, value, fromIndex) { + var index = array ? array.length : 0; + if (typeof fromIndex == 'number') { + index = (fromIndex < 0 ? nativeMax(0, index + fromIndex) : nativeMin(fromIndex, index - 1)) + 1; + } + while (index--) { + if (array[index] === value) { + return index; + } + } + return -1; + } + + /** + * Removes all provided values from the given array using strict equality for + * comparisons, i.e. `===`. + * + * @static + * @memberOf _ + * @category Arrays + * @param {Array} array The array to modify. + * @param {...*} [value] The values to remove. + * @returns {Array} Returns `array`. + * @example + * + * var array = [1, 2, 3, 1, 2, 3]; + * _.pull(array, 2, 3); + * console.log(array); + * // => [1, 1] + */ + function pull(array) { + var args = arguments, + argsIndex = 0, + argsLength = args.length, + length = array ? array.length : 0; + + while (++argsIndex < argsLength) { + var index = -1, + value = args[argsIndex]; + while (++index < length) { + if (array[index] === value) { + splice.call(array, index--, 1); + length--; + } + } + } + return array; + } + + /** + * Creates an array of numbers (positive and/or negative) progressing from + * `start` up to but not including `end`. If `start` is less than `stop` a + * zero-length range is created unless a negative `step` is specified. + * + * @static + * @memberOf _ + * @category Arrays + * @param {number} [start=0] The start of the range. + * @param {number} end The end of the range. + * @param {number} [step=1] The value to increment or decrement by. + * @returns {Array} Returns a new range array. + * @example + * + * _.range(4); + * // => [0, 1, 2, 3] + * + * _.range(1, 5); + * // => [1, 2, 3, 4] + * + * _.range(0, 20, 5); + * // => [0, 5, 10, 15] + * + * _.range(0, -4, -1); + * // => [0, -1, -2, -3] + * + * _.range(1, 4, 0); + * // => [1, 1, 1] + * + * _.range(0); + * // => [] + */ + function range(start, end, step) { + start = +start || 0; + step = typeof step == 'number' ? step : (+step || 1); + + if (end == null) { + end = start; + start = 0; + } + // use `Array(length)` so engines like Chakra and V8 avoid slower modes + // http://youtu.be/XAqIpGU8ZZk#t=17m25s + var index = -1, + length = nativeMax(0, ceil((end - start) / (step || 1))), + result = Array(length); + + while (++index < length) { + result[index] = start; + start += step; + } + return result; + } + + /** + * Removes all elements from an array that the callback returns truey for + * and returns an array of removed elements. The callback is bound to `thisArg` + * and invoked with three arguments; (value, index, array). + * + * If a property name is provided for `callback` the created "_.pluck" style + * callback will return the property value of the given element. + * + * If an object is provided for `callback` the created "_.where" style callback + * will return `true` for elements that have the properties of the given object, + * else `false`. + * + * @static + * @memberOf _ + * @category Arrays + * @param {Array} array The array to modify. + * @param {Function|Object|string} [callback=identity] The function called + * per iteration. If a property name or object is provided it will be used + * to create a "_.pluck" or "_.where" style callback, respectively. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {Array} Returns a new array of removed elements. + * @example + * + * var array = [1, 2, 3, 4, 5, 6]; + * var evens = _.remove(array, function(num) { return num % 2 == 0; }); + * + * console.log(array); + * // => [1, 3, 5] + * + * console.log(evens); + * // => [2, 4, 6] + */ + function remove(array, callback, thisArg) { + var index = -1, + length = array ? array.length : 0, + result = []; + + callback = lodash.createCallback(callback, thisArg, 3); + while (++index < length) { + var value = array[index]; + if (callback(value, index, array)) { + result.push(value); + splice.call(array, index--, 1); + length--; + } + } + return result; + } + + /** + * The opposite of `_.initial` this method gets all but the first element or + * first `n` elements of an array. If a callback function is provided elements + * at the beginning of the array are excluded from the result as long as the + * callback returns truey. The callback is bound to `thisArg` and invoked + * with three arguments; (value, index, array). + * + * If a property name is provided for `callback` the created "_.pluck" style + * callback will return the property value of the given element. + * + * If an object is provided for `callback` the created "_.where" style callback + * will return `true` for elements that have the properties of the given object, + * else `false`. + * + * @static + * @memberOf _ + * @alias drop, tail + * @category Arrays + * @param {Array} array The array to query. + * @param {Function|Object|number|string} [callback=1] The function called + * per element or the number of elements to exclude. If a property name or + * object is provided it will be used to create a "_.pluck" or "_.where" + * style callback, respectively. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {Array} Returns a slice of `array`. + * @example + * + * _.rest([1, 2, 3]); + * // => [2, 3] + * + * _.rest([1, 2, 3], 2); + * // => [3] + * + * _.rest([1, 2, 3], function(num) { + * return num < 3; + * }); + * // => [3] + * + * var characters = [ + * { 'name': 'barney', 'blocked': true, 'employer': 'slate' }, + * { 'name': 'fred', 'blocked': false, 'employer': 'slate' }, + * { 'name': 'pebbles', 'blocked': true, 'employer': 'na' } + * ]; + * + * // using "_.pluck" callback shorthand + * _.pluck(_.rest(characters, 'blocked'), 'name'); + * // => ['fred', 'pebbles'] + * + * // using "_.where" callback shorthand + * _.rest(characters, { 'employer': 'slate' }); + * // => [{ 'name': 'pebbles', 'blocked': true, 'employer': 'na' }] + */ + function rest(array, callback, thisArg) { + if (typeof callback != 'number' && callback != null) { + var n = 0, + index = -1, + length = array ? array.length : 0; + + callback = lodash.createCallback(callback, thisArg, 3); + while (++index < length && callback(array[index], index, array)) { + n++; + } + } else { + n = (callback == null || thisArg) ? 1 : nativeMax(0, callback); + } + return slice(array, n); + } + + /** + * Uses a binary search to determine the smallest index at which a value + * should be inserted into a given sorted array in order to maintain the sort + * order of the array. If a callback is provided it will be executed for + * `value` and each element of `array` to compute their sort ranking. The + * callback is bound to `thisArg` and invoked with one argument; (value). + * + * If a property name is provided for `callback` the created "_.pluck" style + * callback will return the property value of the given element. + * + * If an object is provided for `callback` the created "_.where" style callback + * will return `true` for elements that have the properties of the given object, + * else `false`. + * + * @static + * @memberOf _ + * @category Arrays + * @param {Array} array The array to inspect. + * @param {*} value The value to evaluate. + * @param {Function|Object|string} [callback=identity] The function called + * per iteration. If a property name or object is provided it will be used + * to create a "_.pluck" or "_.where" style callback, respectively. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + * @example + * + * _.sortedIndex([20, 30, 50], 40); + * // => 2 + * + * // using "_.pluck" callback shorthand + * _.sortedIndex([{ 'x': 20 }, { 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x'); + * // => 2 + * + * var dict = { + * 'wordToNumber': { 'twenty': 20, 'thirty': 30, 'fourty': 40, 'fifty': 50 } + * }; + * + * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) { + * return dict.wordToNumber[word]; + * }); + * // => 2 + * + * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) { + * return this.wordToNumber[word]; + * }, dict); + * // => 2 + */ + function sortedIndex(array, value, callback, thisArg) { + var low = 0, + high = array ? array.length : low; + + // explicitly reference `identity` for better inlining in Firefox + callback = callback ? lodash.createCallback(callback, thisArg, 1) : identity; + value = callback(value); + + while (low < high) { + var mid = (low + high) >>> 1; + (callback(array[mid]) < value) + ? low = mid + 1 + : high = mid; + } + return low; + } + + /** + * Creates an array of unique values, in order, of the provided arrays using + * strict equality for comparisons, i.e. `===`. + * + * @static + * @memberOf _ + * @category Arrays + * @param {...Array} [array] The arrays to inspect. + * @returns {Array} Returns an array of combined values. + * @example + * + * _.union([1, 2, 3], [5, 2, 1, 4], [2, 1]); + * // => [1, 2, 3, 5, 4] + */ + function union() { + return baseUniq(baseFlatten(arguments, true, true)); + } + + /** + * Creates a duplicate-value-free version of an array using strict equality + * for comparisons, i.e. `===`. If the array is sorted, providing + * `true` for `isSorted` will use a faster algorithm. If a callback is provided + * each element of `array` is passed through the callback before uniqueness + * is computed. The callback is bound to `thisArg` and invoked with three + * arguments; (value, index, array). + * + * If a property name is provided for `callback` the created "_.pluck" style + * callback will return the property value of the given element. + * + * If an object is provided for `callback` the created "_.where" style callback + * will return `true` for elements that have the properties of the given object, + * else `false`. + * + * @static + * @memberOf _ + * @alias unique + * @category Arrays + * @param {Array} array The array to process. + * @param {boolean} [isSorted=false] A flag to indicate that `array` is sorted. + * @param {Function|Object|string} [callback=identity] The function called + * per iteration. If a property name or object is provided it will be used + * to create a "_.pluck" or "_.where" style callback, respectively. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {Array} Returns a duplicate-value-free array. + * @example + * + * _.uniq([1, 2, 1, 3, 1]); + * // => [1, 2, 3] + * + * _.uniq([1, 1, 2, 2, 3], true); + * // => [1, 2, 3] + * + * _.uniq(['A', 'b', 'C', 'a', 'B', 'c'], function(letter) { return letter.toLowerCase(); }); + * // => ['A', 'b', 'C'] + * + * _.uniq([1, 2.5, 3, 1.5, 2, 3.5], function(num) { return this.floor(num); }, Math); + * // => [1, 2.5, 3] + * + * // using "_.pluck" callback shorthand + * _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x'); + * // => [{ 'x': 1 }, { 'x': 2 }] + */ + function uniq(array, isSorted, callback, thisArg) { + // juggle arguments + if (typeof isSorted != 'boolean' && isSorted != null) { + thisArg = callback; + callback = (typeof isSorted != 'function' && thisArg && thisArg[isSorted] === array) ? null : isSorted; + isSorted = false; + } + if (callback != null) { + callback = lodash.createCallback(callback, thisArg, 3); + } + return baseUniq(array, isSorted, callback); + } + + /** + * Creates an array excluding all provided values using strict equality for + * comparisons, i.e. `===`. + * + * @static + * @memberOf _ + * @category Arrays + * @param {Array} array The array to filter. + * @param {...*} [value] The values to exclude. + * @returns {Array} Returns a new array of filtered values. + * @example + * + * _.without([1, 2, 1, 0, 3, 1, 4], 0, 1); + * // => [2, 3, 4] + */ + function without(array) { + return baseDifference(array, slice(arguments, 1)); + } + + /** + * Creates an array that is the symmetric difference of the provided arrays. + * See http://en.wikipedia.org/wiki/Symmetric_difference. + * + * @static + * @memberOf _ + * @category Arrays + * @param {...Array} [array] The arrays to inspect. + * @returns {Array} Returns an array of values. + * @example + * + * _.xor([1, 2, 3], [5, 2, 1, 4]); + * // => [3, 5, 4] + * + * _.xor([1, 2, 5], [2, 3, 5], [3, 4, 5]); + * // => [1, 4, 5] + */ + function xor() { + var index = -1, + length = arguments.length; + + while (++index < length) { + var array = arguments[index]; + if (isArray(array) || isArguments(array)) { + var result = result + ? baseUniq(baseDifference(result, array).concat(baseDifference(array, result))) + : array; + } + } + return result || []; + } + + /** + * Creates an array of grouped elements, the first of which contains the first + * elements of the given arrays, the second of which contains the second + * elements of the given arrays, and so on. + * + * @static + * @memberOf _ + * @alias unzip + * @category Arrays + * @param {...Array} [array] Arrays to process. + * @returns {Array} Returns a new array of grouped elements. + * @example + * + * _.zip(['fred', 'barney'], [30, 40], [true, false]); + * // => [['fred', 30, true], ['barney', 40, false]] + */ + function zip() { + var array = arguments.length > 1 ? arguments : arguments[0], + index = -1, + length = array ? max(pluck(array, 'length')) : 0, + result = Array(length < 0 ? 0 : length); + + while (++index < length) { + result[index] = pluck(array, index); + } + return result; + } + + /** + * Creates an object composed from arrays of `keys` and `values`. Provide + * either a single two dimensional array, i.e. `[[key1, value1], [key2, value2]]` + * or two arrays, one of `keys` and one of corresponding `values`. + * + * @static + * @memberOf _ + * @alias object + * @category Arrays + * @param {Array} keys The array of keys. + * @param {Array} [values=[]] The array of values. + * @returns {Object} Returns an object composed of the given keys and + * corresponding values. + * @example + * + * _.zipObject(['fred', 'barney'], [30, 40]); + * // => { 'fred': 30, 'barney': 40 } + */ + function zipObject(keys, values) { + var index = -1, + length = keys ? keys.length : 0, + result = {}; + + if (!values && length && !isArray(keys[0])) { + values = []; + } + while (++index < length) { + var key = keys[index]; + if (values) { + result[key] = values[index]; + } else if (key) { + result[key[0]] = key[1]; + } + } + return result; + } + + /*--------------------------------------------------------------------------*/ + + /** + * Creates a function that executes `func`, with the `this` binding and + * arguments of the created function, only after being called `n` times. + * + * @static + * @memberOf _ + * @category Functions + * @param {number} n The number of times the function must be called before + * `func` is executed. + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new restricted function. + * @example + * + * var saves = ['profile', 'settings']; + * + * var done = _.after(saves.length, function() { + * console.log('Done saving!'); + * }); + * + * _.forEach(saves, function(type) { + * asyncSave({ 'type': type, 'complete': done }); + * }); + * // => logs 'Done saving!', after all saves have completed + */ + function after(n, func) { + if (!isFunction(func)) { + throw new TypeError; + } + return function() { + if (--n < 1) { + return func.apply(this, arguments); + } + }; + } + + /** + * Creates a function that, when called, invokes `func` with the `this` + * binding of `thisArg` and prepends any additional `bind` arguments to those + * provided to the bound function. + * + * @static + * @memberOf _ + * @category Functions + * @param {Function} func The function to bind. + * @param {*} [thisArg] The `this` binding of `func`. + * @param {...*} [arg] Arguments to be partially applied. + * @returns {Function} Returns the new bound function. + * @example + * + * var func = function(greeting) { + * return greeting + ' ' + this.name; + * }; + * + * func = _.bind(func, { 'name': 'fred' }, 'hi'); + * func(); + * // => 'hi fred' + */ + function bind(func, thisArg) { + return arguments.length > 2 + ? createWrapper(func, 17, slice(arguments, 2), null, thisArg) + : createWrapper(func, 1, null, null, thisArg); + } + + /** + * Binds methods of an object to the object itself, overwriting the existing + * method. Method names may be specified as individual arguments or as arrays + * of method names. If no method names are provided all the function properties + * of `object` will be bound. + * + * @static + * @memberOf _ + * @category Functions + * @param {Object} object The object to bind and assign the bound methods to. + * @param {...string} [methodName] The object method names to + * bind, specified as individual method names or arrays of method names. + * @returns {Object} Returns `object`. + * @example + * + * var view = { + * 'label': 'docs', + * 'onClick': function() { console.log('clicked ' + this.label); } + * }; + * + * _.bindAll(view); + * jQuery('#docs').on('click', view.onClick); + * // => logs 'clicked docs', when the button is clicked + */ + function bindAll(object) { + var funcs = arguments.length > 1 ? baseFlatten(arguments, true, false, 1) : functions(object), + index = -1, + length = funcs.length; + + while (++index < length) { + var key = funcs[index]; + object[key] = createWrapper(object[key], 1, null, null, object); + } + return object; + } + + /** + * Creates a function that, when called, invokes the method at `object[key]` + * and prepends any additional `bindKey` arguments to those provided to the bound + * function. This method differs from `_.bind` by allowing bound functions to + * reference methods that will be redefined or don't yet exist. + * See http://michaux.ca/articles/lazy-function-definition-pattern. + * + * @static + * @memberOf _ + * @category Functions + * @param {Object} object The object the method belongs to. + * @param {string} key The key of the method. + * @param {...*} [arg] Arguments to be partially applied. + * @returns {Function} Returns the new bound function. + * @example + * + * var object = { + * 'name': 'fred', + * 'greet': function(greeting) { + * return greeting + ' ' + this.name; + * } + * }; + * + * var func = _.bindKey(object, 'greet', 'hi'); + * func(); + * // => 'hi fred' + * + * object.greet = function(greeting) { + * return greeting + 'ya ' + this.name + '!'; + * }; + * + * func(); + * // => 'hiya fred!' + */ + function bindKey(object, key) { + return arguments.length > 2 + ? createWrapper(key, 19, slice(arguments, 2), null, object) + : createWrapper(key, 3, null, null, object); + } + + /** + * Creates a function that is the composition of the provided functions, + * where each function consumes the return value of the function that follows. + * For example, composing the functions `f()`, `g()`, and `h()` produces `f(g(h()))`. + * Each function is executed with the `this` binding of the composed function. + * + * @static + * @memberOf _ + * @category Functions + * @param {...Function} [func] Functions to compose. + * @returns {Function} Returns the new composed function. + * @example + * + * var realNameMap = { + * 'pebbles': 'penelope' + * }; + * + * var format = function(name) { + * name = realNameMap[name.toLowerCase()] || name; + * return name.charAt(0).toUpperCase() + name.slice(1).toLowerCase(); + * }; + * + * var greet = function(formatted) { + * return 'Hiya ' + formatted + '!'; + * }; + * + * var welcome = _.compose(greet, format); + * welcome('pebbles'); + * // => 'Hiya Penelope!' + */ + function compose() { + var funcs = arguments, + length = funcs.length; + + while (length--) { + if (!isFunction(funcs[length])) { + throw new TypeError; + } + } + return function() { + var args = arguments, + length = funcs.length; + + while (length--) { + args = [funcs[length].apply(this, args)]; + } + return args[0]; + }; + } + + /** + * Creates a function which accepts one or more arguments of `func` that when + * invoked either executes `func` returning its result, if all `func` arguments + * have been provided, or returns a function that accepts one or more of the + * remaining `func` arguments, and so on. The arity of `func` can be specified + * if `func.length` is not sufficient. + * + * @static + * @memberOf _ + * @category Functions + * @param {Function} func The function to curry. + * @param {number} [arity=func.length] The arity of `func`. + * @returns {Function} Returns the new curried function. + * @example + * + * var curried = _.curry(function(a, b, c) { + * console.log(a + b + c); + * }); + * + * curried(1)(2)(3); + * // => 6 + * + * curried(1, 2)(3); + * // => 6 + * + * curried(1, 2, 3); + * // => 6 + */ + function curry(func, arity) { + arity = typeof arity == 'number' ? arity : (+arity || func.length); + return createWrapper(func, 4, null, null, null, arity); + } + + /** + * Creates a function that will delay the execution of `func` until after + * `wait` milliseconds have elapsed since the last time it was invoked. + * Provide an options object to indicate that `func` should be invoked on + * the leading and/or trailing edge of the `wait` timeout. Subsequent calls + * to the debounced function will return the result of the last `func` call. + * + * Note: If `leading` and `trailing` options are `true` `func` will be called + * on the trailing edge of the timeout only if the the debounced function is + * invoked more than once during the `wait` timeout. + * + * @static + * @memberOf _ + * @category Functions + * @param {Function} func The function to debounce. + * @param {number} wait The number of milliseconds to delay. + * @param {Object} [options] The options object. + * @param {boolean} [options.leading=false] Specify execution on the leading edge of the timeout. + * @param {number} [options.maxWait] The maximum time `func` is allowed to be delayed before it's called. + * @param {boolean} [options.trailing=true] Specify execution on the trailing edge of the timeout. + * @returns {Function} Returns the new debounced function. + * @example + * + * // avoid costly calculations while the window size is in flux + * var lazyLayout = _.debounce(calculateLayout, 150); + * jQuery(window).on('resize', lazyLayout); + * + * // execute `sendMail` when the click event is fired, debouncing subsequent calls + * jQuery('#postbox').on('click', _.debounce(sendMail, 300, { + * 'leading': true, + * 'trailing': false + * }); + * + * // ensure `batchLog` is executed once after 1 second of debounced calls + * var source = new EventSource('/stream'); + * source.addEventListener('message', _.debounce(batchLog, 250, { + * 'maxWait': 1000 + * }, false); + */ + function debounce(func, wait, options) { + var args, + maxTimeoutId, + result, + stamp, + thisArg, + timeoutId, + trailingCall, + lastCalled = 0, + maxWait = false, + trailing = true; + + if (!isFunction(func)) { + throw new TypeError; + } + wait = nativeMax(0, wait) || 0; + if (options === true) { + var leading = true; + trailing = false; + } else if (isObject(options)) { + leading = options.leading; + maxWait = 'maxWait' in options && (nativeMax(wait, options.maxWait) || 0); + trailing = 'trailing' in options ? options.trailing : trailing; + } + var delayed = function() { + var remaining = wait - (now() - stamp); + if (remaining <= 0) { + if (maxTimeoutId) { + clearTimeout(maxTimeoutId); + } + var isCalled = trailingCall; + maxTimeoutId = timeoutId = trailingCall = undefined; + if (isCalled) { + lastCalled = now(); + result = func.apply(thisArg, args); + if (!timeoutId && !maxTimeoutId) { + args = thisArg = null; + } + } + } else { + timeoutId = setTimeout(delayed, remaining); + } + }; + + var maxDelayed = function() { + if (timeoutId) { + clearTimeout(timeoutId); + } + maxTimeoutId = timeoutId = trailingCall = undefined; + if (trailing || (maxWait !== wait)) { + lastCalled = now(); + result = func.apply(thisArg, args); + if (!timeoutId && !maxTimeoutId) { + args = thisArg = null; + } + } + }; + + return function() { + args = arguments; + stamp = now(); + thisArg = this; + trailingCall = trailing && (timeoutId || !leading); + + if (maxWait === false) { + var leadingCall = leading && !timeoutId; + } else { + if (!maxTimeoutId && !leading) { + lastCalled = stamp; + } + var remaining = maxWait - (stamp - lastCalled), + isCalled = remaining <= 0; + + if (isCalled) { + if (maxTimeoutId) { + maxTimeoutId = clearTimeout(maxTimeoutId); + } + lastCalled = stamp; + result = func.apply(thisArg, args); + } + else if (!maxTimeoutId) { + maxTimeoutId = setTimeout(maxDelayed, remaining); + } + } + if (isCalled && timeoutId) { + timeoutId = clearTimeout(timeoutId); + } + else if (!timeoutId && wait !== maxWait) { + timeoutId = setTimeout(delayed, wait); + } + if (leadingCall) { + isCalled = true; + result = func.apply(thisArg, args); + } + if (isCalled && !timeoutId && !maxTimeoutId) { + args = thisArg = null; + } + return result; + }; + } + + /** + * Defers executing the `func` function until the current call stack has cleared. + * Additional arguments will be provided to `func` when it is invoked. + * + * @static + * @memberOf _ + * @category Functions + * @param {Function} func The function to defer. + * @param {...*} [arg] Arguments to invoke the function with. + * @returns {number} Returns the timer id. + * @example + * + * _.defer(function(text) { console.log(text); }, 'deferred'); + * // logs 'deferred' after one or more milliseconds + */ + function defer(func) { + if (!isFunction(func)) { + throw new TypeError; + } + var args = slice(arguments, 1); + return setTimeout(function() { func.apply(undefined, args); }, 1); + } + + /** + * Executes the `func` function after `wait` milliseconds. Additional arguments + * will be provided to `func` when it is invoked. + * + * @static + * @memberOf _ + * @category Functions + * @param {Function} func The function to delay. + * @param {number} wait The number of milliseconds to delay execution. + * @param {...*} [arg] Arguments to invoke the function with. + * @returns {number} Returns the timer id. + * @example + * + * _.delay(function(text) { console.log(text); }, 1000, 'later'); + * // => logs 'later' after one second + */ + function delay(func, wait) { + if (!isFunction(func)) { + throw new TypeError; + } + var args = slice(arguments, 2); + return setTimeout(function() { func.apply(undefined, args); }, wait); + } + + /** + * Creates a function that memoizes the result of `func`. If `resolver` is + * provided it will be used to determine the cache key for storing the result + * based on the arguments provided to the memoized function. By default, the + * first argument provided to the memoized function is used as the cache key. + * The `func` is executed with the `this` binding of the memoized function. + * The result cache is exposed as the `cache` property on the memoized function. + * + * @static + * @memberOf _ + * @category Functions + * @param {Function} func The function to have its output memoized. + * @param {Function} [resolver] A function used to resolve the cache key. + * @returns {Function} Returns the new memoizing function. + * @example + * + * var fibonacci = _.memoize(function(n) { + * return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2); + * }); + * + * fibonacci(9) + * // => 34 + * + * var data = { + * 'fred': { 'name': 'fred', 'age': 40 }, + * 'pebbles': { 'name': 'pebbles', 'age': 1 } + * }; + * + * // modifying the result cache + * var get = _.memoize(function(name) { return data[name]; }, _.identity); + * get('pebbles'); + * // => { 'name': 'pebbles', 'age': 1 } + * + * get.cache.pebbles.name = 'penelope'; + * get('pebbles'); + * // => { 'name': 'penelope', 'age': 1 } + */ + function memoize(func, resolver) { + if (!isFunction(func)) { + throw new TypeError; + } + var memoized = function() { + var cache = memoized.cache, + key = resolver ? resolver.apply(this, arguments) : keyPrefix + arguments[0]; + + return hasOwnProperty.call(cache, key) + ? cache[key] + : (cache[key] = func.apply(this, arguments)); + } + memoized.cache = {}; + return memoized; + } + + /** + * Creates a function that is restricted to execute `func` once. Repeat calls to + * the function will return the value of the first call. The `func` is executed + * with the `this` binding of the created function. + * + * @static + * @memberOf _ + * @category Functions + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new restricted function. + * @example + * + * var initialize = _.once(createApplication); + * initialize(); + * initialize(); + * // `initialize` executes `createApplication` once + */ + function once(func) { + var ran, + result; + + if (!isFunction(func)) { + throw new TypeError; + } + return function() { + if (ran) { + return result; + } + ran = true; + result = func.apply(this, arguments); + + // clear the `func` variable so the function may be garbage collected + func = null; + return result; + }; + } + + /** + * Creates a function that, when called, invokes `func` with any additional + * `partial` arguments prepended to those provided to the new function. This + * method is similar to `_.bind` except it does **not** alter the `this` binding. + * + * @static + * @memberOf _ + * @category Functions + * @param {Function} func The function to partially apply arguments to. + * @param {...*} [arg] Arguments to be partially applied. + * @returns {Function} Returns the new partially applied function. + * @example + * + * var greet = function(greeting, name) { return greeting + ' ' + name; }; + * var hi = _.partial(greet, 'hi'); + * hi('fred'); + * // => 'hi fred' + */ + function partial(func) { + return createWrapper(func, 16, slice(arguments, 1)); + } + + /** + * This method is like `_.partial` except that `partial` arguments are + * appended to those provided to the new function. + * + * @static + * @memberOf _ + * @category Functions + * @param {Function} func The function to partially apply arguments to. + * @param {...*} [arg] Arguments to be partially applied. + * @returns {Function} Returns the new partially applied function. + * @example + * + * var defaultsDeep = _.partialRight(_.merge, _.defaults); + * + * var options = { + * 'variable': 'data', + * 'imports': { 'jq': $ } + * }; + * + * defaultsDeep(options, _.templateSettings); + * + * options.variable + * // => 'data' + * + * options.imports + * // => { '_': _, 'jq': $ } + */ + function partialRight(func) { + return createWrapper(func, 32, null, slice(arguments, 1)); + } + + /** + * Creates a function that, when executed, will only call the `func` function + * at most once per every `wait` milliseconds. Provide an options object to + * indicate that `func` should be invoked on the leading and/or trailing edge + * of the `wait` timeout. Subsequent calls to the throttled function will + * return the result of the last `func` call. + * + * Note: If `leading` and `trailing` options are `true` `func` will be called + * on the trailing edge of the timeout only if the the throttled function is + * invoked more than once during the `wait` timeout. + * + * @static + * @memberOf _ + * @category Functions + * @param {Function} func The function to throttle. + * @param {number} wait The number of milliseconds to throttle executions to. + * @param {Object} [options] The options object. + * @param {boolean} [options.leading=true] Specify execution on the leading edge of the timeout. + * @param {boolean} [options.trailing=true] Specify execution on the trailing edge of the timeout. + * @returns {Function} Returns the new throttled function. + * @example + * + * // avoid excessively updating the position while scrolling + * var throttled = _.throttle(updatePosition, 100); + * jQuery(window).on('scroll', throttled); + * + * // execute `renewToken` when the click event is fired, but not more than once every 5 minutes + * jQuery('.interactive').on('click', _.throttle(renewToken, 300000, { + * 'trailing': false + * })); + */ + function throttle(func, wait, options) { + var leading = true, + trailing = true; + + if (!isFunction(func)) { + throw new TypeError; + } + if (options === false) { + leading = false; + } else if (isObject(options)) { + leading = 'leading' in options ? options.leading : leading; + trailing = 'trailing' in options ? options.trailing : trailing; + } + debounceOptions.leading = leading; + debounceOptions.maxWait = wait; + debounceOptions.trailing = trailing; + + return debounce(func, wait, debounceOptions); + } + + /** + * Creates a function that provides `value` to the wrapper function as its + * first argument. Additional arguments provided to the function are appended + * to those provided to the wrapper function. The wrapper is executed with + * the `this` binding of the created function. + * + * @static + * @memberOf _ + * @category Functions + * @param {*} value The value to wrap. + * @param {Function} wrapper The wrapper function. + * @returns {Function} Returns the new function. + * @example + * + * var p = _.wrap(_.escape, function(func, text) { + * return '

' + func(text) + '

'; + * }); + * + * p('Fred, Wilma, & Pebbles'); + * // => '

Fred, Wilma, & Pebbles

' + */ + function wrap(value, wrapper) { + return createWrapper(wrapper, 16, [value]); + } + + /*--------------------------------------------------------------------------*/ + + /** + * Creates a function that returns `value`. + * + * @static + * @memberOf _ + * @category Utilities + * @param {*} value The value to return from the new function. + * @returns {Function} Returns the new function. + * @example + * + * var object = { 'name': 'fred' }; + * var getter = _.constant(object); + * getter() === object; + * // => true + */ + function constant(value) { + return function() { + return value; + }; + } + + /** + * Produces a callback bound to an optional `thisArg`. If `func` is a property + * name the created callback will return the property value for a given element. + * If `func` is an object the created callback will return `true` for elements + * that contain the equivalent object properties, otherwise it will return `false`. + * + * @static + * @memberOf _ + * @category Utilities + * @param {*} [func=identity] The value to convert to a callback. + * @param {*} [thisArg] The `this` binding of the created callback. + * @param {number} [argCount] The number of arguments the callback accepts. + * @returns {Function} Returns a callback function. + * @example + * + * var characters = [ + * { 'name': 'barney', 'age': 36 }, + * { 'name': 'fred', 'age': 40 } + * ]; + * + * // wrap to create custom callback shorthands + * _.createCallback = _.wrap(_.createCallback, function(func, callback, thisArg) { + * var match = /^(.+?)__([gl]t)(.+)$/.exec(callback); + * return !match ? func(callback, thisArg) : function(object) { + * return match[2] == 'gt' ? object[match[1]] > match[3] : object[match[1]] < match[3]; + * }; + * }); + * + * _.filter(characters, 'age__gt38'); + * // => [{ 'name': 'fred', 'age': 40 }] + */ + function createCallback(func, thisArg, argCount) { + var type = typeof func; + if (func == null || type == 'function') { + return baseCreateCallback(func, thisArg, argCount); + } + // handle "_.pluck" style callback shorthands + if (type != 'object') { + return property(func); + } + var props = keys(func), + key = props[0], + a = func[key]; + + // handle "_.where" style callback shorthands + if (props.length == 1 && a === a && !isObject(a)) { + // fast path the common case of providing an object with a single + // property containing a primitive value + return function(object) { + var b = object[key]; + return a === b && (a !== 0 || (1 / a == 1 / b)); + }; + } + return function(object) { + var length = props.length, + result = false; + + while (length--) { + if (!(result = baseIsEqual(object[props[length]], func[props[length]], null, true))) { + break; + } + } + return result; + }; + } + + /** + * Converts the characters `&`, `<`, `>`, `"`, and `'` in `string` to their + * corresponding HTML entities. + * + * @static + * @memberOf _ + * @category Utilities + * @param {string} string The string to escape. + * @returns {string} Returns the escaped string. + * @example + * + * _.escape('Fred, Wilma, & Pebbles'); + * // => 'Fred, Wilma, & Pebbles' + */ + function escape(string) { + return string == null ? '' : String(string).replace(reUnescapedHtml, escapeHtmlChar); + } + + /** + * This method returns the first argument provided to it. + * + * @static + * @memberOf _ + * @category Utilities + * @param {*} value Any value. + * @returns {*} Returns `value`. + * @example + * + * var object = { 'name': 'fred' }; + * _.identity(object) === object; + * // => true + */ + function identity(value) { + return value; + } + + /** + * Adds function properties of a source object to the destination object. + * If `object` is a function methods will be added to its prototype as well. + * + * @static + * @memberOf _ + * @category Utilities + * @param {Function|Object} [object=lodash] object The destination object. + * @param {Object} source The object of functions to add. + * @param {Object} [options] The options object. + * @param {boolean} [options.chain=true] Specify whether the functions added are chainable. + * @example + * + * function capitalize(string) { + * return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase(); + * } + * + * _.mixin({ 'capitalize': capitalize }); + * _.capitalize('fred'); + * // => 'Fred' + * + * _('fred').capitalize().value(); + * // => 'Fred' + * + * _.mixin({ 'capitalize': capitalize }, { 'chain': false }); + * _('fred').capitalize(); + * // => 'Fred' + */ + function mixin(object, source, options) { + var chain = true, + methodNames = source && functions(source); + + if (!source || (!options && !methodNames.length)) { + if (options == null) { + options = source; + } + ctor = lodashWrapper; + source = object; + object = lodash; + methodNames = functions(source); + } + if (options === false) { + chain = false; + } else if (isObject(options) && 'chain' in options) { + chain = options.chain; + } + var ctor = object, + isFunc = isFunction(ctor); + + forEach(methodNames, function(methodName) { + var func = object[methodName] = source[methodName]; + if (isFunc) { + ctor.prototype[methodName] = function() { + var chainAll = this.__chain__, + value = this.__wrapped__, + args = [value]; + + push.apply(args, arguments); + var result = func.apply(object, args); + if (chain || chainAll) { + if (value === result && isObject(result)) { + return this; + } + result = new ctor(result); + result.__chain__ = chainAll; + } + return result; + }; + } + }); + } + + /** + * Reverts the '_' variable to its previous value and returns a reference to + * the `lodash` function. + * + * @static + * @memberOf _ + * @category Utilities + * @returns {Function} Returns the `lodash` function. + * @example + * + * var lodash = _.noConflict(); + */ + function noConflict() { + context._ = oldDash; + return this; + } + + /** + * A no-operation function. + * + * @static + * @memberOf _ + * @category Utilities + * @example + * + * var object = { 'name': 'fred' }; + * _.noop(object) === undefined; + * // => true + */ + function noop() { + // no operation performed + } + + /** + * Gets the number of milliseconds that have elapsed since the Unix epoch + * (1 January 1970 00:00:00 UTC). + * + * @static + * @memberOf _ + * @category Utilities + * @example + * + * var stamp = _.now(); + * _.defer(function() { console.log(_.now() - stamp); }); + * // => logs the number of milliseconds it took for the deferred function to be called + */ + var now = isNative(now = Date.now) && now || function() { + return new Date().getTime(); + }; + + /** + * Converts the given value into an integer of the specified radix. + * If `radix` is `undefined` or `0` a `radix` of `10` is used unless the + * `value` is a hexadecimal, in which case a `radix` of `16` is used. + * + * Note: This method avoids differences in native ES3 and ES5 `parseInt` + * implementations. See http://es5.github.io/#E. + * + * @static + * @memberOf _ + * @category Utilities + * @param {string} value The value to parse. + * @param {number} [radix] The radix used to interpret the value to parse. + * @returns {number} Returns the new integer value. + * @example + * + * _.parseInt('08'); + * // => 8 + */ + var parseInt = nativeParseInt(whitespace + '08') == 8 ? nativeParseInt : function(value, radix) { + // Firefox < 21 and Opera < 15 follow the ES3 specified implementation of `parseInt` + return nativeParseInt(isString(value) ? value.replace(reLeadingSpacesAndZeros, '') : value, radix || 0); + }; + + /** + * Creates a "_.pluck" style function, which returns the `key` value of a + * given object. + * + * @static + * @memberOf _ + * @category Utilities + * @param {string} key The name of the property to retrieve. + * @returns {Function} Returns the new function. + * @example + * + * var characters = [ + * { 'name': 'fred', 'age': 40 }, + * { 'name': 'barney', 'age': 36 } + * ]; + * + * var getName = _.property('name'); + * + * _.map(characters, getName); + * // => ['barney', 'fred'] + * + * _.sortBy(characters, getName); + * // => [{ 'name': 'barney', 'age': 36 }, { 'name': 'fred', 'age': 40 }] + */ + function property(key) { + return function(object) { + return object[key]; + }; + } + + /** + * Produces a random number between `min` and `max` (inclusive). If only one + * argument is provided a number between `0` and the given number will be + * returned. If `floating` is truey or either `min` or `max` are floats a + * floating-point number will be returned instead of an integer. + * + * @static + * @memberOf _ + * @category Utilities + * @param {number} [min=0] The minimum possible value. + * @param {number} [max=1] The maximum possible value. + * @param {boolean} [floating=false] Specify returning a floating-point number. + * @returns {number} Returns a random number. + * @example + * + * _.random(0, 5); + * // => an integer between 0 and 5 + * + * _.random(5); + * // => also an integer between 0 and 5 + * + * _.random(5, true); + * // => a floating-point number between 0 and 5 + * + * _.random(1.2, 5.2); + * // => a floating-point number between 1.2 and 5.2 + */ + function random(min, max, floating) { + var noMin = min == null, + noMax = max == null; + + if (floating == null) { + if (typeof min == 'boolean' && noMax) { + floating = min; + min = 1; + } + else if (!noMax && typeof max == 'boolean') { + floating = max; + noMax = true; + } + } + if (noMin && noMax) { + max = 1; + } + min = +min || 0; + if (noMax) { + max = min; + min = 0; + } else { + max = +max || 0; + } + if (floating || min % 1 || max % 1) { + var rand = nativeRandom(); + return nativeMin(min + (rand * (max - min + parseFloat('1e-' + ((rand +'').length - 1)))), max); + } + return baseRandom(min, max); + } + + /** + * Resolves the value of property `key` on `object`. If `key` is a function + * it will be invoked with the `this` binding of `object` and its result returned, + * else the property value is returned. If `object` is falsey then `undefined` + * is returned. + * + * @static + * @memberOf _ + * @category Utilities + * @param {Object} object The object to inspect. + * @param {string} key The name of the property to resolve. + * @returns {*} Returns the resolved value. + * @example + * + * var object = { + * 'cheese': 'crumpets', + * 'stuff': function() { + * return 'nonsense'; + * } + * }; + * + * _.result(object, 'cheese'); + * // => 'crumpets' + * + * _.result(object, 'stuff'); + * // => 'nonsense' + */ + function result(object, key) { + if (object) { + var value = object[key]; + return isFunction(value) ? object[key]() : value; + } + } + + /** + * A micro-templating method that handles arbitrary delimiters, preserves + * whitespace, and correctly escapes quotes within interpolated code. + * + * Note: In the development build, `_.template` utilizes sourceURLs for easier + * debugging. See http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl + * + * For more information on precompiling templates see: + * http://lodash.com/custom-builds + * + * For more information on Chrome extension sandboxes see: + * http://developer.chrome.com/stable/extensions/sandboxingEval.html + * + * @static + * @memberOf _ + * @category Utilities + * @param {string} text The template text. + * @param {Object} data The data object used to populate the text. + * @param {Object} [options] The options object. + * @param {RegExp} [options.escape] The "escape" delimiter. + * @param {RegExp} [options.evaluate] The "evaluate" delimiter. + * @param {Object} [options.imports] An object to import into the template as local variables. + * @param {RegExp} [options.interpolate] The "interpolate" delimiter. + * @param {string} [sourceURL] The sourceURL of the template's compiled source. + * @param {string} [variable] The data object variable name. + * @returns {Function|string} Returns a compiled function when no `data` object + * is given, else it returns the interpolated text. + * @example + * + * // using the "interpolate" delimiter to create a compiled template + * var compiled = _.template('hello <%= name %>'); + * compiled({ 'name': 'fred' }); + * // => 'hello fred' + * + * // using the "escape" delimiter to escape HTML in data property values + * _.template('<%- value %>', { 'value': '