UNPKG

bitcoin-utility-belt

Version:

Bitcoin Utility Belt is a client-side Bitcoin JavaScript library

473 lines (407 loc) 12.5 kB
// import libs let bitcoin = require("bitcoinjs-lib"); let bitcoinMessage = require("bitcoinjs-message"); let bip32 = require('bip32'); let bip38 = require("bip38"); let bip39 = require('bip39'); let wif = require("wif"); let bigi = require("bigi"); let safeBuffer = require("safe-buffer").Buffer; let assert = require("assert"); let validateAddress = (address, testnet = false) => { try { // check network: bitcoin or testnet let network; if(testnet){ network = bitcoin.networks.testnet; }else{ network = bitcoin.networks.bitcoin; } // try to output script to validate address bitcoin.address.toOutputScript(address, network); // no errors return true return true; } catch (err) { // return false return false; } }; let checkAddress = (address, testnet = false) => { try{ let type = false; // check network: bitcoin or testnet let network; if(testnet){ network = bitcoin.networks.testnet; }else{ network = bitcoin.networks.bitcoin; } if(validateAddress(address)){ let addressScript = bitcoin.address.toOutputScript(address, network); if(bitcoin.script.pubKeyHash.output.check(addressScript)){ type = "P2PKH"; } if(bitcoin.script.scriptHash.output.check(addressScript)){ type = "P2SH|P2WSH"; } if(bitcoin.script.witnessPubKeyHash.output.check(addressScript)){ type = "P2PKH"; } } return type; } catch(err){ // show error console.error(err); return false; } }; let generateAddress = (type, publicKeyHash, network) => { try{ let address; let redeemScript; let scriptPubKey; // choose wallet type switch (type){ case "P2SH": // pay to script hash redeemScript = bitcoin.script.scriptHash.output.encode(publicKeyHash); address = bitcoin.address.fromOutputScript(redeemScript, network); break; case "P2WPKH": // pay to witness public key hash redeemScript = bitcoin.script.witnessPubKeyHash.output.encode(publicKeyHash); address = bitcoin.address.fromOutputScript(redeemScript, network); break; case "P2WSH": // pay to witness script hash redeemScript = bitcoin.script.witnessPubKeyHash.output.encode(publicKeyHash); let redeemScriptHash = bitcoin.script.scriptHash.output.encode(bitcoin.crypto.hash160(redeemScript)); address = bitcoin.address.fromOutputScript(redeemScriptHash, network); break; default: // pay to public key hash redeemScript = bitcoin.script.pubKeyHash.output.encode(publicKeyHash); address = bitcoin.address.fromOutputScript(redeemScript, network); break; } return address; } catch(err){ // show error console.error(err); return false; } }; let getPublicKeyHex = (privateKey, testnet = false) => { try{ // check network: bitcoin or testnet let network; if(testnet){ network = bitcoin.networks.testnet; }else{ network = bitcoin.networks.bitcoin; } // create key pair of eliptic curves let keyPair = bitcoin.ECPair.fromWIF(privateKey, network); // public key buffer let publicKeyBuffer = keyPair.getPublicKeyBuffer(); let publicKeyHex = bitcoin.script.compile(publicKeyBuffer).toString('hex'); return publicKeyHex; } catch(err){ // show error console.error(err); return false; } }; let createMultiSig = (pubKeys, countSign, type = "P2SH", testnet = false) => { try{ // check network: bitcoin or testnet let network; if(testnet){ network = bitcoin.networks.testnet; }else{ network = bitcoin.networks.bitcoin; } let scriptPubKey; let address; let pubKeysHex = pubKeys.map(function (hex) { return Buffer.from(hex, 'hex'); }); switch(type){ case "P2SH": let redeemScript = bitcoin.script.multisig.output.encode(countSign, pubKeysHex); scriptPubKey = bitcoin.script.scriptHash.output.encode(bitcoin.crypto.hash160(redeemScript)); address = bitcoin.address.fromOutputScript(scriptPubKey, network); break; default: let witnessScript = bitcoin.script.multisig.output.encode(countSign, pubKeysHex); scriptPubKey = bitcoin.script.witnessScriptHash.output.encode(bitcoin.crypto.sha256(witnessScript)); address = bitcoin.address.fromOutputScript(scriptPubKey, network); break; } return address; } catch(err){ // show error console.error(err); return false; } }; let recoverAddress = (privateKey, type="P2PKH", testnet = false) => { try{ // check network: bitcoin or testnet let network; if(testnet){ network = bitcoin.networks.testnet; }else{ network = bitcoin.networks.bitcoin; } // create key pair of eliptic curves let keyPair = bitcoin.ECPair.fromWIF(privateKey, network); // public key buffer let publicKeyBuffer = keyPair.getPublicKeyBuffer(); // public key hash let publicKeyHash = bitcoin.crypto.hash160(publicKeyBuffer); // generate Address let address = generateAddress(type, publicKeyHash, network); // return address return address; } catch(err){ // show error console.error(err); return false; } }; let chooseBipSeed = (bip, count, testnet) => { // choose bip let path; switch (bip){ case "32": if(testnet){ path = "m/0'/1/0"+count; }else{ path = "m/0'/0/0"+count; } break; case "44": if(testnet){ path = "m/44'/1'/0'/0/"+count; }else{ path = "m/44'/0'/0'/0/"+count; } break; default: if(testnet){ path = "m/49'/1'/0'/0/"+count; }else{ path = "m/49'/0'/0'/0/"+count; } break; } return path; }; let recoverSeed = (seed, count = 1, type="P2PKH", bip="49", testnet = false) => { try{ // check network: bitcoin or testnet let network; if(testnet){ network = bitcoin.networks.testnet; }else{ network = bitcoin.networks.bitcoin; } // choosing wallet let wallet; let wallets = []; let mnemonic = seed; let bip39seed = bip39.mnemonicToSeed(mnemonic); let root = bip32.fromSeed(bip39seed); let path; let i; for (i = 0; i < count; i++) { // choose bip path = chooseBipSeed(bip, i, testnet); // get child let child = root.derivePath(path); // create new key pair of eliptic curves let d = bigi.fromBuffer(child.privateKey); let keyPair = new bitcoin.ECPair(d, null, {network: network}); // public key hash let publicKeyHash = bitcoin.crypto.hash160(child.publicKey); // generate Address let address = generateAddress(type, publicKeyHash, network); // return wallet wallets.push({ "address": address, "privateKey": keyPair.toWIF() }); } return wallets; } catch(err){ // show error console.error(err); return false; } }; let create = (type = "P2PKH", testnet = false) => { try{ // check network: bitcoin or testnet let network; if(testnet){ network = bitcoin.networks.testnet; }else{ network = bitcoin.networks.bitcoin; } // create new random key pair of eliptic curves let keyPair = bitcoin.ECPair.makeRandom({network: network}); // public key buffer let publicKeyBuffer = keyPair.getPublicKeyBuffer(); // public key hash let publicKeyHash = bitcoin.crypto.hash160(publicKeyBuffer); // generate Address let address = generateAddress(type, publicKeyHash, network); // return wallet let wallet = { "address": address, "privateKey": keyPair.toWIF() }; return wallet; } catch (err) { // show error console.error(err); return false; } }; let createSeed = (count = 1, type="P2PKH", bip="49", testnet = false) => { try{ // check network: bitcoin or testnet let network; if(testnet){ network = bitcoin.networks.testnet; }else{ network = bitcoin.networks.bitcoin; } // choosing wallet let wallets = []; let mnemonic = bip39.generateMnemonic(); let seed = bip39.mnemonicToSeed(mnemonic); let root = bip32.fromSeed(seed); let path; let i; for (i = 0; i < count; i++) { // choose bip path = chooseBipSeed(bip, i, testnet); // get child let child = root.derivePath(path); // create new key pair of eliptic curves let d = bigi.fromBuffer(child.privateKey); let keyPair = new bitcoin.ECPair(d, null, {network: network}); // public key hash let publicKeyHash = bitcoin.crypto.hash160(child.publicKey); // generate Address let address = generateAddress(type, publicKeyHash, network); // return wallet wallets.push({ "address": address, "privateKey": keyPair.toWIF() }); } let wallet = { "seed": mnemonic, "wallets": wallets }; return wallet; } catch(err){ // show error console.error(err); return false; } }; let generateMnemonic = () => { return bip39.generateMnemonic(); }; let validateMnemonic = (seed) => { return bip39.validateMnemonic(seed); }; let createBrainWallet = (passphrase, type="P2PKH", testnet = false) => { try{ // check network: bitcoin or testnet let network; if(testnet){ network = bitcoin.networks.testnet; }else{ network = bitcoin.networks.bitcoin; } let passphraseHash = bitcoin.crypto.sha256(safeBuffer.from(passphrase)); let d = bigi.fromBuffer(passphraseHash); let keyPair = new bitcoin.ECPair(d, null, {network: network}); // public key buffer let publicKeyBuffer = keyPair.getPublicKeyBuffer(); // public key hash let publicKeyHash = bitcoin.crypto.hash160(publicKeyBuffer); // generate Address let address = generateAddress(type, publicKeyHash, network); // return wallet with address and private key let wallet = { "address": address, "privateKey": keyPair.toWIF() }; return wallet; } catch(err){ // show error console.error(err); return false; } }; let encrypt = (privateKey, passphrase) => { try{ // validate private key and passphrase if(privateKey === ""){ throw new Error("Invalid private key"); } if(passphrase === ""){ throw new Error("Invalid passphrase"); } // encrypt key let decoded = wif.decode(privateKey); let decodedPK = decoded.privateKey; let compressed = decoded.compressed; let encryptedKey = bip38.encrypt(decodedPK, compressed, passphrase); // return encrypted key return encryptedKey; } catch(err){ // show error console.error(err); return false; } }; let decrypt = (encryptedKey, passphrase, consoleLog = false) => { try { // validate encrypte key and passphrase if(encryptedKey === ""){ throw new Error("Invalid encrypted key"); } if(passphrase === ""){ throw new Error("Invalid passphrase"); } // decrypt key let decryptedKey = bip38.decrypt(encryptedKey,passphrase,function(status){ if(consoleLog){ console.log(status.percent.toFixed(2)); } }); // return wif private key return wif.encode(0x80, decryptedKey.privateKey, decryptedKey.compressed); } catch(err){ // show error console.error(err); return false; } }; // export functions module.exports = { checkAddress: checkAddress, create: create, createSeed: createSeed, createBrainWallet: createBrainWallet, createMultiSig: createMultiSig, decrypt: decrypt, encrypt: encrypt, generateMnemonic: generateMnemonic, getPublicKeyHex: getPublicKeyHex, recoverAddress: recoverAddress, recoverSeed: recoverSeed, validateAddress: validateAddress, validateMnemonic: validateMnemonic };