]> git.immae.eu Git - perso/Immae/Projets/Cryptomonnaies/BIP39.git/blobdiff - src/js/index.js
Change Bitcoin Gold coin number to 156
[perso/Immae/Projets/Cryptomonnaies/BIP39.git] / src / js / index.js
index a147f61df8550bccec7013f7e698d7df3613d224..4baa14c9d9349ff69d68df5a929488f5daaff280 100644 (file)
@@ -38,6 +38,7 @@
     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.entropyFilterWarning = DOM.entropyContainer.find(".filter-warning");
     DOM.phrase = $(".phrase");
@@ -53,6 +54,7 @@
     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.bip49accountXprv = $("#bip49 .account-xprv");
     DOM.bip49accountXpub = $("#bip49 .account-xpub");
     DOM.bip49change = $("#bip49 .change");
+    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.hardenedAddresses = $(".hardened-addresses");
     DOM.useBitpayAddressesContainer = $(".use-bitpay-addresses-container");
     DOM.useBitpayAddresses = $(".use-bitpay-addresses");
+    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.bip44change.on("input", calcForDerivationPath);
         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.useBitpayAddresses.on("change", useBitpayAddressesChange);
         setQrEvents(DOM.showQrEls);
         else if (bip49TabSelected()) {
             displayBip49Info();
         }
+        else if (bip84TabSelected()) {
+            displayBip84Info();
+        }
         displayBip32Info();
     }
 
             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);
         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);
         DOM.extendedPubKey.val(extendedPubKey);
         // Display the addresses and privkeys
         clearAddressesList();
-        displayAddresses(0, 20);
+        var initialAddressCount = parseInt(DOM.rowsToAdd.val());
+        displayAddresses(0, initialAddressCount);
     }
 
     function displayAddresses(start, total) {
     }
 
     function segwitSelected() {
-        return bip49TabSelected() || bip141TabSelected();
+        return bip49TabSelected() || bip84TabSelected() || bip141TabSelected();
     }
 
     function p2wpkhSelected() {
-        return bip141TabSelected() && DOM.bip141semantics.val() == "p2wpkh";
+        return bip84TabSelected() ||
+                bip141TabSelected() && DOM.bip141semantics.val() == "p2wpkh";
     }
 
     function p2wpkhInP2shSelected() {
         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();
                 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);
                 }
-                var address = key.getAddress().toString();
+                // 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, { compressed: false });
+                }
+                // get address
+                var address = keyPair.getAddress().toString();
+                // get privkey
+                var hasPrivkey = !key.isNeutered();
                 var privkey = "NA";
-                if (!key.isNeutered()) {
-                    privkey = key.keyPair.toWIF(network);
+                if (hasPrivkey) {
+                    privkey = keyPair.toWIF(network);
+                    // BIP38 encode private key if required
+                    if (useBip38) {
+                        privkey = bitcoinjsBip38.encrypt(keyPair.d.toBuffer(), false, bip38password, function(p) {
+                            console.log("Progressed " + p.percent.toFixed(1) + "% for index " + index);
+                        });
+                    }
                 }
-                var pubkey = key.getPublicKeyBuffer().toString('hex');
+                // get pubkey
+                var pubkey = keyPair.getPublicKeyBuffer().toString('hex');
                 var indexText = getDerivationPath() + "/" + index;
                 if (useHardenedAddresses) {
                     indexText = indexText + "'";
                 }
                 // Ethereum values are different
                 if (networks[DOM.network.val()].name == "ETH - Ethereum") {
-                    var privKeyBuffer = key.keyPair.d.toBuffer();
+                    var privKeyBuffer = keyPair.d.toBuffer(32);
                     privkey = privKeyBuffer.toString('hex');
                     var addressBuffer = ethUtil.privateToAddress(privKeyBuffer);
                     var hexAddress = addressBuffer.toString('hex');
                 addAddressToList(indexText, address, pubkey, privkey);
                 if (isLast) {
                     hidePending();
+                    updateCsv();
                 }
             }, 50)
         }
 
     function clearAddressesList() {
         DOM.addresses.empty();
+        DOM.csv.val("");
         stopGenerating();
     }
 
     function wordArrayToPhrase(words) {
         var phrase = words.join(" ");
         var language = getLanguageFromPhrase(phrase);
-        if (language == "japanese") {
+        if (language == "japanese" || language == "korean") {
             phrase = words.join("\u3000");
         }
         return phrase;
         DOM.phrase.val(phrase);
         // Show the word indexes
         showWordIndexes();
+        // Show the checksum
+        showChecksum();
     }
 
     function clearEntropyFeedback() {
         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(entropy.binaryStr);
+        DOM.entropyBinary.text(spacedBinaryStr);
         DOM.entropyBitsPerEvent.text(bitsPerEvent);
         // detect and warn of filtering
         var rawNoSpaces = DOM.entropy.val().replace(/\s/g, "");
         return DOM.bip49tab.hasClass("active");
     }
 
+    function bip84TabSelected() {
+        return DOM.bip84tab.hasClass("active");
+    }
+
     function bip141TabSelected() {
         return DOM.bip141tab.hasClass("active");
     }
     function setHdCoin(coinValue) {
         DOM.bip44coin.val(coinValue);
         DOM.bip49coin.val(coinValue);
+        DOM.bip84coin.val(coinValue);
     }
 
     function showSegwitAvailable() {
         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: "AXE - Axe",
+            segwitAvailable: false,
+            onSelect: function() {
+                network = bitcoinjs.bitcoin.networks.axe;
+                setHdCoin(0);
+            },
+        },
+        {
+            name: "BEET - Beetlecoin",
+            segwitAvailable: false,
+            onSelect: function() {
+                network = bitcoinjs.bitcoin.networks.beetlecoin;
+                setHdCoin(800);
+            },
+        },
         {
             name: "BCH - Bitcoin Cash",
             segwitAvailable: false,
                 setHdCoin(145);
             },
         },
+        {
+            name: "BLK - BlackCoin",
+            segwitAvailable: false,
+            onSelect: function() {
+                network = bitcoinjs.bitcoin.networks.blackcoin;
+                setHdCoin(10);
+            },
+        },
         {
             name: "BTC - Bitcoin",
             segwitAvailable: true,
             segwitAvailable: true,
             onSelect: function() {
                 network = bitcoinjs.bitcoin.networks.bgold;
-                setHdCoin(0);
+                setHdCoin(156);
             },
         },
         {
                 setHdCoin(1);
             },
         },
+        {
+            name: "DNR - Denarius",
+            segwitAvailable: false,
+            onSelect: function() {
+                network = bitcoinjs.bitcoin.networks.denarius;
+                setHdCoin(116);
+            },
+        },
+        {
+            name: "NEBL - Neblio",
+            segwitAvailable: false,
+            onSelect: function() {
+                network = bitcoinjs.bitcoin.networks.neblio;
+                setHdCoin(146);
+            },
+        },
         {
             name: "DOGE - Dogecoin",
             segwitAvailable: false,
                 setHdCoin(7);
             },
         },
+        {
+            name: "ONX - Onixcoin",
+            segwitAvailable: false,
+            onSelect: function() {
+                network = bitcoinjs.bitcoin.networks.onixcoin;
+                setHdCoin(174);
+            },
+        },
         {
             name: "PIVX - PIVX",
             segwitAvailable: false,
                 network = bitcoinjs.bitcoin.networks.bitcoin;
                 setHdCoin(144);
             },
-        }
+        },
     ]
 
     var clients = [