Files
bip39/src/js/index.js
Ian Coleman ea2cb91a49 Tidy up split phrase warning
Make red only when danger is present
Align neatly with the rest of the UI
Increase size of text area to show all three rows, although it still
overflows on 24 words.
2019-11-11 11:04:23 +11:00

3253 lines
106 KiB
JavaScript

(function() {
// mnemonics is populated as required by getLanguage
var mnemonics = { "english": new Mnemonic("english") };
var mnemonic = mnemonics["english"];
var seed = null;
var bip32RootKey = null;
var bip32ExtendedKey = null;
var network = bitcoinjs.bitcoin.networks.bitcoin;
var addressRowTemplate = $("#address-row-template");
var showIndex = true;
var showAddress = true;
var showPubKey = true;
var showPrivKey = true;
var showQr = false;
var litecoinUseLtub = true;
var isDefaultBip44ChangeValue = true;
var entropyChangeTimeoutEvent = null;
var phraseChangeTimeoutEvent = null;
var rootKeyChangedTimeoutEvent = null;
var generationProcesses = [];
var DOM = {};
DOM.privacyScreenToggle = $(".privacy-screen-toggle");
DOM.network = $(".network");
DOM.bip32Client = $("#bip32-client");
DOM.phraseNetwork = $("#network-phrase");
DOM.useEntropy = $(".use-entropy");
DOM.entropyContainer = $(".entropy-container");
DOM.entropy = $(".entropy");
DOM.entropyFiltered = DOM.entropyContainer.find(".filtered");
DOM.entropyType = DOM.entropyContainer.find(".type");
DOM.entropyCrackTime = DOM.entropyContainer.find(".crack-time");
DOM.entropyEventCount = DOM.entropyContainer.find(".event-count");
DOM.entropyBits = DOM.entropyContainer.find(".bits");
DOM.entropyBitsPerEvent = DOM.entropyContainer.find(".bits-per-event");
DOM.entropyWordCount = DOM.entropyContainer.find(".word-count");
DOM.entropyBinary = DOM.entropyContainer.find(".binary");
DOM.entropyWordIndexes = DOM.entropyContainer.find(".word-indexes");
DOM.entropyChecksum = DOM.entropyContainer.find(".checksum");
DOM.entropyMnemonicLength = DOM.entropyContainer.find(".mnemonic-length");
DOM.entropyWeakEntropyOverrideWarning = DOM.entropyContainer.find(".weak-entropy-override-warning");
DOM.entropyFilterWarning = DOM.entropyContainer.find(".filter-warning");
DOM.phrase = $(".phrase");
DOM.splitPhrase = $(".phraseSplit");
DOM.phraseSplitWarn = $(".phraseSplitWarn");
DOM.passphrase = $(".passphrase");
DOM.generateContainer = $(".generate-container");
DOM.generate = $(".generate");
DOM.seed = $(".seed");
DOM.rootKey = $(".root-key");
DOM.litecoinLtubContainer = $(".litecoin-ltub-container");
DOM.litecoinUseLtub = $(".litecoin-use-ltub");
DOM.extendedPrivKey = $(".extended-priv-key");
DOM.extendedPubKey = $(".extended-pub-key");
DOM.bip32tab = $("#bip32-tab");
DOM.bip44tab = $("#bip44-tab");
DOM.bip49tab = $("#bip49-tab");
DOM.bip84tab = $("#bip84-tab");
DOM.bip141tab = $("#bip141-tab");
DOM.bip32panel = $("#bip32");
DOM.bip44panel = $("#bip44");
DOM.bip49panel = $("#bip49");
DOM.bip32path = $("#bip32-path");
DOM.bip44path = $("#bip44-path");
DOM.bip44purpose = $("#bip44 .purpose");
DOM.bip44coin = $("#bip44 .coin");
DOM.bip44account = $("#bip44 .account");
DOM.bip44accountXprv = $("#bip44 .account-xprv");
DOM.bip44accountXpub = $("#bip44 .account-xpub");
DOM.bip44change = $("#bip44 .change");
DOM.defaultBip44ChangeValue = $("#bip44 .default-bip44-change-value");
DOM.bip49unavailable = $("#bip49 .unavailable");
DOM.bip49available = $("#bip49 .available");
DOM.bip49path = $("#bip49-path");
DOM.bip49purpose = $("#bip49 .purpose");
DOM.bip49coin = $("#bip49 .coin");
DOM.bip49account = $("#bip49 .account");
DOM.bip49accountXprv = $("#bip49 .account-xprv");
DOM.bip49accountXpub = $("#bip49 .account-xpub");
DOM.bip49change = $("#bip49 .change");
DOM.bip84unavailable = $("#bip84 .unavailable");
DOM.bip84available = $("#bip84 .available");
DOM.bip84path = $("#bip84-path");
DOM.bip84purpose = $("#bip84 .purpose");
DOM.bip84coin = $("#bip84 .coin");
DOM.bip84account = $("#bip84 .account");
DOM.bip84accountXprv = $("#bip84 .account-xprv");
DOM.bip84accountXpub = $("#bip84 .account-xpub");
DOM.bip84change = $("#bip84 .change");
DOM.bip141unavailable = $("#bip141 .unavailable");
DOM.bip141available = $("#bip141 .available");
DOM.bip141path = $("#bip141-path");
DOM.bip141semantics = $(".bip141-semantics");
DOM.generatedStrength = $(".generate-container .strength");
DOM.generatedStrengthWarning = $(".generate-container .warning");
DOM.hardenedAddresses = $(".hardened-addresses");
DOM.bitcoinCashAddressTypeContainer = $(".bch-addr-type-container");
DOM.bitcoinCashAddressType = $("[name=bch-addr-type]")
DOM.useBip38 = $(".use-bip38");
DOM.bip38Password = $(".bip38-password");
DOM.addresses = $(".addresses");
DOM.csvTab = $("#csv-tab a");
DOM.csv = $(".csv");
DOM.rowsToAdd = $(".rows-to-add");
DOM.more = $(".more");
DOM.moreRowsStartIndex = $(".more-rows-start-index");
DOM.feedback = $(".feedback");
DOM.tab = $(".derivation-type a");
DOM.indexToggle = $(".index-toggle");
DOM.addressToggle = $(".address-toggle");
DOM.publicKeyToggle = $(".public-key-toggle");
DOM.privateKeyToggle = $(".private-key-toggle");
DOM.languages = $(".languages a");
DOM.qrContainer = $(".qr-container");
DOM.qrHider = DOM.qrContainer.find(".qr-hider");
DOM.qrImage = DOM.qrContainer.find(".qr-image");
DOM.qrHint = DOM.qrContainer.find(".qr-hint");
DOM.showQrEls = $("[data-show-qr]");
function init() {
// Events
DOM.privacyScreenToggle.on("change", privacyScreenToggled);
DOM.generatedStrength.on("change", generatedStrengthChanged);
DOM.network.on("change", networkChanged);
DOM.bip32Client.on("change", bip32ClientChanged);
DOM.useEntropy.on("change", setEntropyVisibility);
DOM.entropy.on("input", delayedEntropyChanged);
DOM.entropyMnemonicLength.on("change", entropyChanged);
DOM.phrase.on("input", delayedPhraseChanged);
DOM.passphrase.on("input", delayedPhraseChanged);
DOM.generate.on("click", generateClicked);
DOM.more.on("click", showMore);
DOM.rootKey.on("input", delayedRootKeyChanged);
DOM.litecoinUseLtub.on("change", litecoinUseLtubChanged);
DOM.bip32path.on("input", calcForDerivationPath);
DOM.bip44account.on("input", calcForDerivationPath);
DOM.bip44change.on("input", modifiedDefaultBip44ChangeValue);
DOM.bip44change.on("input", calcForDerivationPath);
DOM.defaultBip44ChangeValue.on("click", resetDefaultBip44ChangeValue);
DOM.bip49account.on("input", calcForDerivationPath);
DOM.bip49change.on("input", calcForDerivationPath);
DOM.bip84account.on("input", calcForDerivationPath);
DOM.bip84change.on("input", calcForDerivationPath);
DOM.bip141path.on("input", calcForDerivationPath);
DOM.bip141semantics.on("change", tabChanged);
DOM.tab.on("shown.bs.tab", tabChanged);
DOM.hardenedAddresses.on("change", calcForDerivationPath);
DOM.useBip38.on("change", calcForDerivationPath);
DOM.bip38Password.on("change", calcForDerivationPath);
DOM.indexToggle.on("click", toggleIndexes);
DOM.addressToggle.on("click", toggleAddresses);
DOM.publicKeyToggle.on("click", togglePublicKeys);
DOM.privateKeyToggle.on("click", togglePrivateKeys);
DOM.csvTab.on("click", updateCsv);
DOM.languages.on("click", languageChanged);
DOM.bitcoinCashAddressType.on("change", bitcoinCashAddressTypeChange);
setQrEvents(DOM.showQrEls);
disableForms();
hidePending();
hideValidationError();
populateNetworkSelect();
populateClientSelect();
}
// Event handlers
function generatedStrengthChanged() {
var strength = parseInt(DOM.generatedStrength.val());
if (strength < 12) {
DOM.generatedStrengthWarning.removeClass("hidden");
}
else {
DOM.generatedStrengthWarning.addClass("hidden");
}
}
function networkChanged(e) {
clearDerivedKeys();
clearAddressesList();
DOM.litecoinLtubContainer.addClass("hidden");
DOM.bitcoinCashAddressTypeContainer.addClass("hidden");
var networkIndex = e.target.value;
var network = networks[networkIndex];
network.onSelect();
adjustNetworkForSegwit();
if (seed != null) {
phraseChanged();
}
else {
rootKeyChanged();
}
}
function bip32ClientChanged(e) {
var clientIndex = DOM.bip32Client.val();
if (clientIndex == "custom") {
DOM.bip32path.prop("readonly", false);
}
else {
DOM.bip32path.prop("readonly", true);
clients[clientIndex].onSelect();
if (seed != null) {
phraseChanged();
}
else {
rootKeyChanged();
}
}
}
function setEntropyVisibility() {
if (isUsingOwnEntropy()) {
DOM.entropyContainer.removeClass("hidden");
DOM.generateContainer.addClass("hidden");
DOM.phrase.prop("readonly", true);
DOM.entropy.focus();
entropyChanged();
}
else {
DOM.entropyContainer.addClass("hidden");
DOM.generateContainer.removeClass("hidden");
DOM.phrase.prop("readonly", false);
hidePending();
}
}
function delayedPhraseChanged() {
hideValidationError();
seed = null;
bip32RootKey = null;
bip32ExtendedKey = null;
clearAddressesList();
showPending();
if (phraseChangeTimeoutEvent != null) {
clearTimeout(phraseChangeTimeoutEvent);
}
phraseChangeTimeoutEvent = setTimeout(function() {
phraseChanged();
var entropy = mnemonic.toRawEntropyBin(DOM.phrase.val());
if (entropy !== null) {
DOM.entropyMnemonicLength.val("raw");
DOM.entropy.val(entropy);
}
}, 400);
}
function phraseChanged() {
showPending();
setMnemonicLanguage();
// Get the mnemonic phrase
var phrase = DOM.phrase.val();
var errorText = findPhraseErrors(phrase);
if (errorText) {
showValidationError(errorText);
return;
}
// Calculate and display
var passphrase = DOM.passphrase.val();
calcBip32RootKeyFromSeed(phrase, passphrase);
calcForDerivationPath();
// Show the word indexes
showWordIndexes();
writeSplitPhrase(phrase);
}
function tabChanged() {
showPending();
adjustNetworkForSegwit();
var phrase = DOM.phrase.val();
if (phrase != "") {
// Calculate and display for mnemonic
var errorText = findPhraseErrors(phrase);
if (errorText) {
showValidationError(errorText);
return;
}
// Calculate and display
var passphrase = DOM.passphrase.val();
calcBip32RootKeyFromSeed(phrase, passphrase);
}
else {
// Calculate and display for root key
var rootKeyBase58 = DOM.rootKey.val();
var errorText = validateRootKey(rootKeyBase58);
if (errorText) {
showValidationError(errorText);
return;
}
// Calculate and display
calcBip32RootKeyFromBase58(rootKeyBase58);
}
calcForDerivationPath();
}
function delayedEntropyChanged() {
hideValidationError();
showPending();
if (entropyChangeTimeoutEvent != null) {
clearTimeout(entropyChangeTimeoutEvent);
}
entropyChangeTimeoutEvent = setTimeout(entropyChanged, 400);
}
function entropyChanged() {
// If blank entropy, clear mnemonic, addresses, errors
if (DOM.entropy.val().trim().length == 0) {
clearDisplay();
clearEntropyFeedback();
DOM.phrase.val("");
DOM.phraseSplit.val("");
showValidationError("Blank entropy");
return;
}
// Get the current phrase to detect changes
var phrase = DOM.phrase.val();
// Set the phrase from the entropy
setMnemonicFromEntropy();
// Recalc addresses if the phrase has changed
var newPhrase = DOM.phrase.val();
if (newPhrase != phrase) {
if (newPhrase.length == 0) {
clearDisplay();
}
else {
phraseChanged();
}
}
else {
hidePending();
}
}
function delayedRootKeyChanged() {
// Warn if there is an existing mnemonic or passphrase.
if (DOM.phrase.val().length > 0 || DOM.passphrase.val().length > 0) {
if (!confirm("This will clear existing mnemonic and passphrase")) {
DOM.rootKey.val(bip32RootKey);
return
}
}
hideValidationError();
showPending();
// Clear existing mnemonic and passphrase
DOM.phrase.val("");
DOM.phraseSplit.val("");
DOM.passphrase.val("");
seed = null;
if (rootKeyChangedTimeoutEvent != null) {
clearTimeout(rootKeyChangedTimeoutEvent);
}
rootKeyChangedTimeoutEvent = setTimeout(rootKeyChanged, 400);
}
function rootKeyChanged() {
showPending();
hideValidationError();
var rootKeyBase58 = DOM.rootKey.val();
var errorText = validateRootKey(rootKeyBase58);
if (errorText) {
showValidationError(errorText);
return;
}
// Calculate and display
calcBip32RootKeyFromBase58(rootKeyBase58);
calcForDerivationPath();
}
function litecoinUseLtubChanged() {
litecoinUseLtub = DOM.litecoinUseLtub.prop("checked");
if (litecoinUseLtub) {
network = bitcoinjs.bitcoin.networks.litecoin;
}
else {
network = bitcoinjs.bitcoin.networks.litecoinXprv;
}
phraseChanged();
}
function calcForDerivationPath() {
clearDerivedKeys();
clearAddressesList();
showPending();
// Don't show segwit if it's selected but network doesn't support it
if (segwitSelected() && !networkHasSegwit()) {
showSegwitUnavailable();
hidePending();
return;
}
showSegwitAvailable();
// Get the derivation path
var derivationPath = getDerivationPath();
var errorText = findDerivationPathErrors(derivationPath);
if (errorText) {
showValidationError(errorText);
return;
}
bip32ExtendedKey = calcBip32ExtendedKey(derivationPath);
if (bip44TabSelected()) {
displayBip44Info();
}
else if (bip49TabSelected()) {
displayBip49Info();
}
else if (bip84TabSelected()) {
displayBip84Info();
}
displayBip32Info();
}
function generateClicked() {
if (isUsingOwnEntropy()) {
return;
}
clearDisplay();
showPending();
setTimeout(function() {
setMnemonicLanguage();
var phrase = generateRandomPhrase();
if (!phrase) {
return;
}
phraseChanged();
}, 50);
}
function languageChanged() {
setTimeout(function() {
setMnemonicLanguage();
if (DOM.phrase.val().length > 0) {
var newPhrase = convertPhraseToNewLanguage();
DOM.phrase.val(newPhrase);
phraseChanged();
}
else {
DOM.generate.trigger("click");
}
}, 50);
}
function bitcoinCashAddressTypeChange() {
phraseChanged();
}
function toggleIndexes() {
showIndex = !showIndex;
$("td.index span").toggleClass("invisible");
}
function toggleAddresses() {
showAddress = !showAddress;
$("td.address span").toggleClass("invisible");
}
function togglePublicKeys() {
showPubKey = !showPubKey;
$("td.pubkey span").toggleClass("invisible");
}
function togglePrivateKeys() {
showPrivKey = !showPrivKey;
$("td.privkey span").toggleClass("invisible");
}
function privacyScreenToggled() {
// private-data contains elements added to DOM at runtime
// so catch all by adding visual privacy class to the root of the DOM
if (DOM.privacyScreenToggle.prop("checked")) {
$("body").addClass("visual-privacy");
}
else {
$("body").removeClass("visual-privacy");
}
}
// Private methods
function generateRandomPhrase() {
if (!hasStrongRandom()) {
var errorText = "This browser does not support strong randomness";
showValidationError(errorText);
return;
}
// get the amount of entropy to use
var numWords = parseInt(DOM.generatedStrength.val());
var strength = numWords / 3 * 32;
var buffer = new Uint8Array(strength / 8);
// create secure entropy
var data = crypto.getRandomValues(buffer);
// show the words
var words = mnemonic.toMnemonic(data);
DOM.phrase.val(words);
// show the entropy
var entropyHex = uint8ArrayToHex(data);
DOM.entropy.val(entropyHex);
// ensure entropy fields are consistent with what is being displayed
DOM.entropyMnemonicLength.val("raw");
return words;
}
function calcBip32RootKeyFromSeed(phrase, passphrase) {
seed = mnemonic.toSeed(phrase, passphrase);
bip32RootKey = bitcoinjs.bitcoin.HDNode.fromSeedHex(seed, network);
if(isGRS())
bip32RootKey = groestlcoinjs.HDNode.fromSeedHex(seed, network);
}
function calcBip32RootKeyFromBase58(rootKeyBase58) {
if(isGRS()) {
calcBip32RootKeyFromBase58GRS(rootKeyBase58);
return;
}
// try parsing with various segwit network params since this extended
// key may be from any one of them.
if (networkHasSegwit()) {
var n = network;
if ("baseNetwork" in n) {
n = bitcoinjs.bitcoin.networks[n.baseNetwork];
}
// try parsing using base network params
try {
bip32RootKey = bitcoinjs.bitcoin.HDNode.fromBase58(rootKeyBase58, n);
return;
}
catch (e) {}
// try parsing using p2wpkh params
if ("p2wpkh" in n) {
try {
bip32RootKey = bitcoinjs.bitcoin.HDNode.fromBase58(rootKeyBase58, n.p2wpkh);
return;
}
catch (e) {}
}
// try parsing using p2wpkh-in-p2sh network params
if ("p2wpkhInP2sh" in n) {
try {
bip32RootKey = bitcoinjs.bitcoin.HDNode.fromBase58(rootKeyBase58, n.p2wpkhInP2sh);
return;
}
catch (e) {}
}
}
// try the network params as currently specified
bip32RootKey = bitcoinjs.bitcoin.HDNode.fromBase58(rootKeyBase58, network);
}
function calcBip32RootKeyFromBase58GRS(rootKeyBase58) {
// try parsing with various segwit network params since this extended
// key may be from any one of them.
if (networkHasSegwit()) {
var n = network;
if ("baseNetwork" in n) {
n = bitcoinjs.bitcoin.networks[n.baseNetwork];
}
// try parsing using base network params
try {
bip32RootKey = groestlcoinjs.HDNode.fromBase58(rootKeyBase58, n);
return;
}
catch (e) {}
// try parsing using p2wpkh params
if ("p2wpkh" in n) {
try {
bip32RootKey = groestlcoinjs.HDNode.fromBase58(rootKeyBase58, n.p2wpkh);
return;
}
catch (e) {}
}
// try parsing using p2wpkh-in-p2sh network params
if ("p2wpkhInP2sh" in n) {
try {
bip32RootKey = groestlcoinjs.HDNode.fromBase58(rootKeyBase58, n.p2wpkhInP2sh);
return;
}
catch (e) {}
}
}
// try the network params as currently specified
bip32RootKey = groestlcoinjs.HDNode.fromBase58(rootKeyBase58, network);
}
function calcBip32ExtendedKey(path) {
// Check there's a root key to derive from
if (!bip32RootKey) {
return bip32RootKey;
}
var extendedKey = bip32RootKey;
// Derive the key from the path
var pathBits = path.split("/");
for (var i=0; i<pathBits.length; i++) {
var bit = pathBits[i];
var index = parseInt(bit);
if (isNaN(index)) {
continue;
}
var hardened = bit[bit.length-1] == "'";
var isPriv = !(extendedKey.isNeutered());
var invalidDerivationPath = hardened && !isPriv;
if (invalidDerivationPath) {
extendedKey = null;
}
else if (hardened) {
extendedKey = extendedKey.deriveHardened(index);
}
else {
extendedKey = extendedKey.derive(index);
}
}
return extendedKey;
}
function showValidationError(errorText) {
DOM.feedback
.text(errorText)
.show();
}
function hideValidationError() {
DOM.feedback
.text("")
.hide();
}
function findPhraseErrors(phrase) {
// Preprocess the words
phrase = mnemonic.normalizeString(phrase);
var words = phraseToWordArray(phrase);
// Detect blank phrase
if (words.length == 0) {
return "Blank mnemonic";
}
// Check each word
for (var i=0; i<words.length; i++) {
var word = words[i];
var language = getLanguage();
if (WORDLISTS[language].indexOf(word) == -1) {
console.log("Finding closest match to " + word);
var nearestWord = findNearestWord(word);
return word + " not in wordlist, did you mean " + nearestWord + "?";
}
}
// Check the words are valid
var properPhrase = wordArrayToPhrase(words);
var isValid = mnemonic.check(properPhrase);
if (!isValid) {
return "Invalid mnemonic";
}
return false;
}
function validateRootKey(rootKeyBase58) {
if(isGRS())
return validateRootKeyGRS(rootKeyBase58);
// try various segwit network params since this extended key may be from
// any one of them.
if (networkHasSegwit()) {
var n = network;
if ("baseNetwork" in n) {
n = bitcoinjs.bitcoin.networks[n.baseNetwork];
}
// try parsing using base network params
try {
bitcoinjs.bitcoin.HDNode.fromBase58(rootKeyBase58, n);
return "";
}
catch (e) {}
// try parsing using p2wpkh params
if ("p2wpkh" in n) {
try {
bitcoinjs.bitcoin.HDNode.fromBase58(rootKeyBase58, n.p2wpkh);
return "";
}
catch (e) {}
}
// try parsing using p2wpkh-in-p2sh network params
if ("p2wpkhInP2sh" in n) {
try {
bitcoinjs.bitcoin.HDNode.fromBase58(rootKeyBase58, n.p2wpkhInP2sh);
return "";
}
catch (e) {}
}
}
// try the network params as currently specified
try {
bitcoinjs.bitcoin.HDNode.fromBase58(rootKeyBase58, network);
}
catch (e) {
return "Invalid root key";
}
return "";
}
function validateRootKeyGRS(rootKeyBase58) {
// try various segwit network params since this extended key may be from
// any one of them.
if (networkHasSegwit()) {
var n = network;
if ("baseNetwork" in n) {
n = bitcoinjs.bitcoin.networks[n.baseNetwork];
}
// try parsing using base network params
try {
groestlcoinjs.HDNode.fromBase58(rootKeyBase58, n);
return "";
}
catch (e) {}
// try parsing using p2wpkh params
if ("p2wpkh" in n) {
try {
groestlcoinjs.HDNode.fromBase58(rootKeyBase58, n.p2wpkh);
return "";
}
catch (e) {}
}
// try parsing using p2wpkh-in-p2sh network params
if ("p2wpkhInP2sh" in n) {
try {
groestlcoinjs.HDNode.fromBase58(rootKeyBase58, n.p2wpkhInP2sh);
return "";
}
catch (e) {}
}
}
// try the network params as currently specified
try {
groestlcoinjs.HDNode.fromBase58(rootKeyBase58, network);
}
catch (e) {
return "Invalid root key";
}
return "";
}
function getDerivationPath() {
if (bip44TabSelected()) {
var purpose = parseIntNoNaN(DOM.bip44purpose.val(), 44);
var coin = parseIntNoNaN(DOM.bip44coin.val(), 0);
var account = parseIntNoNaN(DOM.bip44account.val(), 0);
var change = parseIntNoNaN(DOM.bip44change.val(), "");
var path = "m";
path += "/" + purpose + "'";
path += "/" + coin + "'";
path += "/" + account + "'";
if (change !== "") {
path += "/" + change;
}
DOM.bip44path.val(path);
var derivationPath = DOM.bip44path.val();
console.log("Using derivation path from BIP44 tab: " + derivationPath);
return derivationPath;
}
else if (bip49TabSelected()) {
var purpose = parseIntNoNaN(DOM.bip49purpose.val(), 49);
var coin = parseIntNoNaN(DOM.bip49coin.val(), 0);
var account = parseIntNoNaN(DOM.bip49account.val(), 0);
var change = parseIntNoNaN(DOM.bip49change.val(), 0);
var path = "m/";
path += purpose + "'/";
path += coin + "'/";
path += account + "'/";
path += change;
DOM.bip49path.val(path);
var derivationPath = DOM.bip49path.val();
console.log("Using derivation path from BIP49 tab: " + derivationPath);
return derivationPath;
}
else if (bip84TabSelected()) {
var purpose = parseIntNoNaN(DOM.bip84purpose.val(), 84);
var coin = parseIntNoNaN(DOM.bip84coin.val(), 0);
var account = parseIntNoNaN(DOM.bip84account.val(), 0);
var change = parseIntNoNaN(DOM.bip84change.val(), 0);
var path = "m/";
path += purpose + "'/";
path += coin + "'/";
path += account + "'/";
path += change;
DOM.bip84path.val(path);
var derivationPath = DOM.bip84path.val();
console.log("Using derivation path from BIP84 tab: " + derivationPath);
return derivationPath;
}
else if (bip32TabSelected()) {
var derivationPath = DOM.bip32path.val();
console.log("Using derivation path from BIP32 tab: " + derivationPath);
return derivationPath;
}
else if (bip141TabSelected()) {
var derivationPath = DOM.bip141path.val();
console.log("Using derivation path from BIP141 tab: " + derivationPath);
return derivationPath;
}
else {
console.log("Unknown derivation path");
}
}
function findDerivationPathErrors(path) {
// TODO is not perfect but is better than nothing
// Inspired by
// https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#test-vectors
// and
// https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#extended-keys
var maxDepth = 255; // TODO verify this!!
var maxIndexValue = Math.pow(2, 31); // TODO verify this!!
if (path[0] != "m") {
return "First character must be 'm'";
}
if (path.length > 1) {
if (path[1] != "/") {
return "Separator must be '/'";
}
var indexes = path.split("/");
if (indexes.length > maxDepth) {
return "Derivation depth is " + indexes.length + ", must be less than " + maxDepth;
}
for (var depth = 1; depth<indexes.length; depth++) {
var index = indexes[depth];
var invalidChars = index.replace(/^[0-9]+'?$/g, "")
if (invalidChars.length > 0) {
return "Invalid characters " + invalidChars + " found at depth " + depth;
}
var indexValue = parseInt(index.replace("'", ""));
if (isNaN(depth)) {
return "Invalid number at depth " + depth;
}
if (indexValue > maxIndexValue) {
return "Value of " + indexValue + " at depth " + depth + " must be less than " + maxIndexValue;
}
}
}
// Check root key exists or else derivation path is useless!
if (!bip32RootKey) {
return "No root key";
}
// Check no hardened derivation path when using xpub keys
var hardenedPath = path.indexOf("'") > -1;
var hardenedAddresses = bip32TabSelected() && DOM.hardenedAddresses.prop("checked");
var hardened = hardenedPath || hardenedAddresses;
var isXpubkey = bip32RootKey.isNeutered();
if (hardened && isXpubkey) {
return "Hardened derivation path is invalid with xpub key";
}
return false;
}
function isGRS() {
return networks[DOM.network.val()].name == "GRS - Groestlcoin" || networks[DOM.network.val()].name == "GRS - Groestlcoin Testnet";
}
function isELA() {
return networks[DOM.network.val()].name == "ELA - Elastos"
}
function displayBip44Info() {
// Get the derivation path for the account
var purpose = parseIntNoNaN(DOM.bip44purpose.val(), 44);
var coin = parseIntNoNaN(DOM.bip44coin.val(), 0);
var account = parseIntNoNaN(DOM.bip44account.val(), 0);
var path = "m/";
path += purpose + "'/";
path += coin + "'/";
path += account + "'/";
// Calculate the account extended keys
var accountExtendedKey = calcBip32ExtendedKey(path);
var accountXprv = accountExtendedKey.toBase58();
var accountXpub = accountExtendedKey.neutered().toBase58();
// Display the extended keys
DOM.bip44accountXprv.val(accountXprv);
DOM.bip44accountXpub.val(accountXpub);
if (isELA()) {
displayBip44InfoForELA();
}
}
function displayBip49Info() {
// Get the derivation path for the account
var purpose = parseIntNoNaN(DOM.bip49purpose.val(), 49);
var coin = parseIntNoNaN(DOM.bip49coin.val(), 0);
var account = parseIntNoNaN(DOM.bip49account.val(), 0);
var path = "m/";
path += purpose + "'/";
path += coin + "'/";
path += account + "'/";
// Calculate the account extended keys
var accountExtendedKey = calcBip32ExtendedKey(path);
var accountXprv = accountExtendedKey.toBase58();
var accountXpub = accountExtendedKey.neutered().toBase58();
// Display the extended keys
DOM.bip49accountXprv.val(accountXprv);
DOM.bip49accountXpub.val(accountXpub);
}
function displayBip84Info() {
// Get the derivation path for the account
var purpose = parseIntNoNaN(DOM.bip84purpose.val(), 84);
var coin = parseIntNoNaN(DOM.bip84coin.val(), 0);
var account = parseIntNoNaN(DOM.bip84account.val(), 0);
var path = "m/";
path += purpose + "'/";
path += coin + "'/";
path += account + "'/";
// Calculate the account extended keys
var accountExtendedKey = calcBip32ExtendedKey(path);
var accountXprv = accountExtendedKey.toBase58();
var accountXpub = accountExtendedKey.neutered().toBase58();
// Display the extended keys
DOM.bip84accountXprv.val(accountXprv);
DOM.bip84accountXpub.val(accountXpub);
}
function displayBip32Info() {
// Display the key
DOM.seed.val(seed);
var rootKey = bip32RootKey.toBase58();
DOM.rootKey.val(rootKey);
var xprvkeyB58 = "NA";
if (!bip32ExtendedKey.isNeutered()) {
xprvkeyB58 = bip32ExtendedKey.toBase58();
}
var extendedPrivKey = xprvkeyB58;
DOM.extendedPrivKey.val(extendedPrivKey);
var extendedPubKey = bip32ExtendedKey.neutered().toBase58();
DOM.extendedPubKey.val(extendedPubKey);
// Display the addresses and privkeys
clearAddressesList();
var initialAddressCount = parseInt(DOM.rowsToAdd.val());
displayAddresses(0, initialAddressCount);
if (isELA()) {
displayBip32InfoForELA();
}
}
function displayAddresses(start, total) {
generationProcesses.push(new (function() {
var rows = [];
this.stop = function() {
for (var i=0; i<rows.length; i++) {
rows[i].shouldGenerate = false;
}
hidePending();
}
for (var i=0; i<total; i++) {
var index = i + start;
var isLast = i == total - 1;
rows.push(new TableRow(index, isLast));
}
})());
}
function segwitSelected() {
return bip49TabSelected() || bip84TabSelected() || bip141TabSelected();
}
function p2wpkhSelected() {
return bip84TabSelected() ||
bip141TabSelected() && DOM.bip141semantics.val() == "p2wpkh";
}
function p2wpkhInP2shSelected() {
return bip49TabSelected() ||
(bip141TabSelected() && DOM.bip141semantics.val() == "p2wpkh-p2sh");
}
function TableRow(index, isLast) {
var self = this;
this.shouldGenerate = true;
var useHardenedAddresses = DOM.hardenedAddresses.prop("checked");
var useBip38 = DOM.useBip38.prop("checked");
var bip38password = DOM.bip38Password.val();
var isSegwit = segwitSelected();
var segwitAvailable = networkHasSegwit();
var isP2wpkh = p2wpkhSelected();
var isP2wpkhInP2sh = p2wpkhInP2shSelected();
function init() {
calculateValues();
}
function calculateValues() {
setTimeout(function() {
if (!self.shouldGenerate) {
return;
}
// derive HDkey for this row of the table
var key = "NA";
if (useHardenedAddresses) {
key = bip32ExtendedKey.deriveHardened(index);
}
else {
key = bip32ExtendedKey.derive(index);
}
// bip38 requires uncompressed keys
// see https://github.com/iancoleman/bip39/issues/140#issuecomment-352164035
var keyPair = key.keyPair;
var useUncompressed = useBip38;
if (useUncompressed) {
keyPair = new bitcoinjs.bitcoin.ECPair(keyPair.d, null, { network: network, compressed: false });
if(isGRS())
keyPair = new groestlcoinjs.ECPair(keyPair.d, null, { network: network, compressed: false });
}
// get address
var address = keyPair.getAddress().toString();
// get privkey
var hasPrivkey = !key.isNeutered();
var privkey = "NA";
if (hasPrivkey) {
privkey = keyPair.toWIF();
// BIP38 encode private key if required
if (useBip38) {
if(isGRS())
privkey = groestlcoinjsBip38.encrypt(keyPair.d.toBuffer(), false, bip38password, function(p) {
console.log("Progressed " + p.percent.toFixed(1) + "% for index " + index);
}, null, networks[DOM.network.val()].name.includes("Testnet"));
else
privkey = bitcoinjsBip38.encrypt(keyPair.d.toBuffer(), false, bip38password, function(p) {
console.log("Progressed " + p.percent.toFixed(1) + "% for index " + index);
});
}
}
// get pubkey
var pubkey = keyPair.getPublicKeyBuffer().toString('hex');
var indexText = getDerivationPath() + "/" + index;
if (useHardenedAddresses) {
indexText = indexText + "'";
}
// Ethereum values are different
if (networkIsEthereum()) {
var privKeyBuffer = keyPair.d.toBuffer(32);
privkey = privKeyBuffer.toString('hex');
var addressBuffer = ethUtil.privateToAddress(privKeyBuffer);
var hexAddress = addressBuffer.toString('hex');
var checksumAddress = ethUtil.toChecksumAddress(hexAddress);
address = ethUtil.addHexPrefix(checksumAddress);
privkey = ethUtil.addHexPrefix(privkey);
pubkey = ethUtil.addHexPrefix(pubkey);
}
// Stellar is different
if (networks[DOM.network.val()].name == "XLM - Stellar") {
var purpose = parseIntNoNaN(DOM.bip44purpose.val(), 44);
var coin = parseIntNoNaN(DOM.bip44coin.val(), 0);
var path = "m/";
path += purpose + "'/";
path += coin + "'/" + index + "'";
var keypair = stellarUtil.getKeypair(path, seed);
indexText = path;
privkey = keypair.secret();
pubkey = address = keypair.publicKey();
}
if ((networks[DOM.network.val()].name == "NAS - Nebulas")) {
var NasAccount = require("nebulas-account");
var privKeyBuffer = keyPair.d.toBuffer(32);
var nebulasAccount = new NasAccount();
nebulasAccount.setPrivateKey(privKeyBuffer);
address = nebulasAccount.getAddressString();
privkey = nebulasAccount.getPrivateKeyString();
pubkey = nebulasAccount.getPublicKeyString();
}
// Ripple values are different
if (networks[DOM.network.val()].name == "XRP - Ripple") {
privkey = convertRipplePriv(privkey);
address = convertRippleAdrr(address);
}
// CasinoCoin values are different
if (networks[DOM.network.val()].name == "CSC - CasinoCoin") {
privkey = convertCasinoCoinPriv(privkey);
address = convertCasinoCoinAdrr(address);
}
// Bitcoin Cash address format may vary
if (networks[DOM.network.val()].name == "BCH - Bitcoin Cash") {
var bchAddrType = DOM.bitcoinCashAddressType.filter(":checked").val();
if (bchAddrType == "cashaddr") {
address = bchaddr.toCashAddress(address);
}
else if (bchAddrType == "bitpay") {
address = bchaddr.toBitpayAddress(address);
}
}
// Bitcoin Cash address format may vary
if (networks[DOM.network.val()].name == "SLP - Simple Ledger Protocol") {
var bchAddrType = DOM.bitcoinCashAddressType.filter(":checked").val();
if (bchAddrType == "cashaddr") {
address = bchaddr.toSlpAddress(address);
}
}
// Segwit addresses are different
if (isSegwit) {
if (!segwitAvailable) {
return;
}
if (isP2wpkh) {
var keyhash = bitcoinjs.bitcoin.crypto.hash160(key.getPublicKeyBuffer());
var scriptpubkey = bitcoinjs.bitcoin.script.witnessPubKeyHash.output.encode(keyhash);
address = bitcoinjs.bitcoin.address.fromOutputScript(scriptpubkey, network)
}
else if (isP2wpkhInP2sh) {
var keyhash = bitcoinjs.bitcoin.crypto.hash160(key.getPublicKeyBuffer());
var scriptsig = bitcoinjs.bitcoin.script.witnessPubKeyHash.output.encode(keyhash);
var addressbytes = bitcoinjs.bitcoin.crypto.hash160(scriptsig);
var scriptpubkey = bitcoinjs.bitcoin.script.scriptHash.output.encode(addressbytes);
address = bitcoinjs.bitcoin.address.fromOutputScript(scriptpubkey, network)
}
}
if ((networks[DOM.network.val()].name == "CRW - Crown")) {
address = bitcoinjs.bitcoin.networks.crown.toNewAddress(address);
}
if (networks[DOM.network.val()].name == "EOS - EOSIO") {
address = ""
pubkey = eosUtil.bufferToPublic(keyPair.getPublicKeyBuffer());
privkey = eosUtil.bufferToPrivate(keyPair.d.toBuffer(32));
}
//Groestlcoin Addresses are different
if(isGRS()) {
if (isSegwit) {
if (!segwitAvailable) {
return;
}
if (isP2wpkh) {
address = groestlcoinjs.address.fromOutputScript(scriptpubkey, network)
}
else if (isP2wpkhInP2sh) {
address = groestlcoinjs.address.fromOutputScript(scriptpubkey, network)
}
}
//non-segwit addresses are handled by using groestlcoinjs for bip32RootKey
}
if (isELA()) {
let elaAddress = calcAddressForELA(
seed,
parseIntNoNaN(DOM.bip44coin.val(), 0),
parseIntNoNaN(DOM.bip44account.val(), 0),
parseIntNoNaN(DOM.bip44change.val(), 0),
index
);
address = elaAddress.address;
privkey = elaAddress.privateKey;
pubkey = elaAddress.publicKey;
}
addAddressToList(indexText, address, pubkey, privkey);
if (isLast) {
hidePending();
updateCsv();
}
}, 50)
}
init();
}
function showMore() {
var rowsToAdd = parseInt(DOM.rowsToAdd.val());
if (isNaN(rowsToAdd)) {
rowsToAdd = 20;
DOM.rowsToAdd.val("20");
}
var start = parseInt(DOM.moreRowsStartIndex.val())
if (isNaN(start)) {
start = lastIndexInTable() + 1;
}
else {
var newStart = start + rowsToAdd;
DOM.moreRowsStartIndex.val(newStart);
}
if (rowsToAdd > 200) {
var msg = "Generating " + rowsToAdd + " rows could take a while. ";
msg += "Do you want to continue?";
if (!confirm(msg)) {
return;
}
}
displayAddresses(start, rowsToAdd);
}
function clearDisplay() {
clearAddressesList();
clearKeys();
hideValidationError();
}
function clearAddressesList() {
DOM.addresses.empty();
DOM.csv.val("");
stopGenerating();
}
function stopGenerating() {
while (generationProcesses.length > 0) {
var generation = generationProcesses.shift();
generation.stop();
}
}
function clearKeys() {
clearRootKey();
clearDerivedKeys();
}
function clearRootKey() {
DOM.rootKey.val("");
}
function clearDerivedKeys() {
DOM.extendedPrivKey.val("");
DOM.extendedPubKey.val("");
DOM.bip44accountXprv.val("");
DOM.bip44accountXpub.val("");
}
function addAddressToList(indexText, address, pubkey, privkey) {
var row = $(addressRowTemplate.html());
// Elements
var indexCell = row.find(".index span");
var addressCell = row.find(".address span");
var pubkeyCell = row.find(".pubkey span");
var privkeyCell = row.find(".privkey span");
// Content
indexCell.text(indexText);
addressCell.text(address);
pubkeyCell.text(pubkey);
privkeyCell.text(privkey);
// Visibility
if (!showIndex) {
indexCell.addClass("invisible");
}
if (!showAddress) {
addressCell.addClass("invisible");
}
if (!showPubKey) {
pubkeyCell.addClass("invisible");
}
if (!showPrivKey) {
privkeyCell.addClass("invisible");
}
DOM.addresses.append(row);
var rowShowQrEls = row.find("[data-show-qr]");
setQrEvents(rowShowQrEls);
}
function hasStrongRandom() {
return 'crypto' in window && window['crypto'] !== null;
}
function disableForms() {
$("form").on("submit", function(e) {
e.preventDefault();
});
}
function parseIntNoNaN(val, defaultVal) {
var v = parseInt(val);
if (isNaN(v)) {
return defaultVal;
}
return v;
}
function showPending() {
DOM.feedback
.text("Calculating...")
.show();
}
function findNearestWord(word) {
var language = getLanguage();
var words = WORDLISTS[language];
var minDistance = 99;
var closestWord = words[0];
for (var i=0; i<words.length; i++) {
var comparedTo = words[i];
if (comparedTo.indexOf(word) == 0) {
return comparedTo;
}
var distance = Levenshtein.get(word, comparedTo);
if (distance < minDistance) {
closestWord = comparedTo;
minDistance = distance;
}
}
return closestWord;
}
function hidePending() {
DOM.feedback
.text("")
.hide();
}
function populateNetworkSelect() {
for (var i=0; i<networks.length; i++) {
var network = networks[i];
var option = $("<option>");
option.attr("value", i);
option.text(network.name);
if (network.name == "BTC - Bitcoin") {
option.prop("selected", true);
}
DOM.phraseNetwork.append(option);
}
}
function populateClientSelect() {
for (var i=0; i<clients.length; i++) {
var client = clients[i];
var option = $("<option>");
option.attr("value", i);
option.text(client.name);
DOM.bip32Client.append(option);
}
}
function getLanguage() {
var defaultLanguage = "english";
// Try to get from existing phrase
var language = getLanguageFromPhrase();
// Try to get from url if not from phrase
if (language.length == 0) {
language = getLanguageFromUrl();
}
// Default to English if no other option
if (language.length == 0) {
language = defaultLanguage;
}
return language;
}
function getLanguageFromPhrase(phrase) {
// Check if how many words from existing phrase match a language.
var language = "";
if (!phrase) {
phrase = DOM.phrase.val();
}
if (phrase.length > 0) {
var words = phraseToWordArray(phrase);
var languageMatches = {};
for (l in WORDLISTS) {
// Track how many words match in this language
languageMatches[l] = 0;
for (var i=0; i<words.length; i++) {
var wordInLanguage = WORDLISTS[l].indexOf(words[i]) > -1;
if (wordInLanguage) {
languageMatches[l]++;
}
}
// Find languages with most word matches.
// This is made difficult due to commonalities between Chinese
// simplified vs traditional.
var mostMatches = 0;
var mostMatchedLanguages = [];
for (var l in languageMatches) {
var numMatches = languageMatches[l];
if (numMatches > mostMatches) {
mostMatches = numMatches;
mostMatchedLanguages = [l];
}
else if (numMatches == mostMatches) {
mostMatchedLanguages.push(l);
}
}
}
if (mostMatchedLanguages.length > 0) {
// Use first language and warn if multiple detected
language = mostMatchedLanguages[0];
if (mostMatchedLanguages.length > 1) {
console.warn("Multiple possible languages");
console.warn(mostMatchedLanguages);
}
}
}
return language;
}
function getLanguageFromUrl() {
for (var language in WORDLISTS) {
if (window.location.hash.indexOf(language) > -1) {
return language;
}
}
return "";
}
function setMnemonicLanguage() {
var language = getLanguage();
// Load the bip39 mnemonic generator for this language if required
if (!(language in mnemonics)) {
mnemonics[language] = new Mnemonic(language);
}
mnemonic = mnemonics[language];
}
function convertPhraseToNewLanguage() {
var oldLanguage = getLanguageFromPhrase();
var newLanguage = getLanguageFromUrl();
var oldPhrase = DOM.phrase.val();
var oldWords = phraseToWordArray(oldPhrase);
var newWords = [];
for (var i=0; i<oldWords.length; i++) {
var oldWord = oldWords[i];
var index = WORDLISTS[oldLanguage].indexOf(oldWord);
var newWord = WORDLISTS[newLanguage][index];
newWords.push(newWord);
}
newPhrase = wordArrayToPhrase(newWords);
return newPhrase;
}
// TODO look at jsbip39 - mnemonic.splitWords
function phraseToWordArray(phrase) {
var words = phrase.split(/\s/g);
var noBlanks = [];
for (var i=0; i<words.length; i++) {
var word = words[i];
if (word.length > 0) {
noBlanks.push(word);
}
}
return noBlanks;
}
// TODO look at jsbip39 - mnemonic.joinWords
function wordArrayToPhrase(words) {
var phrase = words.join(" ");
var language = getLanguageFromPhrase(phrase);
if (language == "japanese") {
phrase = words.join("\u3000");
}
return phrase;
}
function writeSplitPhrase(phrase) {
var wordCount = phrase.split(/\s/g).length;
var left=[];
for (var i=0;i<wordCount;i++) left.push(i);
var group=[[],[],[]],
groupI=-1;
var seed = Math.abs(sjcl.hash.sha256.hash(phrase)[0])% 2147483647;
while (left.length>0) {
groupI=(groupI+1)%3;
seed = seed * 16807 % 2147483647;
var selected=Math.floor(left.length*(seed - 1) / 2147483646);
group[groupI].push(left[selected]);
left.splice(selected,1);
}
var cards=[phrase.split(/\s/g),phrase.split(/\s/g),phrase.split(/\s/g)];
for (var i=0;i<3;i++) {
for (var ii=0;ii<wordCount/3;ii++) cards[i][group[i][ii]]='XXXX';
cards[i]='Card '+(i+1)+': '+wordArrayToPhrase(cards[i]);
}
DOM.splitPhrase.val(cards.join("\r\n"));
var triesPerSecond=10000000000;
var hackTime=Math.pow(2,wordCount*10/3)/triesPerSecond;
var displayRedText = false;
if (hackTime<1) {
hackTime="<1 second";
displayRedText = true;
} else if (hackTime<86400) {
hackTime=Math.floor(hackTime)+" seconds";
displayRedText = true;
} else if(hackTime<31557600) {
hackTime=Math.floor(hackTime/86400)+" days";
displayRedText = true;
} else {
hackTime=Math.floor(hackTime/31557600)+" years";
}
DOM.phraseSplitWarn.html("Time to hack with only one card: "+hackTime);
if (displayRedText) {
DOM.phraseSplitWarn.addClass("text-danger");
} else {
DOM.phraseSplitWarn.removeClass("text-danger");
}
}
function isUsingOwnEntropy() {
return DOM.useEntropy.prop("checked");
}
function setMnemonicFromEntropy() {
clearEntropyFeedback();
// Get entropy value
var entropyStr = DOM.entropy.val();
// Work out minimum base for entropy
var entropy = Entropy.fromString(entropyStr);
if (entropy.binaryStr.length == 0) {
return;
}
// Show entropy details
showEntropyFeedback(entropy);
// Use entropy hash if not using raw entropy
var bits = entropy.binaryStr;
var mnemonicLength = DOM.entropyMnemonicLength.val();
if (mnemonicLength != "raw") {
// Get bits by hashing entropy with SHA256
var hash = sjcl.hash.sha256.hash(entropy.cleanStr);
var hex = sjcl.codec.hex.fromBits(hash);
bits = BigInteger.parse(hex, 16).toString(2);
while (bits.length % 256 != 0) {
bits = "0" + bits;
}
// Truncate hash to suit number of words
mnemonicLength = parseInt(mnemonicLength);
var numberOfBits = 32 * mnemonicLength / 3;
bits = bits.substring(0, numberOfBits);
// show warning for weak entropy override
if (mnemonicLength / 3 * 32 > entropy.binaryStr.length) {
DOM.entropyWeakEntropyOverrideWarning.removeClass("hidden");
}
else {
DOM.entropyWeakEntropyOverrideWarning.addClass("hidden");
}
}
else {
// hide warning for weak entropy override
DOM.entropyWeakEntropyOverrideWarning.addClass("hidden");
}
// Discard trailing entropy
var bitsToUse = Math.floor(bits.length / 32) * 32;
var start = bits.length - bitsToUse;
var binaryStr = bits.substring(start);
// Convert entropy string to numeric array
var entropyArr = [];
for (var i=0; i<binaryStr.length / 8; i++) {
var byteAsBits = binaryStr.substring(i*8, i*8+8);
var entropyByte = parseInt(byteAsBits, 2);
entropyArr.push(entropyByte)
}
// Convert entropy array to mnemonic
var phrase = mnemonic.toMnemonic(entropyArr);
// Set the mnemonic in the UI
DOM.phrase.val(phrase);
writeSplitPhrase(phrase);
// Show the word indexes
showWordIndexes();
// Show the checksum
showChecksum();
}
function clearEntropyFeedback() {
DOM.entropyCrackTime.text("...");
DOM.entropyType.text("");
DOM.entropyWordCount.text("0");
DOM.entropyEventCount.text("0");
DOM.entropyBitsPerEvent.text("0");
DOM.entropyBits.text("0");
DOM.entropyFiltered.html("&nbsp;");
DOM.entropyBinary.html("&nbsp;");
}
function showEntropyFeedback(entropy) {
var numberOfBits = entropy.binaryStr.length;
var timeToCrack = "unknown";
try {
var z = zxcvbn(entropy.base.parts.join(""));
timeToCrack = z.crack_times_display.offline_fast_hashing_1e10_per_second;
if (z.feedback.warning != "") {
timeToCrack = timeToCrack + " - " + z.feedback.warning;
};
}
catch (e) {
console.log("Error detecting entropy strength with zxcvbn:");
console.log(e);
}
var entropyTypeStr = getEntropyTypeStr(entropy);
var wordCount = Math.floor(numberOfBits / 32) * 3;
var bitsPerEvent = entropy.bitsPerEvent.toFixed(2);
var spacedBinaryStr = addSpacesEveryElevenBits(entropy.binaryStr);
DOM.entropyFiltered.html(entropy.cleanHtml);
DOM.entropyType.text(entropyTypeStr);
DOM.entropyCrackTime.text(timeToCrack);
DOM.entropyEventCount.text(entropy.base.ints.length);
DOM.entropyBits.text(numberOfBits);
DOM.entropyWordCount.text(wordCount);
DOM.entropyBinary.text(spacedBinaryStr);
DOM.entropyBitsPerEvent.text(bitsPerEvent);
// detect and warn of filtering
var rawNoSpaces = DOM.entropy.val().replace(/\s/g, "");
var cleanNoSpaces = entropy.cleanStr.replace(/\s/g, "");
var isFiltered = rawNoSpaces.length != cleanNoSpaces.length;
if (isFiltered) {
DOM.entropyFilterWarning.removeClass('hidden');
}
else {
DOM.entropyFilterWarning.addClass('hidden');
}
}
function getEntropyTypeStr(entropy) {
var typeStr = entropy.base.str;
// Add some detail if these are cards
if (entropy.base.asInt == 52) {
var cardDetail = []; // array of message strings
// Detect duplicates
var dupes = [];
var dupeTracker = {};
for (var i=0; i<entropy.base.parts.length; i++) {
var card = entropy.base.parts[i];
var cardUpper = card.toUpperCase();
if (cardUpper in dupeTracker) {
dupes.push(card);
}
dupeTracker[cardUpper] = true;
}
if (dupes.length > 0) {
var dupeWord = "duplicates";
if (dupes.length == 1) {
dupeWord = "duplicate";
}
var msg = dupes.length + " " + dupeWord + ": " + dupes.slice(0,3).join(" ");
if (dupes.length > 3) {
msg += "...";
}
cardDetail.push(msg);
}
// Detect full deck
var uniqueCards = [];
for (var uniqueCard in dupeTracker) {
uniqueCards.push(uniqueCard);
}
if (uniqueCards.length == 52) {
cardDetail.unshift("full deck");
}
// Detect missing cards
var values = "A23456789TJQK";
var suits = "CDHS";
var missingCards = [];
for (var i=0; i<suits.length; i++) {
for (var j=0; j<values.length; j++) {
var card = values[j] + suits[i];
if (!(card in dupeTracker)) {
missingCards.push(card);
}
}
}
// Display missing cards if six or less, ie clearly going for full deck
if (missingCards.length > 0 && missingCards.length <= 6) {
var msg = missingCards.length + " missing: " + missingCards.slice(0,3).join(" ");
if (missingCards.length > 3) {
msg += "...";
}
cardDetail.push(msg);
}
// Add card details to typeStr
if (cardDetail.length > 0) {
typeStr += " (" + cardDetail.join(", ") + ")";
}
}
return typeStr;
}
function setQrEvents(els) {
els.on("mouseenter", createQr);
els.on("mouseleave", destroyQr);
els.on("click", toggleQr);
}
function createQr(e) {
var content = e.target.textContent || e.target.value;
if (content) {
var qrEl = kjua({
text: content,
render: "canvas",
size: 310,
ecLevel: 'H',
});
DOM.qrImage.append(qrEl);
if (!showQr) {
DOM.qrHider.addClass("hidden");
}
else {
DOM.qrHider.removeClass("hidden");
}
DOM.qrContainer.removeClass("hidden");
}
}
function destroyQr() {
DOM.qrImage.text("");
DOM.qrContainer.addClass("hidden");
}
function toggleQr() {
showQr = !showQr;
DOM.qrHider.toggleClass("hidden");
DOM.qrHint.toggleClass("hidden");
}
function bip44TabSelected() {
return DOM.bip44tab.hasClass("active");
}
function bip32TabSelected() {
return DOM.bip32tab.hasClass("active");
}
function networkIsEthereum() {
var name = networks[DOM.network.val()].name;
return (name == "ETH - Ethereum")
|| (name == "ETC - Ethereum Classic")
|| (name == "EWT - EnergyWeb")
|| (name == "PIRL - Pirl")
|| (name == "MIX - MIX")
|| (name == "MUSIC - Musicoin")
|| (name == "POA - Poa")
|| (name == "EXP - Expanse")
|| (name == "CLO - Callisto")
|| (name == "DXN - DEXON")
|| (name == "ELLA - Ellaism")
|| (name == "ESN - Ethersocial Network")
|| (name == "VET - VeChain")
}
function networkHasSegwit() {
var n = network;
if ("baseNetwork" in network) {
n = bitcoinjs.bitcoin.networks[network.baseNetwork];
}
// check if only p2wpkh params are required
if (p2wpkhSelected()) {
return "p2wpkh" in n;
}
// check if only p2wpkh-in-p2sh params are required
else if (p2wpkhInP2shSelected()) {
return "p2wpkhInP2sh" in n;
}
// require both if it's unclear which params are required
return "p2wpkh" in n && "p2wpkhInP2sh" in n;
}
function bip49TabSelected() {
return DOM.bip49tab.hasClass("active");
}
function bip84TabSelected() {
return DOM.bip84tab.hasClass("active");
}
function bip141TabSelected() {
return DOM.bip141tab.hasClass("active");
}
function setBip44ChangeValue() {
if (isDefaultBip44ChangeValue) {
if (networkIsEthereum()) {
DOM.bip44change.val("");
} else {
DOM.bip44change.val(0);
}
}
}
function modifiedDefaultBip44ChangeValue() {
isDefaultBip44ChangeValue = false;
}
function resetDefaultBip44ChangeValue() {
isDefaultBip44ChangeValue = true;
setBip44ChangeValue();
}
function setHdCoin(coinValue) {
DOM.bip44coin.val(coinValue);
DOM.bip49coin.val(coinValue);
DOM.bip84coin.val(coinValue);
setBip44ChangeValue();
}
function showSegwitAvailable() {
DOM.bip49unavailable.addClass("hidden");
DOM.bip49available.removeClass("hidden");
DOM.bip84unavailable.addClass("hidden");
DOM.bip84available.removeClass("hidden");
DOM.bip141unavailable.addClass("hidden");
DOM.bip141available.removeClass("hidden");
}
function showSegwitUnavailable() {
DOM.bip49available.addClass("hidden");
DOM.bip49unavailable.removeClass("hidden");
DOM.bip84available.addClass("hidden");
DOM.bip84unavailable.removeClass("hidden");
DOM.bip141available.addClass("hidden");
DOM.bip141unavailable.removeClass("hidden");
}
function adjustNetworkForSegwit() {
// If segwit is selected the xpub/xprv prefixes need to be adjusted
// to avoid accidentally importing BIP49 xpub to BIP44 watch only
// wallet.
// See https://github.com/iancoleman/bip39/issues/125
var segwitNetworks = null;
// if a segwit network is alread selected, need to use base network to
// look up new parameters
if ("baseNetwork" in network) {
network = bitcoinjs.bitcoin.networks[network.baseNetwork];
}
// choose the right segwit params
if (p2wpkhSelected() && "p2wpkh" in network) {
network = network.p2wpkh;
}
else if (p2wpkhInP2shSelected() && "p2wpkhInP2sh" in network) {
network = network.p2wpkhInP2sh;
}
}
function lastIndexInTable() {
var pathText = DOM.addresses.find(".index").last().text();
var pathBits = pathText.split("/");
var lastBit = pathBits[pathBits.length-1];
var lastBitClean = lastBit.replace("'", "");
return parseInt(lastBitClean);
}
function uint8ArrayToHex(a) {
var s = ""
for (var i=0; i<a.length; i++) {
var h = a[i].toString(16);
while (h.length < 2) {
h = "0" + h;
}
s = s + h;
}
return s;
}
function showWordIndexes() {
var phrase = DOM.phrase.val();
var words = phraseToWordArray(phrase);
var wordIndexes = [];
var language = getLanguage();
for (var i=0; i<words.length; i++) {
var word = words[i];
var wordIndex = WORDLISTS[language].indexOf(word);
wordIndexes.push(wordIndex);
}
var wordIndexesStr = wordIndexes.join(", ");
DOM.entropyWordIndexes.text(wordIndexesStr);
}
function showChecksum() {
var phrase = DOM.phrase.val();
var words = phraseToWordArray(phrase);
var checksumBitlength = words.length / 3;
var checksum = "";
var binaryStr = "";
var language = getLanguage();
for (var i=words.length-1; i>=0; i--) {
var word = words[i];
var wordIndex = WORDLISTS[language].indexOf(word);
var wordBinary = wordIndex.toString(2);
while (wordBinary.length < 11) {
wordBinary = "0" + wordBinary;
}
var binaryStr = wordBinary + binaryStr;
if (binaryStr.length >= checksumBitlength) {
var start = binaryStr.length - checksumBitlength;
var end = binaryStr.length;
checksum = binaryStr.substring(start, end);
// add spaces so the last group is 11 bits, not the first
checksum = checksum.split("").reverse().join("")
checksum = addSpacesEveryElevenBits(checksum);
checksum = checksum.split("").reverse().join("")
break;
}
}
DOM.entropyChecksum.text(checksum);
}
function updateCsv() {
var tableCsv = "path,address,public key,private key\n";
var rows = DOM.addresses.find("tr");
for (var i=0; i<rows.length; i++) {
var row = $(rows[i]);
var cells = row.find("td");
for (var j=0; j<cells.length; j++) {
var cell = $(cells[j]);
if (!cell.children().hasClass("invisible")) {
tableCsv = tableCsv + cell.text();
}
if (j != cells.length - 1) {
tableCsv = tableCsv + ",";
}
}
tableCsv = tableCsv + "\n";
}
DOM.csv.val(tableCsv);
}
function addSpacesEveryElevenBits(binaryStr) {
return binaryStr.match(/.{1,11}/g).join(" ");
}
var networks = [
{
name: "AC - Asiacoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.asiacoin;
setHdCoin(51);
},
},
{
name: "ACC - Adcoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.adcoin;
setHdCoin(161);
},
},
{
name: "ARYA - Aryacoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.aryacoin;
setHdCoin(357);
},
},
{
name: "AUR - Auroracoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.auroracoin;
setHdCoin(85);
},
},
{
name: "AXE - Axe",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.axe;
setHdCoin(4242);
},
},
{
name: "ANON - ANON",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.anon;
setHdCoin(220);
},
},
{
name: "BOLI - Bolivarcoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.bolivarcoin;
setHdCoin(278);
},
},
{
name: "BCA - Bitcoin Atom",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.atom;
setHdCoin(185);
},
},
{
name: "BCH - Bitcoin Cash",
onSelect: function() {
DOM.bitcoinCashAddressTypeContainer.removeClass("hidden");
setHdCoin(145);
},
},
{
name: "BEET - Beetlecoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.beetlecoin;
setHdCoin(800);
},
},
{
name: "BELA - Belacoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.belacoin;
setHdCoin(73);
},
},
{
name: "BLK - BlackCoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.blackcoin;
setHdCoin(10);
},
},
{
name: "BND - Blocknode",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.blocknode;
setHdCoin(2941);
},
},
{
name: "tBND - Blocknode Testnet",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.blocknode_testnet;
setHdCoin(1);
},
},
{
name: "BRIT - Britcoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.britcoin;
setHdCoin(70);
},
},
{
name: "BSD - Bitsend",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.bitsend;
setHdCoin(91);
},
},
{
name: "BST - BlockStamp",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.blockstamp;
setHdCoin(254);
},
},
{
name: "BTA - Bata",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.bata;
setHdCoin(89);
},
},
{
name: "BTC - Bitcoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.bitcoin;
setHdCoin(0);
},
},
{
name: "BTC - Bitcoin Testnet",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.testnet;
setHdCoin(1);
},
},
{
name: "BITG - Bitcoin Green",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.bitcoingreen;
setHdCoin(222);
},
},
{
name: "BTCP - Bitcoin Private",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.bitcoinprivate;
setHdCoin(183);
},
},
{
name: "BSV - BitcoinSV",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.bitcoinsv;
setHdCoin(236);
},
},
{
name: "BTCZ - Bitcoinz",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.bitcoinz;
setHdCoin(177);
},
},
{
name: "BTDX - BitCloud",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.bitcloud;
setHdCoin(218);
},
},
{
name: "BTG - Bitcoin Gold",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.bgold;
setHdCoin(156);
},
},
{
name: "BTX - Bitcore",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.bitcore;
setHdCoin(160);
},
},
{
name: "CCN - Cannacoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.cannacoin;
setHdCoin(19);
},
},
{
name: "CESC - Cryptoescudo",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.cannacoin;
setHdCoin(111);
},
},
{
name: "CDN - Canadaecoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.canadaecoin;
setHdCoin(34);
},
},
{
name: "CLAM - Clams",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.clam;
setHdCoin(23);
},
},
{
name: "CLO - Callisto",
segwitAvailable: false,
onSelect: function() {
network = bitcoinjs.bitcoin.networks.bitcoin;
setHdCoin(820);
},
},
{
name: "CLUB - Clubcoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.clubcoin;
setHdCoin(79);
},
},
{
name: "CMP - Compcoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.compcoin;
setHdCoin(71);
},
},
{
name: "CPU - CPUchain",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.cpuchain;
setHdCoin(363);
},
},
{
name: "CRAVE - Crave",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.crave;
setHdCoin(186);
},
},
{
name: "CRW - Crown (Legacy)",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.crown;
setHdCoin(72);
},
},
{
name: "CRW - Crown",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.crown;
setHdCoin(72);
},
},
{
name: "CSC - CasinoCoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.bitcoin;
setHdCoin(359);
},
},
{
name: "DASH - Dash",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.dash;
setHdCoin(5);
},
},
{
name: "DASH - Dash Testnet",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.dashtn;
setHdCoin(1);
},
},
{
name: "DFC - Defcoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.defcoin;
setHdCoin(1337);
},
},
{
name: "DGB - Digibyte",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.digibyte;
setHdCoin(20);
},
},
{
name: "DGC - Digitalcoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.digitalcoin;
setHdCoin(18);
},
},
{
name: "DMD - Diamond",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.diamond;
setHdCoin(152);
},
},
{
name: "DNR - Denarius",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.denarius;
setHdCoin(116);
},
},
{
name: "DOGE - Dogecoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.dogecoin;
setHdCoin(3);
},
},
{
name: "DOGEt - Dogecoin Testnet",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.dogecointestnet;
setHdCoin(1);
},
},
{
name: "DXN - DEXON",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.bitcoin;
setHdCoin(237);
},
},
{
name: "ECN - Ecoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.ecoin;
setHdCoin(115);
},
},
{
name: "EDRC - Edrcoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.edrcoin;
setHdCoin(56);
},
},
{
name: "EFL - Egulden",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.egulden;
setHdCoin(78);
},
},
{
name: "ELA - Elastos",
onSelect: function () {
network = bitcoinjs.bitcoin.networks.elastos;
setHdCoin(2305);
},
},
{
name: "ELLA - Ellaism",
segwitAvailable: false,
onSelect: function() {
network = bitcoinjs.bitcoin.networks.bitcoin;
setHdCoin(163);
},
},
{
name: "EMC2 - Einsteinium",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.einsteinium;
setHdCoin(41);
},
},
{
name: "ERC - Europecoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.europecoin;
setHdCoin(151);
},
},
{
name: "EOS - EOSIO",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.bitcoin;
setHdCoin(194);
},
},
{
name: "ESN - Ethersocial Network",
segwitAvailable: false,
onSelect: function() {
network = bitcoinjs.bitcoin.networks.bitcoin;
setHdCoin(31102);
},
},
{
name: "ETC - Ethereum Classic",
segwitAvailable: false,
onSelect: function() {
network = bitcoinjs.bitcoin.networks.bitcoin;
setHdCoin(61);
},
},
{
name: "ETH - Ethereum",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.bitcoin;
setHdCoin(60);
},
},
{
name: "EWT - EnergyWeb",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.bitcoin;
setHdCoin(246);
},
},
{
name: "EXCL - Exclusivecoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.exclusivecoin;
setHdCoin(190);
},
},
{
name: "EXCC - ExchangeCoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.exchangecoin;
setHdCoin(0);
},
},
{
name: "EXP - Expanse",
segwitAvailable: false,
onSelect: function() {
network = bitcoinjs.bitcoin.networks.bitcoin;
setHdCoin(40);
},
},
{
name: "FIX - FIX",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.fix;
setHdCoin(336);
},
},
{
name: "FIX - FIX Testnet",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.fixtestnet;
setHdCoin(1);
},
},
{
name: "FJC - Fujicoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.fujicoin;
setHdCoin(75);
},
},
{
name: "FLASH - Flashcoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.flashcoin;
setHdCoin(120);
},
},
{
name: "FRST - Firstcoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.firstcoin;
setHdCoin(167);
},
},
{
name: "FTC - Feathercoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.feathercoin;
setHdCoin(8);
},
},
{
name: "GAME - GameCredits",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.game;
setHdCoin(101);
},
},
{
name: "GBX - Gobyte",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.gobyte;
setHdCoin(176);
},
},
{
name: "GCR - GCRCoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.gcr;
setHdCoin(79);
},
},
{
name: "GRC - Gridcoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.gridcoin;
setHdCoin(84);
},
},
{
name: "GRS - Groestlcoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.groestlcoin;
setHdCoin(17);
},
},
{
name: "GRS - Groestlcoin Testnet",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.groestlcointestnet;
setHdCoin(1);
},
},
{
name: "HNC - Helleniccoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.helleniccoin;
setHdCoin(168);
},
},
{
name: "HUSH - Hush (Legacy)",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.hush;
setHdCoin(197);
},
},
{
name: "HUSH - Hush3",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.hush3;
setHdCoin(197);
},
},
{
name: "INSN - Insane",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.insane;
setHdCoin(68);
},
},
{
name: "IOP - Iop",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.iop;
setHdCoin(66);
},
},
{
name: "IXC - Ixcoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.ixcoin;
setHdCoin(86);
},
},
{
name: "JBS - Jumbucks",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.jumbucks;
setHdCoin(26);
},
},
{
name: "KMD - Komodo",
bip49available: false,
onSelect: function() {
network = bitcoinjs.bitcoin.networks.komodo;
setHdCoin(141);
},
},
{
name: "KOBO - Kobocoin",
bip49available: false,
onSelect: function() {
network = bitcoinjs.bitcoin.networks.kobocoin;
setHdCoin(196);
},
},
{
name: "LBC - Library Credits",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.lbry;
setHdCoin(140);
},
},
{
name: "LCC - Litecoincash",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.litecoincash;
setHdCoin(192);
},
},
{
name: "LDCN - Landcoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.landcoin;
setHdCoin(63);
},
},
{
name: "LINX - Linx",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.linx;
setHdCoin(114);
},
},
{
name: "LKR - Lkrcoin",
segwitAvailable: false,
onSelect: function() {
network = bitcoinjs.bitcoin.networks.lkrcoin;
setHdCoin(557);
},
},
{
name: "LTC - Litecoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.litecoin;
setHdCoin(2);
DOM.litecoinLtubContainer.removeClass("hidden");
},
},
{
name: "LTCt - Litecoin Testnet",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.litecointestnet;
setHdCoin(1);
DOM.litecoinLtubContainer.removeClass("hidden");
},
},
{
name: "LTZ - LitecoinZ",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.litecoinz;
setHdCoin(221);
},
},
{
name: "LYNX - Lynx",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.lynx;
setHdCoin(191);
},
},
{
name: "MAZA - Maza",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.maza;
setHdCoin(13);
},
},
{
name: "MEC - Megacoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.megacoin;
setHdCoin(217);
},
},
{
name: "MIX - MIX",
segwitAvailable: false,
onSelect: function() {
network = bitcoinjs.bitcoin.networks.bitcoin;
setHdCoin(76);
},
},
{
name: "MNX - Minexcoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.minexcoin;
setHdCoin(182);
},
},
{
name: "MONA - Monacoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.monacoin,
setHdCoin(22);
},
},
{
name: "MONK - Monkey Project",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.monkeyproject,
setHdCoin(214);
},
},
{
name: "MUSIC - Musicoin",
segwitAvailable: false,
onSelect: function() {
network = bitcoinjs.bitcoin.networks.bitcoin;
setHdCoin(184);
},
},
{
name: "NAV - Navcoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.navcoin;
setHdCoin(130);
},
},
{
name: "NAS - Nebulas",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.bitcoin;
setHdCoin(2718);
},
},
{
name: "NEBL - Neblio",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.neblio;
setHdCoin(146);
},
},
{
name: "NEOS - Neoscoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.neoscoin;
setHdCoin(25);
},
},
{
name: "NIX - NIX Platform",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.nix;
setHdCoin(400);
},
},
{
name: "NLG - Gulden",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.gulden;
setHdCoin(87);
},
},
{
name: "NMC - Namecoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.namecoin;
setHdCoin(7);
},
},
{
name: "NRG - Energi",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.energi;
setHdCoin(204);
},
},
{
name: "NRO - Neurocoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.neurocoin;
setHdCoin(110);
},
},
{
name: "NSR - Nushares",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.nushares;
setHdCoin(11);
},
},
{
name: "NYC - Newyorkc",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.newyorkc;
setHdCoin(179);
},
},
{
name: "NVC - Novacoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.novacoin;
setHdCoin(50);
},
},
{
name: "OK - Okcash",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.okcash;
setHdCoin(69);
},
},
{
name: "OMNI - Omnicore",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.omnicore;
setHdCoin(200);
},
},
{
name: "ONION - DeepOnion",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.deeponion;
setHdCoin(305);
},
},
{
name: "ONX - Onixcoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.onixcoin;
setHdCoin(174);
},
},
{
name: "PHR - Phore",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.phore;
setHdCoin(444);
},
},
{
name: "PINK - Pinkcoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.pinkcoin;
setHdCoin(117);
},
},
{
name: "PIRL - Pirl",
segwitAvailable: false,
onSelect: function() {
network = bitcoinjs.bitcoin.networks.bitcoin;
setHdCoin(164);
},
},
{
name: "PIVX - PIVX",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.pivx;
setHdCoin(119);
},
},
{
name: "PIVX - PIVX Testnet",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.pivxtestnet;
setHdCoin(1);
},
},
{
name: "POA - Poa",
segwitAvailable: false,
onSelect: function() {
network = bitcoinjs.bitcoin.networks.bitcoin;
setHdCoin(178);
},
},
{
name: "POSW - POSWcoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.poswcoin;
setHdCoin(47);
},
},
{
name: "POT - Potcoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.potcoin;
setHdCoin(81);
},
},
{
name: "PPC - Peercoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.peercoin;
setHdCoin(6);
},
},
{
name: "PRJ - ProjectCoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.projectcoin;
setHdCoin(533);
},
},
{
name: "PSB - Pesobit",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.pesobit;
setHdCoin(62);
},
},
{
name: "PUT - Putincoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.putincoin;
setHdCoin(122);
},
},
{
name: "RPD - Rapids",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.rapids;
setHdCoin(320);
},
},
{
name: "RVN - Ravencoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.ravencoin;
setHdCoin(175);
},
},
{
name: "RBY - Rubycoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.rubycoin;
setHdCoin(16);
},
},
{
name: "RDD - Reddcoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.reddcoin;
setHdCoin(4);
},
},
{
name: "RVR - RevolutionVR",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.revolutionvr;
setHdCoin(129);
},
},
{
name: "SAFE - Safecoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.safecoin;
setHdCoin(19165);
},
},
{
name: "SLS - Salus",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.salus;
setHdCoin(63);
},
},
{
name: "SDC - ShadowCash",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.shadow;
setHdCoin(35);
},
},
{
name: "SDC - ShadowCash Testnet",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.shadowtn;
setHdCoin(1);
},
},
{
name: "SLM - Slimcoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.slimcoin;
setHdCoin(63);
},
},
{
name: "SLM - Slimcoin Testnet",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.slimcointn;
setHdCoin(111);
},
},
{
name: "SLP - Simple Ledger Protocol",
onSelect: function() {
DOM.bitcoinCashAddressTypeContainer.removeClass("hidden");
setHdCoin(245);
},
},
{
name: "SLR - Solarcoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.solarcoin;
setHdCoin(58);
},
},
{
name: "SMLY - Smileycoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.smileycoin;
setHdCoin(59);
},
},
{
name: "STASH - Stash",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.stash;
setHdCoin(0xC0C0);
},
},
{
name: "STASH - Stash Testnet",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.stashtn;
setHdCoin(0xCAFE);
},
},
{
name: "STRAT - Stratis",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.stratis;
setHdCoin(105);
},
},
{
name: "TSTRAT - Stratis Testnet",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.stratistest;
setHdCoin(105);
},
},
{
name: "SYS - Syscoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.syscoin;
setHdCoin(57);
},
},
{
name: "THC - Hempcoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.hempcoin;
setHdCoin(113);
},
},
{
name: "THT - Thought",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.thought;
setHdCoin(1618);
},
},
{
name: "TOA - Toa",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.toa;
setHdCoin(159);
},
},
{
name: "TWINS - TWINS",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.twins;
setHdCoin(970);
},
},
{
name: "TWINS - TWINS Testnet",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.twinstestnet;
setHdCoin(1);
},
},
{
name: "USC - Ultimatesecurecash",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.ultimatesecurecash;
setHdCoin(112);
},
},
{
name: "USNBT - NuBits",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.nubits;
setHdCoin(12);
},
},
{
name: "UNO - Unobtanium",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.unobtanium;
setHdCoin(92);
},
},
{
name: "VASH - Vpncoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.vpncoin;
setHdCoin(33);
},
},
{
name: "VET - VeChain",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.bitcoin;
setHdCoin(818);
},
},
{
name: "VIA - Viacoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.viacoin;
setHdCoin(14);
},
},
{
name: "VIA - Viacoin Testnet",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.viacointestnet;
setHdCoin(1);
},
},
{
name: "VIVO - Vivo",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.vivo;
setHdCoin(166);
},
},
{
name: "VTC - Vertcoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.vertcoin;
setHdCoin(28);
},
},
{
name: "WGR - Wagerr",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.wagerr;
setHdCoin(7825266);
},
},
{
name: "WC - Wincoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.wincoin;
setHdCoin(181);
},
},
{
name: "XAX - Artax",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.artax;
setHdCoin(219);
},
},
{
name: "XBC - Bitcoinplus",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.bitcoinplus;
setHdCoin(65);
},
},
{
name: "XLM - Stellar",
onSelect: function() {
network = stellarUtil.dummyNetwork;
setHdCoin(148);
},
},
{
name: "XMY - Myriadcoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.myriadcoin;
setHdCoin(90);
},
},
{
name: "XRP - Ripple",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.bitcoin;
setHdCoin(144);
},
},
{
name: "XVC - Vcash",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.vcash;
setHdCoin(127);
},
},
{
name: "XVG - Verge",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.verge;
setHdCoin(77);
},
},
{
name: "XUEZ - Xuez",
segwitAvailable: false,
onSelect: function() {
network = bitcoinjs.bitcoin.networks.xuez;
setHdCoin(225);
},
},
{
name: "XWC - Whitecoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.whitecoin;
setHdCoin(155);
},
},
{
name: "XZC - Zcoin",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.zcoin;
setHdCoin(136);
},
},
{
name: "ZCL - Zclassic",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.zclassic;
setHdCoin(147);
},
},
{
name: "ZEC - Zcash",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.zcash;
setHdCoin(133);
},
},
{
name: "ZEN - Horizen",
onSelect: function() {
network = bitcoinjs.bitcoin.networks.zencash;
setHdCoin(121);
},
},
]
var clients = [
{
name: "Bitcoin Core",
onSelect: function() {
DOM.bip32path.val("m/0'/0'");
DOM.hardenedAddresses.prop('checked', true);
},
},
{
name: "blockchain.info",
onSelect: function() {
DOM.bip32path.val("m/44'/0'/0'");
DOM.hardenedAddresses.prop('checked', false);
},
},
{
name: "MultiBit HD",
onSelect: function() {
DOM.bip32path.val("m/0'/0");
DOM.hardenedAddresses.prop('checked', false);
},
},
{
name: "Coinomi, Ledger",
onSelect: function() {
DOM.bip32path.val("m/44'/"+DOM.bip44coin.val()+"'/0'");
DOM.hardenedAddresses.prop('checked', false);
},
}
]
// ELA - Elastos functions - begin
function displayBip44InfoForELA() {
if (!isELA()) {
return;
}
var coin = parseIntNoNaN(DOM.bip44coin.val(), 0);
var account = parseIntNoNaN(DOM.bip44account.val(), 0);
// Calculate the account extended keys
var accountXprv = elastosjs.getAccountExtendedPrivateKey(seed, coin, account);
var accountXpub = elastosjs.getAccountExtendedPublicKey(seed, coin, account);
// Display the extended keys
DOM.bip44accountXprv.val(accountXprv);
DOM.bip44accountXpub.val(accountXpub);
}
function displayBip32InfoForELA() {
if (!isELA()) {
return;
}
var coin = parseIntNoNaN(DOM.bip44coin.val(), 0);
var account = parseIntNoNaN(DOM.bip44account.val(), 0);
var change = parseIntNoNaN(DOM.bip44change.val(), 0);
DOM.extendedPrivKey.val(elastosjs.getBip32ExtendedPrivateKey(seed, coin, account, change));
DOM.extendedPubKey.val(elastosjs.getBip32ExtendedPublicKey(seed, coin, account, change));
// Display the addresses and privkeys
clearAddressesList();
var initialAddressCount = parseInt(DOM.rowsToAdd.val());
displayAddresses(0, initialAddressCount);
}
function calcAddressForELA(seed, coin, account, change, index) {
if (!isELA()) {
return;
}
var publicKey = elastosjs.getDerivedPublicKey(elastosjs.getMasterPublicKey(seed), change, index);
return {
privateKey: elastosjs.getDerivedPrivateKey(seed, coin, account, change, index),
publicKey: publicKey,
address: elastosjs.getAddress(publicKey.toString('hex'))
};
}
// ELA - Elastos functions - end
init();
})();