UNPKG

moac-lightwallets

Version:
1,432 lines (1,149 loc) 2.52 MB
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.lightwallet = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ module.exports = { txutils: require('./lib/txutils.js'), encryption: require('./lib/encryption.js'), signing: require('./lib/signing.js'), keystore: require('./lib/keystore.js'), upgrade: require('./lib/upgrade.js'), }; },{"./lib/encryption.js":2,"./lib/keystore.js":3,"./lib/signing.js":4,"./lib/txutils.js":5,"./lib/upgrade.js":6}],2:[function(require,module,exports){ (function (Buffer){ var util = require("ethereumjs-util"); var nacl = require('tweetnacl'); function nacl_encodeHex(msgUInt8Arr) { var msgBase64 = nacl.util.encodeBase64(msgUInt8Arr); return (new Buffer(msgBase64, 'base64')).toString('hex'); } function nacl_decodeHex(msgHex) { var msgBase64 = (new Buffer(msgHex, 'hex')).toString('base64'); return nacl.util.decodeBase64(msgBase64); } function _asymEncryptRaw (keystore, pwDerivedKey, msgUint8Array, myPubKey, theirPubKey, hdPathString) { if (hdPathString === undefined) { hdPathString = keystore.defaultHdPathString; } if (keystore.ksData[hdPathString].info.purpose !== 'asymEncrypt') { throw new Error('encryption._asymEncryptRaw: Function not defined when purpose is not "asymEncrypt"'); } if (keystore.ksData[hdPathString].encPrivKeys[myPubKey] === undefined) { throw new Error('encryption._asymEncryptRaw: public key not found in KeyStore'); } var privKey = keystore.exportPrivateKey(myPubKey, pwDerivedKey, hdPathString); var privKeyUInt8Array = nacl_decodeHex(privKey); var pubKeyUInt8Array = nacl_decodeHex(theirPubKey); var nonce = nacl.randomBytes(nacl.box.nonceLength); var encryptedMessage = nacl.box(msgUint8Array, nonce, pubKeyUInt8Array, privKeyUInt8Array); var output = { alg: 'curve25519-xsalsa20-poly1305', nonce: nacl.util.encodeBase64(nonce), ciphertext: nacl.util.encodeBase64(encryptedMessage) }; return output; } function _asymDecryptRaw (keystore, pwDerivedKey, encMsg, theirPubKey, myPubKey, hdPathString) { if (hdPathString === undefined) { hdPathString = keystore.defaultHdPathString; } if (keystore.ksData[hdPathString].info.purpose !== 'asymEncrypt') { throw new Error('encryption._asymDecryptRaw: Function not defined when purpose is not "asymEncrypt"'); } if (keystore.ksData[hdPathString].encPrivKeys[myPubKey] === undefined) { throw new Error('encryption._asymDecryptRaw: public key not found in KeyStore'); } var privKey = keystore.exportPrivateKey(myPubKey, pwDerivedKey, hdPathString); var privKeyUInt8Array = nacl_decodeHex(privKey); var pubKeyUInt8Array = nacl_decodeHex(theirPubKey); var nonce = nacl.util.decodeBase64(encMsg.nonce); var ciphertext = nacl.util.decodeBase64(encMsg.ciphertext); var cleartext = nacl.box.open(ciphertext, nonce, pubKeyUInt8Array, privKeyUInt8Array); return cleartext; } asymEncryptString = function (keystore, pwDerivedKey, msg, myPubKey, theirPubKey, hdPathString) { var messageUInt8Array = nacl.util.decodeUTF8(msg); return _asymEncryptRaw(keystore, pwDerivedKey, messageUInt8Array, myPubKey, theirPubKey, hdPathString); } asymDecryptString = function (keystore, pwDerivedKey, encMsg, theirPubKey, myPubKey, hdPathString) { var cleartext = _asymDecryptRaw(keystore, pwDerivedKey, encMsg, theirPubKey, myPubKey, hdPathString); if (cleartext === false) { return false; } else { return nacl.util.encodeUTF8(cleartext); } } multiEncryptString = function (keystore, pwDerivedKey, msg, myPubKey, theirPubKeyArray, hdPathString) { var messageUInt8Array = nacl.util.decodeUTF8(msg); var symEncryptionKey = nacl.randomBytes(nacl.secretbox.keyLength); var symNonce = nacl.randomBytes(nacl.secretbox.nonceLength); var symEncMessage = nacl.secretbox(messageUInt8Array, symNonce, symEncryptionKey); if (theirPubKeyArray.length < 1) { throw new Error('Found no pubkeys to encrypt to.'); } var encryptedSymKey = {}; encryptedSymKey = [] for (var i=0; i<theirPubKeyArray.length; i++) { var encSymKey = _asymEncryptRaw(keystore, pwDerivedKey, symEncryptionKey, myPubKey, theirPubKeyArray[i], hdPathString); delete encSymKey['alg']; encryptedSymKey.push(encSymKey); } var output = {}; output.version = 1; output.asymAlg = 'curve25519-xsalsa20-poly1305'; output.symAlg = 'xsalsa20-poly1305'; output.symNonce = nacl.util.encodeBase64(symNonce); output.symEncMessage = nacl.util.encodeBase64(symEncMessage); output.encryptedSymKey = encryptedSymKey; return output; } multiDecryptString = function (keystore, pwDerivedKey, encMsg, theirPubKey, myPubKey, hdPathString) { var symKey = false; for (var i=0; i < encMsg.encryptedSymKey.length; i++) { var result = _asymDecryptRaw(keystore, pwDerivedKey, encMsg.encryptedSymKey[i], theirPubKey, myPubKey, hdPathString) if (result !== false) { symKey = result; break; } } if (symKey === false) { return false; } else { var symNonce = nacl.util.decodeBase64(encMsg.symNonce); var symEncMessage = nacl.util.decodeBase64(encMsg.symEncMessage); var msg = nacl.secretbox.open(symEncMessage, symNonce, symKey); if (msg === false) { return false; } else { return nacl.util.encodeUTF8(msg); } } } module.exports = { asymEncryptString: asymEncryptString, asymDecryptString: asymDecryptString, multiEncryptString: multiEncryptString, multiDecryptString: multiDecryptString, }; }).call(this,require("buffer").Buffer) },{"buffer":99,"ethereumjs-util":382,"tweetnacl":419}],3:[function(require,module,exports){ (function (Buffer){ var CryptoJS = require('crypto-js'); var Transaction = require('ethereumjs-tx'); var EC = require('elliptic').ec; var ec = new EC('secp256k1'); var bitcore = require('bitcore-lib'); var Random = bitcore.crypto.Random; var Hash = bitcore.crypto.Hash; var Mnemonic = require('bitcore-mnemonic'); var nacl = require('tweetnacl'); var scrypt = require('scrypt-async'); var encryption = require('./encryption'); var signing = require('./signing'); function strip0x (input) { if (typeof(input) !== 'string') { return input; } else if (input.length >= 2 && input.slice(0,2) === '0x') { return input.slice(2); } else { return input; } } function add0x (input) { if (typeof(input) !== 'string') { return input; } else if (input.length < 2 || input.slice(0,2) !== '0x') { return '0x' + input; } else { return input; } } function leftPadString (stringToPad, padChar, length) { var repreatedPadChar = ''; for (var i=0; i<length; i++) { repreatedPadChar += padChar; } return ( (repreatedPadChar + stringToPad).slice(-length) ); } function nacl_encodeHex(msgUInt8Arr) { var msgBase64 = nacl.util.encodeBase64(msgUInt8Arr); return (new Buffer(msgBase64, 'base64')).toString('hex'); } function nacl_decodeHex(msgHex) { var msgBase64 = (new Buffer(msgHex, 'hex')).toString('base64'); return nacl.util.decodeBase64(msgBase64); } var KeyStore = function(mnemonic, pwDerivedKey, hdPathString) { this.defaultHdPathString = "m/0'/0'/0'"; if (hdPathString === undefined) { hdPathString = this.defaultHdPathString; } this.ksData = {}; this.ksData[hdPathString] = {}; pathKsData = this.ksData[hdPathString]; pathKsData.info = {curve: 'secp256k1', purpose: 'sign'}; this.encSeed = undefined; this.encHdRootPriv = undefined; this.version = 2; pathKsData.encHdPathPriv = undefined; pathKsData.hdIndex = 0; pathKsData.encPrivKeys = {}; pathKsData.addresses = []; if ( (typeof pwDerivedKey !== 'undefined') && (typeof mnemonic !== 'undefined') ){ var words = mnemonic.split(' '); if (!Mnemonic.isValid(mnemonic, Mnemonic.Words.ENGLISH) || words.length !== 12){ throw new Error('KeyStore: Invalid mnemonic'); } // Pad the seed to length 120 before encrypting var paddedSeed = leftPadString(mnemonic, ' ', 120); this.encSeed = KeyStore._encryptString(paddedSeed, pwDerivedKey); // hdRoot is the relative root from which we derive the keys using // generateNewAddress(). The derived keys are then // `hdRoot/hdIndex`. // // Default hdRoot is m/0'/0'/0', the overall logic is // m/0'/Persona'/Purpose', where the 0' purpose is // for standard Ethereum accounts. var hdRoot = new Mnemonic(mnemonic).toHDPrivateKey().xprivkey; this.encHdRootPriv = KeyStore._encryptString(hdRoot, pwDerivedKey); var hdRootKey = new bitcore.HDPrivateKey(hdRoot); var hdPath = hdRootKey.derive(hdPathString).xprivkey; pathKsData.encHdPathPriv = KeyStore._encryptString(hdPath, pwDerivedKey); } }; KeyStore._encryptString = function (string, pwDerivedKey) { var nonce = nacl.randomBytes(nacl.secretbox.nonceLength); var encObj = nacl.secretbox(nacl.util.decodeUTF8(string), nonce, pwDerivedKey); var encString = { 'encStr': nacl.util.encodeBase64(encObj), 'nonce': nacl.util.encodeBase64(nonce)}; return encString; }; KeyStore._decryptString = function (encryptedStr, pwDerivedKey) { var secretbox = nacl.util.decodeBase64(encryptedStr.encStr); var nonce = nacl.util.decodeBase64(encryptedStr.nonce); var decryptedStr = nacl.secretbox.open(secretbox, nonce, pwDerivedKey); return nacl.util.encodeUTF8(decryptedStr); }; KeyStore._encryptKey = function (privKey, pwDerivedKey) { var privKeyArray = nacl_decodeHex(privKey); var nonce = nacl.randomBytes(nacl.secretbox.nonceLength); var encKey = nacl.secretbox(privKeyArray, nonce, pwDerivedKey); encKey = { 'key': nacl.util.encodeBase64(encKey), 'nonce': nacl.util.encodeBase64(nonce)}; return encKey; }; KeyStore._decryptKey = function (encryptedKey, pwDerivedKey) { var secretbox = nacl.util.decodeBase64(encryptedKey.key); var nonce = nacl.util.decodeBase64(encryptedKey.nonce); var decryptedKey = nacl.secretbox.open(secretbox, nonce, pwDerivedKey); return nacl_encodeHex(decryptedKey); }; KeyStore._computeAddressFromPrivKey = function (privKey) { var keyPair = ec.genKeyPair(); keyPair._importPrivate(privKey, 'hex'); var compact = false; var pubKey = keyPair.getPublic(compact, 'hex').slice(2); var pubKeyWordArray = CryptoJS.enc.Hex.parse(pubKey); var hash = CryptoJS.SHA3(pubKeyWordArray, { outputLength: 256 }); var address = hash.toString(CryptoJS.enc.Hex).slice(24); return address; }; KeyStore._computePubkeyFromPrivKey = function (privKey, curve) { if (curve !== 'curve25519') { throw new Error('KeyStore._computePubkeyFromPrivKey: Only "curve25519" supported.') } var privKeyBase64 = (new Buffer(privKey, 'hex')).toString('base64') var privKeyUInt8Array = nacl.util.decodeBase64(privKeyBase64); var pubKey = nacl.box.keyPair.fromSecretKey(privKeyUInt8Array).publicKey; var pubKeyBase64 = nacl.util.encodeBase64(pubKey); var pubKeyHex = (new Buffer(pubKeyBase64, 'base64')).toString('hex'); return pubKeyHex; } KeyStore.prototype.addHdDerivationPath = function (hdPathString, pwDerivedKey, info) { if (info.purpose !== 'sign' && info.purpose !== 'asymEncrypt') { throw new Error("KeyStore.addHdDerivationPath: info.purpose is '" + info.purpose + "' but must be either 'sign' or 'asymEncrypt'."); } if (info.curve !== 'secp256k1' && info.curve !== 'curve25519') { throw new Error("KeyStore.addHdDerivationPath: info.curve is '" + info.curve + "' but must be either 'secp256k1' or 'curve25519'."); } var hdRoot = KeyStore._decryptString(this.encHdRootPriv, pwDerivedKey); var hdRootKey = new bitcore.HDPrivateKey(hdRoot); var hdPath = hdRootKey.derive(hdPathString).xprivkey; this.ksData[hdPathString] = {}; this.ksData[hdPathString].info = info; this.ksData[hdPathString].encHdPathPriv = KeyStore._encryptString(hdPath, pwDerivedKey); this.ksData[hdPathString].hdIndex = 0; this.ksData[hdPathString].encPrivKeys = {}; if (info.purpose === 'sign') { this.ksData[hdPathString].addresses = []; } else if (info.purpose === 'asymEncrypt') { this.ksData[hdPathString].pubKeys = []; } } KeyStore.prototype.setDefaultHdDerivationPath = function (hdPathString) { if (this.ksData[hdPathString] === undefined) { throw new Error('setDefaultHdDerivationPath: HD path does not exist. Cannot set default.'); } this.defaultHdPathString = hdPathString; } KeyStore.prototype._generatePrivKeys = function(pwDerivedKey, n, hdPathString) { if (hdPathString === undefined) { hdPathString = this.defaultHdPathString; } var hdRoot = KeyStore._decryptString(this.ksData[hdPathString].encHdPathPriv, pwDerivedKey); var keys = []; for (var i = 0; i < n; i++){ var hdprivkey = new bitcore.HDPrivateKey(hdRoot).derive(this.ksData[hdPathString].hdIndex++); var privkeyBuf = hdprivkey.privateKey.toBuffer(); var privkeyHex = privkeyBuf.toString('hex'); if (privkeyBuf.length < 16) { // Way too small key, something must have gone wrong // Halt and catch fire throw new Error('Private key suspiciously small: < 16 bytes. Aborting!'); } else if (privkeyBuf.length < 32) { // Pad private key if too short // bitcore has a bug where it sometimes returns // truncated keys privkeyHex = leftPadString(privkeyBuf.toString('hex'), '0', 64); } else if (privkeyBuf.length > 32) { throw new Error('Private key larger than 32 bytes. Aborting!'); } var encPrivKey = KeyStore._encryptKey(privkeyHex, pwDerivedKey); keys[i] = { privKey: privkeyHex, encPrivKey: encPrivKey } } return keys; }; // This function is tested using the test vectors here: // http://www.di-mgt.com.au/sha_testvectors.html KeyStore._concatAndSha256 = function(entropyBuf0, entropyBuf1) { var totalEnt = Buffer.concat([entropyBuf0, entropyBuf1]); if (totalEnt.length !== entropyBuf0.length + entropyBuf1.length) { throw new Error('generateRandomSeed: Logic error! Concatenation of entropy sources failed.') } var hashedEnt = Hash.sha256(totalEnt); return hashedEnt; } // External static functions // Generates a random seed. If the optional string // extraEntropy is set, a random set of entropy // is created, then concatenated with extraEntropy // and hashed to produce the entropy that gives the seed. // Thus if extraEntropy comes from a high-entropy source // (like dice) it can give some protection from a bad RNG. // If extraEntropy is not set, the random number generator // is used directly. KeyStore.generateRandomSeed = function(extraEntropy) { var seed = ''; if (extraEntropy === undefined) { seed = new Mnemonic(Mnemonic.Words.ENGLISH); } else if (typeof extraEntropy === 'string') { var entBuf = new Buffer(extraEntropy); var randBuf = Random.getRandomBuffer(256 / 8); var hashedEnt = this._concatAndSha256(randBuf, entBuf).slice(0, 128 / 8); seed = new Mnemonic(hashedEnt, Mnemonic.Words.ENGLISH); } else { throw new Error('generateRandomSeed: extraEntropy is set but not a string.') } return seed.toString(); }; KeyStore.isSeedValid = function(seed) { return Mnemonic.isValid(seed, Mnemonic.Words.ENGLISH) }; KeyStore.prototype.isDerivedKeyCorrect = function(pwDerivedKey) { var paddedSeed = KeyStore._decryptString(this.encSeed, pwDerivedKey); if (paddedSeed.length > 0) { return true; } return false; }; // Takes keystore serialized as string and returns an instance of KeyStore KeyStore.deserialize = function (keystore) { var jsonKS = JSON.parse(keystore); if (jsonKS.version === undefined || jsonKS.version === 1) { throw new Error('Old version of serialized keystore. Please use KeyStore.upgradeOldSerialized() to convert it to the latest version.') } // Create keystore var keystoreX = new KeyStore(); keystoreX.encSeed = jsonKS.encSeed; keystoreX.encHdRootPriv = jsonKS.encHdRootPriv; keystoreX.ksData = jsonKS.ksData; return keystoreX; }; // External API functions KeyStore.prototype.serialize = function () { var jsonKS = {'encSeed': this.encSeed, 'ksData' : this.ksData, 'encHdRootPriv' : this.encHdRootPriv, 'version' : this.version}; return JSON.stringify(jsonKS); }; KeyStore.prototype.getAddresses = function (hdPathString) { if (hdPathString === undefined) { hdPathString = this.defaultHdPathString; } if (this.ksData[hdPathString].info.purpose !== 'sign') { throw new Error('KeyStore.getAddresses: Addresses not defined when purpose is not "sign"'); } return this.ksData[hdPathString].addresses; }; KeyStore.prototype.getSeed = function (pwDerivedKey) { var paddedSeed = KeyStore._decryptString(this.encSeed, pwDerivedKey); return paddedSeed.trim(); }; KeyStore.prototype.exportPrivateKey = function (address, pwDerivedKey, hdPathString) { if (hdPathString === undefined) { hdPathString = this.defaultHdPathString; } var address = strip0x(address); if (this.ksData[hdPathString].encPrivKeys[address] === undefined) { throw new Error('KeyStore.exportPrivateKey: Address not found in KeyStore'); } var encPrivKey = this.ksData[hdPathString].encPrivKeys[address]; var privKey = KeyStore._decryptKey(encPrivKey, pwDerivedKey); return privKey; }; KeyStore.prototype.generateNewAddress = function(pwDerivedKey, n, hdPathString) { if (hdPathString === undefined) { hdPathString = this.defaultHdPathString; } if (this.ksData[hdPathString].info.purpose !== 'sign') { throw new Error('KeyStore.generateNewAddress: Address not defined when purpose is not "sign"'); } if (!this.encSeed) { throw new Error('KeyStore.generateNewAddress: No seed set'); } n = n || 1; var keys = this._generatePrivKeys(pwDerivedKey, n, hdPathString); for (var i = 0; i < n; i++) { var keyObj = keys[i]; var address = KeyStore._computeAddressFromPrivKey(keyObj.privKey); this.ksData[hdPathString].encPrivKeys[address] = keyObj.encPrivKey; this.ksData[hdPathString].addresses.push(address); } }; KeyStore.prototype.generateNewEncryptionKeys = function(pwDerivedKey, n, hdPathString) { if (hdPathString === undefined) { hdPathString = this.defaultHdPathString; } if (this.ksData[hdPathString].info.purpose !== 'asymEncrypt') { throw new Error('KeyStore.generateNewEncryptionKeys: Address not defined when purpose is not "asymEncrypt"'); } if (!this.encSeed) { throw new Error('KeyStore.generateNewEncryptionKeys: No seed set'); } n = n || 1; var keys = this._generatePrivKeys(pwDerivedKey, n, hdPathString); var curve = this.ksData[hdPathString].info.curve; for (var i = 0; i < n; i++) { var keyObj = keys[i]; var pubkey = KeyStore._computePubkeyFromPrivKey(keyObj.privKey, curve); this.ksData[hdPathString].encPrivKeys[pubkey] = keyObj.encPrivKey; this.ksData[hdPathString].pubKeys.push(pubkey); } }; KeyStore.prototype.getPubKeys = function (hdPathString) { if (hdPathString === undefined) { hdPathString = this.defaultHdPathString; } if (this.ksData[hdPathString].info.purpose !== 'asymEncrypt') { throw new Error('KeyStore.getPubKeys: Not defined when purpose is not "asymEncrypt"'); } if (this.ksData[hdPathString].pubKeys === undefined) { throw new Error('KeyStore.getPubKeys: No pubKeys data found!'); } return this.ksData[hdPathString].pubKeys; } KeyStore.deriveKeyFromPassword = function(password, callback) { var salt = 'lightwalletSalt'; // should we have user-defined salt? var logN = 14; var r = 8; var dkLen = 32; var interruptStep = 200; var cb = function(derKey) { var ui8arr = (new Uint8Array(derKey)); callback(null, ui8arr); } scrypt(password, salt, logN, r, dkLen, interruptStep, cb, null); } // Async functions exposed for Hooked Web3-provider // hasAddress(address, callback) // signTransaction(txParams, callback) // // The function signTransaction() needs the // function KeyStore.prototype.passwordProvider(callback) // to be set in order to run properly. // The function passwordProvider is an async function // that calls the callback(err, password) with a password // supplied by the user or by other means. // The user of the hooked web3-provider is encouraged // to write their own passwordProvider. // // Uses defaultHdPathString for the addresses. KeyStore.prototype.passwordProvider = function (callback) { var password = prompt("Enter password to continue","Enter password"); callback(null, password); } KeyStore.prototype.hasAddress = function (address, callback) { var addrToCheck = strip0x(address); if (this.ksData[this.defaultHdPathString].encPrivKeys[addrToCheck] === undefined) { callback('Address not found!', false); } else { callback(null, true); } }; KeyStore.prototype.signTransaction = function (txParams, callback) { var ethjsTxParams = {}; ethjsTxParams.from = add0x(txParams.from); ethjsTxParams.to = add0x(txParams.to); ethjsTxParams.gasLimit = add0x(txParams.gas); ethjsTxParams.gasPrice = add0x(txParams.gasPrice); ethjsTxParams.nonce = add0x(txParams.nonce); ethjsTxParams.value = add0x(txParams.value); ethjsTxParams.data = add0x(txParams.data); var txObj = new Transaction(ethjsTxParams); var rawTx = txObj.serialize().toString('hex'); var signingAddress = strip0x(txParams.from); var self = this; this.passwordProvider( function (err, password) { if (err) return callback(err); KeyStore.deriveKeyFromPassword(password, function (err, pwDerivedKey) { var signedTx = signing.signTx(self, pwDerivedKey, rawTx, signingAddress, self.defaultHdPathString); callback(null, '0x' + signedTx); }) }) }; module.exports = KeyStore; }).call(this,require("buffer").Buffer) },{"./encryption":2,"./signing":4,"bitcore-lib":7,"bitcore-mnemonic":86,"buffer":99,"crypto-js":330,"elliptic":356,"ethereumjs-tx":379,"scrypt-async":418,"tweetnacl":419}],4:[function(require,module,exports){ (function (Buffer){ var Transaction = require("ethereumjs-tx") var util = require("ethereumjs-util") signTx = function (keystore, pwDerivedKey, rawTx, signingAddress, hdPathString) { if (hdPathString === undefined) { hdPathString = keystore.defaultHdPathString; } rawTx = util.stripHexPrefix(rawTx); signingAddress = util.stripHexPrefix(signingAddress); var txCopy = new Transaction(new Buffer(rawTx, 'hex')); var privKey = keystore.exportPrivateKey(signingAddress, pwDerivedKey, hdPathString); txCopy.sign(new Buffer(privKey, 'hex')); privKey = ''; return txCopy.serialize().toString('hex'); }; module.exports.signTx = signTx; signMsg = function (keystore, pwDerivedKey, rawMsg, signingAddress, hdPathString) { if (hdPathString === undefined) { hdPathString = keystore.defaultHdPathString; } signingAddress = util.stripHexPrefix(signingAddress); var msgHash = util.sha3(rawMsg); var privKey = keystore.exportPrivateKey(signingAddress, pwDerivedKey, hdPathString); return util.ecsign(msgHash, new Buffer(privKey, 'hex')); }; module.exports.signMsg = signMsg; recoverAddress = function (rawMsg, v, r, s) { var msgHash = util.sha3(rawMsg); return util.pubToAddress(util.ecrecover(msgHash, v, r, s)); }; module.exports.recoverAddress = recoverAddress; concatSig = function (v, r, s) { r = util.fromSigned(r); s = util.fromSigned(s); v = util.bufferToInt(v); r = util.toUnsigned(r).toString('hex'); s = util.toUnsigned(s).toString('hex'); v = util.stripHexPrefix(util.intToHex(v)); return util.addHexPrefix(r.concat(s, v).toString("hex")); }; module.exports.concatSig = concatSig; }).call(this,require("buffer").Buffer) },{"buffer":99,"ethereumjs-tx":379,"ethereumjs-util":382}],5:[function(require,module,exports){ (function (Buffer){ var Transaction = require('ethereumjs-tx'); var coder = require('web3/lib/solidity/coder'); var rlp = require('rlp'); var CryptoJS = require('crypto-js'); function add0x (input) { if (typeof(input) !== 'string') { return input; } else if (input.length < 2 || input.slice(0,2) !== '0x') { return '0x' + input; } else { return input; } } function _encodeFunctionTxData (functionName, types, args) { var fullName = functionName + '(' + types.join() + ')'; var signature = CryptoJS.SHA3(fullName, { outputLength: 256 }).toString(CryptoJS.enc.Hex).slice(0, 8); var dataHex = signature + coder.encodeParams(types, args); return dataHex; } function _getTypesFromAbi (abi, functionName) { function matchesFunctionName(json) { return (json.name === functionName && json.type === 'function'); } function getTypes(json) { return json.type; } var funcJson = abi.filter(matchesFunctionName)[0]; return (funcJson.inputs).map(getTypes); } function functionTx (abi, functionName, args, txObject) { // txObject contains gasPrice, gasLimit, nonce, to, value var types = _getTypesFromAbi(abi, functionName); var txData = _encodeFunctionTxData(functionName, types, args); var txObjectCopy = {}; txObjectCopy.to = add0x(txObject.to); txObjectCopy.gasPrice = add0x(txObject.gasPrice); txObjectCopy.gasLimit = add0x(txObject.gasLimit); txObjectCopy.nonce = add0x(txObject.nonce); txObjectCopy.data = add0x(txData); txObjectCopy.value = add0x(txObject.value); return (new Transaction(txObjectCopy)).serialize().toString('hex'); } function createdContractAddress (fromAddress, nonce) { var rlpEncodedHex = rlp.encode([new Buffer(fromAddress, 'hex'), nonce]).toString('hex'); var rlpEncodedWordArray = CryptoJS.enc.Hex.parse(rlpEncodedHex); var hash = CryptoJS.SHA3(rlpEncodedWordArray, {outputLength: 256}).toString(CryptoJS.enc.Hex); return hash.slice(24); } function createContractTx (fromAddress, txObject) { // txObject contains gasPrice, gasLimit, value, data, nonce var txObjectCopy = {}; txObjectCopy.to = add0x(txObject.to); txObjectCopy.gasPrice = add0x(txObject.gasPrice); txObjectCopy.gasLimit = add0x(txObject.gasLimit); txObjectCopy.nonce = add0x(txObject.nonce); txObjectCopy.data = add0x(txObject.data); txObjectCopy.value = add0x(txObject.value); var contractAddress = createdContractAddress(fromAddress, txObject.nonce); var tx = new Transaction(txObjectCopy); return {tx: tx.serialize().toString('hex'), addr: contractAddress}; } function valueTx (txObject) { // txObject contains gasPrice, gasLimit, value, nonce var txObjectCopy = {}; txObjectCopy.to = add0x(txObject.to); txObjectCopy.gasPrice = add0x(txObject.gasPrice); txObjectCopy.gasLimit = add0x(txObject.gasLimit); txObjectCopy.nonce = add0x(txObject.nonce); txObjectCopy.value = add0x(txObject.value); var tx = new Transaction(txObjectCopy); return tx.serialize().toString('hex'); } module.exports = { _encodeFunctionTxData: _encodeFunctionTxData, _getTypesFromAbi: _getTypesFromAbi, functionTx: functionTx, createdContractAddress: createdContractAddress, createContractTx: createContractTx, valueTx: valueTx }; }).call(this,require("buffer").Buffer) },{"buffer":99,"crypto-js":330,"ethereumjs-tx":379,"rlp":417,"web3/lib/solidity/coder":423}],6:[function(require,module,exports){ var CryptoJS = require('crypto-js'); var keystore = require('./keystore'); var Transaction = require('ethereumjs-tx'); var EC = require('elliptic').ec; var ec = new EC('secp256k1'); var bitcore = require('bitcore-lib'); var Random = bitcore.crypto.Random; var Hash = bitcore.crypto.Hash; var Mnemonic = require('bitcore-mnemonic'); var nacl = require('tweetnacl'); var scrypt = require('scrypt-async'); legacyDecryptString = function (encryptedStr, password) { var decryptedStr = CryptoJS.AES.decrypt(encryptedStr.encStr, password, {'iv': encryptedStr.iv, 'salt': encryptedStr.salt }); return decryptedStr.toString(CryptoJS.enc.Latin1); }; legacyGenerateEncKey = function(password, salt, keyHash) { var encKey = CryptoJS.PBKDF2(password, salt, { keySize: 512 / 32, iterations: 150 }).toString(); var hash = CryptoJS.SHA3(encKey).toString(); if (keyHash !== hash){ throw new Error('Invalid Password'); } return encKey; }; upgradeOldSerialized = function (oldSerialized, password, callback) { // Upgrades old serialized version of the keystore // to the latest version var oldKS = JSON.parse(oldSerialized); if (oldKS.version === undefined || oldKS.version === 1) { var derivedKey = legacyGenerateEncKey(password, oldKS.salt, oldKS.keyHash); var seed = legacyDecryptString(oldKS.encSeed, derivedKey); keystore.deriveKeyFromPassword(password, function(err, pwDerivedKey) { var newKeyStore = new keystore(seed, pwDerivedKey); var hdIndex = oldKS.hdIndex; newKeyStore.generateNewAddress(pwDerivedKey, hdIndex); callback(null, newKeyStore.serialize()); }) } else { throw new Error('Keystore is not of correct version.') } } module.exports.upgradeOldSerialized = upgradeOldSerialized; },{"./keystore":3,"bitcore-lib":7,"bitcore-mnemonic":86,"crypto-js":330,"elliptic":356,"ethereumjs-tx":379,"scrypt-async":418,"tweetnacl":419}],7:[function(require,module,exports){ (function (global,Buffer){ 'use strict'; var bitcore = module.exports; // module information bitcore.version = 'v' + require('./package.json').version; bitcore.versionGuard = function(version) { if (version !== undefined) { var message = 'More than one instance of bitcore-lib found. ' + 'Please make sure to require bitcore-lib and check that submodules do' + ' not also include their own bitcore-lib dependency.'; throw new Error(message); } }; bitcore.versionGuard(global._bitcore); global._bitcore = bitcore.version; // 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.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'); // 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'); }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},require("buffer").Buffer) },{"./lib/address":8,"./lib/block":11,"./lib/block/blockheader":10,"./lib/block/merkleblock":12,"./lib/crypto/bn":13,"./lib/crypto/ecdsa":14,"./lib/crypto/hash":15,"./lib/crypto/point":16,"./lib/crypto/random":17,"./lib/crypto/signature":18,"./lib/encoding/base58":19,"./lib/encoding/base58check":20,"./lib/encoding/bufferreader":21,"./lib/encoding/bufferwriter":22,"./lib/encoding/varint":23,"./lib/errors":24,"./lib/hdkeycache":26,"./lib/hdprivatekey.js":27,"./lib/hdpublickey.js":28,"./lib/networks":29,"./lib/opcode":30,"./lib/privatekey":31,"./lib/publickey":32,"./lib/script":33,"./lib/transaction":36,"./lib/transaction/sighash":44,"./lib/unit":48,"./lib/uri":49,"./lib/util/buffer":50,"./lib/util/js":51,"./lib/util/preconditions":52,"./package.json":85,"bn.js":53,"bs58":54,"buffer":99,"elliptic":56,"lodash":78}],8:[function(require,module,exports){ (function (Buffer){ 'use strict'; var _ = require('lodash'); var $ = require('./util/preconditions'); var errors = require('./errors'); var Base58Check = require('./encoding/base58check'); var Networks = require('./networks'); var Hash = require('./crypto/hash'); var JSUtil = require('./util/js'); var PublicKey = require('./publickey'); /** * 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 */ if (!(this instanceof Address)) { return new Address(data, network, type); } if (_.isArray(data) && _.isNumber(network)) { return Address.createMultisig(data, network, type); } if (data instanceof Address) { // Immutable instance return data; } $.checkArgument(data, 'First argument is required, please include address data.', 'guide/address.html'); if (network && !Networks.get(network)) { throw new TypeError('Second argument must be "livenet" or "testnet".'); } if (type && (type !== Address.PayToPublicKeyHash && type !== Address.PayToScriptHash)) { throw new TypeError('Third argument must be "pubkeyhash" or "scripthash".'); } var info = this._classifyArguments(data, network, type); // set defaults if not set info.network = info.network || Networks.get(network) || Networks.defaultNetwork; info.type = info.type || type || Address.PayToPublicKeyHash; JSUtil.defineImmutable(this, { hashBuffer: info.hashBuffer, network: info.network, type: info.type }); return this; } /** * 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) { /* 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'; /** * @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; }; /** * 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 }; }; /** * 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 = {}; var pubkeyhashNetwork = Networks.get(buffer[0], 'pubkeyhash'); var scripthashNetwork = Networks.get(buffer[0], 'scripthash'); if (pubkeyhashNetwork) { version.network = pubkeyhashNetwork; version.type = Address.PayToPublicKeyHash; } else if (scripthashNetwork) { version.network = scripthashNetwork; version.type = Address.PayToScriptHash; } return version; }; /** * 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.'); } network = Networks.get(network); var bufferVersion = Address._classifyFromVersion(buffer); if (!bufferVersion.network || (network && network !== bufferVersion.network)) { throw new TypeError('Address has mismatched network type.'); } if (!bufferVersion.type || (type && type !== bufferVersion.type)) { throw new TypeError('Address has mismatched type.'); } info.hashBuffer = buffer.slice(1); info.network = bufferVersion.network; info.type = bufferVersion.type; return info; }; /** * 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 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; }; /** * 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) { $.checkArgument(script instanceof Script, 'script must be a Script instance'); var info = script.getAddressInfo(network); if (!info) { throw new errors.Script.CantDeriveAddress(script); } return info; }; /** * 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) { network = network || publicKeys[0].network || Networks.defaultNetwork; return Address.payingTo(Script.buildMultisigOut(publicKeys, threshold), network); }; /** * 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('data parameter supplied is not a string.'); } data = data.trim(); var addressBuffer = Base58Check.decode(data); var info = Address._transformBuffer(addressBuffer, network, type); return info; }; /** * 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); }; /** * 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); }; /** * 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) { $.checkArgument(hash, 'hash parameter is required'); var info = Address._transformHash(hash); return new Address(info.hashBuffer, network, Address.PayToScriptHash); }; /** * Builds a p2sh address paying to script. This will hash the script and * use that to create the address. * If you want to extract an address associated with a script instead, * see {{Address#fromScript}} * * @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.payingTo = function(script, network) { $.checkArgument(script, 'script is required'); $.checkArgument(script instanceof Script, 'script must be instance of Script'); return Address.fromScriptHash(Hash.sha256ripemd160(script.toBuffer()), network); }; /** * Extract address from a Script. The script must be of one * of the following types: p2pkh input, p2pkh output, p2sh input * or p2sh output. * This will analyze the script and extract address information from it. * If you want to transform any script to a p2sh Address paying * to that script's hash instead, use {{Address#payingTo}} * * @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) { $.checkArgument(script instanceof Script, 'script must be a Script instance'); var info = Address._transformScript(script, network); return new Address(info.hashBuffer, network, info.type); }; /** * 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); }; /** * 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); }; /** * Instantiate an address from an Object * * @param {string} json - An JSON string or Object with keys: hash, network and type * @returns {Address} A new valid instance of an Address */ Address.fromObject = function fromObject(obj) { $.checkState( JSUtil.isHexa(obj.hash), 'Unexpected hash property, "' + obj.hash + '", expected to be hex.' ); var hashBuffer = new Buffer(obj.hash, 'hex'); return new Address(hashBuffer, obj.network, obj.type); }; /** * 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; } return error; }; /** * Will return a boolean if an address is