X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=src%2Fjs%2Findex.js;h=6f0da65d391a29e58f3dcdc597fc3511039b7e40;hb=30c9e79de32e529e9b87b836a1bc808e6dbbc646;hp=09bcdd9505d7d979086d8c87a2e381df58fe66f8;hpb=d6cedc9405e5f5751c8635f59ed3ff6876460776;p=perso%2FImmae%2FProjets%2FCryptomonnaies%2FBIP39.git diff --git a/src/js/index.js b/src/js/index.js index 09bcdd9..6f0da65 100644 --- a/src/js/index.js +++ b/src/js/index.js @@ -1,9 +1,10 @@ (function() { var mnemonic = new Mnemonic("english"); + var seed = null var bip32RootKey = null; var bip32ExtendedKey = null; - var network = Bitcoin.networks.bitcoin; + var network = bitcoin.networks.bitcoin; var addressRowTemplate = $("#address-row-template"); var showIndex = true; @@ -15,10 +16,10 @@ var DOM = {}; DOM.network = $(".network"); DOM.phraseNetwork = $("#network-phrase"); - DOM.bip44Network = $("#network-bip44"); DOM.phrase = $(".phrase"); DOM.passphrase = $(".passphrase"); DOM.generate = $(".generate"); + DOM.seed = $(".seed"); DOM.rootKey = $(".root-key"); DOM.extendedPrivKey = $(".extended-priv-key"); DOM.extendedPubKey = $(".extended-pub-key"); @@ -42,8 +43,6 @@ DOM.addressToggle = $(".address-toggle"); DOM.privateKeyToggle = $(".private-key-toggle"); - var derivationPath = DOM.bip44path.val(); - function init() { // Events DOM.network.on("change", networkChanged); @@ -51,48 +50,26 @@ DOM.passphrase.on("input", delayedPhraseChanged); DOM.generate.on("click", generateClicked); DOM.more.on("click", showMore); - DOM.bip32path.on("input", bip32Changed); - DOM.bip44purpose.on("input", bip44Changed); - DOM.bip44coin.on("input", bip44Changed); - DOM.bip44account.on("input", bip44Changed); - DOM.bip44change.on("input", bip44Changed); - DOM.tab.on("click", tabClicked); + DOM.bip32path.on("input", delayedPhraseChanged); + DOM.bip44purpose.on("input", delayedPhraseChanged); + DOM.bip44coin.on("input", delayedPhraseChanged); + DOM.bip44account.on("input", delayedPhraseChanged); + DOM.bip44change.on("input", delayedPhraseChanged); + DOM.tab.on("click", delayedPhraseChanged); DOM.indexToggle.on("click", toggleIndexes); DOM.addressToggle.on("click", toggleAddresses); DOM.privateKeyToggle.on("click", togglePrivateKeys); disableForms(); hidePending(); hideValidationError(); + populateNetworkSelect(); } // Event handlers function networkChanged(e) { - var n = e.target.value; - if (n == "bitcoin") { - network = Bitcoin.networks.bitcoin; - DOM.bip44coin.val(0); - setBip44DerivationPath(); - enableBip44Tab(); - } - else if (n == "bitcoin-testnet") { - network = Bitcoin.networks.testnet; - DOM.bip44coin.val(1); - setBip44DerivationPath(); - enableBip44Tab(); - } - else if (n == "litecoin") { - network = Bitcoin.networks.litecoin; - DOM.bip44coin.val(2); - setBip44DerivationPath(); - enableBip44Tab(); - } - else if (n == "dogecoin") { - network = Bitcoin.networks.dogecoin; - disableBip44Tab(); - } - DOM.phraseNetwork.val(n); - DOM.bip44Network.val(n); + var network = e.target.value; + networks[network].onSelect(); delayedPhraseChanged(); } @@ -117,7 +94,8 @@ return; } // Get the derivation path - var errorText = findDerivationPathErrors(); + var derivationPath = getDerivationPath(); + var errorText = findDerivationPathErrors(derivationPath); if (errorText) { showValidationError(errorText); return; @@ -140,27 +118,6 @@ }, 50); } - function tabClicked(e) { - var activePath = $(e.target.getAttribute("href") + " .path"); - derivationPath = activePath.val(); - derivationChanged(); - } - - function derivationChanged() { - delayedPhraseChanged(); - } - - function bip32Changed() { - derivationPath = DOM.bip32path.val(); - derivationChanged(); - } - - function bip44Changed() { - setBip44DerivationPath(); - derivationPath = DOM.bip44path.val(); - derivationChanged(); - } - function toggleIndexes() { showIndex = !showIndex; $("td.index span").toggleClass("invisible"); @@ -185,21 +142,6 @@ return; } var numWords = parseInt(DOM.strength.val()); - // Check strength is an integer - if (isNaN(numWords)) { - DOM.strength.val("12"); - numWords = 12; - } - // Check strength is a multiple of 32, if not round it down - if (numWords % 3 != 0) { - numWords = Math.floor(numWords / 3) * 3; - DOM.strength.val(numWords); - } - // Check strength is at least 32 - if (numWords == 0) { - numWords = 3; - DOM.strength.val(numWords); - } var strength = numWords / 3 * 32; var words = mnemonic.generate(strength); DOM.phrase.val(words); @@ -207,8 +149,8 @@ } function calcBip32Seed(phrase, passphrase, path) { - var seed = mnemonic.toSeed(phrase, passphrase); - bip32RootKey = Bitcoin.HDNode.fromSeedHex(seed, network); + seed = mnemonic.toSeed(phrase, passphrase); + bip32RootKey = bitcoin.HDNode.fromSeedHex(seed, network); bip32ExtendedKey = bip32RootKey; // Derive the key from the path var pathBits = path.split("/"); @@ -263,13 +205,72 @@ return false; } + function getDerivationPath() { + if (DOM.bip44tab.hasClass("active")) { + 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(), 0); + var path = "m/"; + path += purpose + "'/"; + path += coin + "'/"; + path += account + "'/"; + path += change; + DOM.bip44path.val(path); + var derivationPath = DOM.bip44path.val(); + console.log("Using derivation path from BIP44 tab: " + derivationPath); + return derivationPath; + } + else if (DOM.bip32tab.hasClass("active")) { + var derivationPath = DOM.bip32path.val(); + console.log("Using derivation path from BIP32 tab: " + derivationPath); + return derivationPath; + } + else { + console.log("Unknown derivation path"); + } + } + function findDerivationPathErrors(path) { - // TODO + // 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 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; + } + } + } return false; } function displayBip32Info() { // Display the key + DOM.seed.val(seed); var rootKey = bip32RootKey.toBase58(); DOM.rootKey.val(rootKey); var extendedPrivKey = bip32ExtendedKey.toBase58(); @@ -299,7 +300,8 @@ var key = bip32ExtendedKey.derive(index); var address = key.getAddress().toString(); var privkey = key.privKey.toWIF(network); - addAddressToList(index, address, privkey); + var indexText = getDerivationPath() + "/" + index; + addAddressToList(indexText, address, privkey); }, 50) } @@ -340,14 +342,14 @@ DOM.extendedPubKey.val(""); } - function addAddressToList(index, address, privkey) { + function addAddressToList(indexText, address, privkey) { var row = $(addressRowTemplate.html()); // Elements var indexCell = row.find(".index span"); var addressCell = row.find(".address span"); var privkeyCell = row.find(".privkey span"); // Content - indexCell.text(index); + indexCell.text(indexText); addressCell.text(address); privkeyCell.text(privkey); // Visibility @@ -358,7 +360,7 @@ addressCell.addClass("invisible"); } if (!showPrivKey) { - privkeCell.addClass("invisible"); + privkeyCell.addClass("invisible"); } DOM.addresses.append(row); } @@ -373,19 +375,6 @@ }); } - function setBip44DerivationPath() { - 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(), 0); - var path = "m/"; - path += purpose + "'/"; - path += coin + "'/"; - path += account + "'/"; - path += change; - DOM.bip44path.val(path); - } - function parseIntNoNaN(val, defaultVal) { var v = parseInt(val); if (isNaN(v)) { @@ -406,27 +395,88 @@ .hide(); } - function enableBip44Tab() { - // show bip44 tab (but don't select it) - DOM.bip44tab.removeClass("hidden"); - DOM.bip44panel.removeClass("hidden"); + function populateNetworkSelect() { + for (var i=0; i"); + option.attr("value", i); + option.text(network.name); + DOM.phraseNetwork.append(option); + } } - function disableBip44Tab() { - // hide bip44 tab - DOM.bip44tab.addClass("hidden"); - DOM.bip44tab.removeClass("active"); - // hide bip44 panel - DOM.bip44panel.addClass("hidden"); - DOM.bip44panel.removeClass("active"); - // show bip32 tab - DOM.bip32tab.addClass("active"); - // show bip32 panel - DOM.bip32panel.addClass("active"); - // set the derivation path - var activePath = $("#bip32 .path"); - derivationPath = activePath.val(); - } + var networks = [ + { + name: "Bitcoin", + onSelect: function() { + network = bitcoin.networks.bitcoin; + DOM.bip44coin.val(0); + }, + }, + { + name: "Bitcoin Testnet", + onSelect: function() { + network = bitcoin.networks.testnet; + DOM.bip44coin.val(1); + }, + }, + { + name: "Litecoin", + onSelect: function() { + network = bitcoin.networks.litecoin; + DOM.bip44coin.val(2); + }, + }, + { + name: "Dogecoin", + onSelect: function() { + network = bitcoin.networks.dogecoin; + DOM.bip44coin.val(3); + }, + }, + { + name: "ShadowCash", + onSelect: function() { + network = bitcoin.networks.shadow; + DOM.bip44coin.val(35); + }, + }, + { + name: "ShadowCash Testnet", + onSelect: function() { + network = bitcoin.networks.shadowtn; + DOM.bip44coin.val(1); + }, + }, + { + name: "Viacoin", + onSelect: function() { + network = bitcoin.networks.viacoin; + DOM.bip44coin.val(14); + }, + }, + { + name: "Viacoin Testnet", + onSelect: function() { + network = bitcoin.networks.viacointestnet; + DOM.bip44coin.val(1); + }, + }, + { + name: "Jumbucks", + onSelect: function() { + network = bitcoin.networks.jumbucks; + DOM.bip44coin.val(26); + }, + }, + { + name: "CLAM", + onSelect: function() { + network = bitcoin.networks.clam; + DOM.bip44coin.val(23); + }, + }, + ] init();